summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Android.bp14
-rw-r--r--StubLibraries.bp28
-rw-r--r--apex/Android.bp38
-rw-r--r--apex/blobstore/framework/java/android/app/blob/BlobHandle.java11
-rw-r--r--apex/blobstore/framework/java/android/app/blob/BlobInfo.java20
-rw-r--r--apex/blobstore/service/java/com/android/server/blob/BlobStoreManagerService.java8
-rw-r--r--apex/blobstore/service/java/com/android/server/blob/BlobStoreSession.java8
-rw-r--r--apex/media/framework/Android.bp5
-rw-r--r--apex/media/framework/java/android/media/MediaParser.java63
-rw-r--r--apex/permission/framework/Android.bp5
-rw-r--r--apex/permission/service/Android.bp43
-rw-r--r--apex/permission/service/api/current.txt45
-rw-r--r--apex/permission/service/api/system-server-current.txt46
-rw-r--r--apex/permission/service/api/system-server-removed.txt1
-rw-r--r--apex/permission/service/java/com/android/permission/persistence/IoUtils.java2
-rw-r--r--apex/permission/tests/Android.bp2
-rw-r--r--apex/statsd/framework/Android.bp11
-rw-r--r--apex/statsd/framework/java/android/util/StatsEvent.java50
-rw-r--r--apex/statsd/framework/java/android/util/StatsLog.java2
-rw-r--r--apex/statsd/framework/test/src/android/util/StatsEventTest.java160
-rw-r--r--api/test-current.txt125
-rw-r--r--cmds/bootanimation/BootAnimation.cpp30
-rw-r--r--cmds/bootanimation/BootAnimation.h3
-rw-r--r--cmds/idmap2/Android.bp2
-rw-r--r--cmds/idmap2/idmap2/CommandUtils.cpp (renamed from cmds/idmap2/idmap2/Verify.cpp)22
-rw-r--r--cmds/idmap2/idmap2/CommandUtils.h29
-rw-r--r--cmds/idmap2/idmap2/Commands.h1
-rw-r--r--cmds/idmap2/idmap2/CreateMultiple.cpp4
-rw-r--r--cmds/idmap2/idmap2/Main.cpp5
-rw-r--r--cmds/idmap2/idmap2/Scan.cpp14
-rw-r--r--cmds/idmap2/idmap2d/Idmap2Service.cpp75
-rw-r--r--cmds/idmap2/include/idmap2/Idmap.h17
-rw-r--r--cmds/idmap2/libidmap2/BinaryStreamVisitor.cpp2
-rw-r--r--cmds/idmap2/libidmap2/Idmap.cpp64
-rw-r--r--cmds/idmap2/libidmap2/RawPrintVisitor.cpp8
-rw-r--r--cmds/idmap2/libidmap2/ResourceMapping.cpp10
-rw-r--r--cmds/idmap2/libidmap2_policies/include/idmap2/Policies.h26
-rw-r--r--cmds/idmap2/tests/BinaryStreamVisitorTests.cpp5
-rw-r--r--cmds/idmap2/tests/IdmapTests.cpp74
-rw-r--r--cmds/idmap2/tests/RawPrintVisitorTests.cpp41
-rw-r--r--cmds/idmap2/tests/ResourceMappingTests.cpp70
-rw-r--r--cmds/idmap2/tests/TestHelpers.h52
-rw-r--r--cmds/incidentd/src/Section.cpp7
-rw-r--r--cmds/statsd/src/atoms.proto499
-rw-r--r--cmds/statsd/src/metrics/MetricProducer.cpp2
-rw-r--r--cmds/statsd/src/metrics/ValueMetricProducer.cpp16
-rw-r--r--cmds/statsd/src/metrics/ValueMetricProducer.h5
-rw-r--r--cmds/statsd/src/statsd_config.proto15
-rw-r--r--cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp245
-rw-r--r--cmds/statsd/tests/statsd_test_util.cpp4
-rw-r--r--core/java/android/accessibilityservice/AccessibilityService.java6
-rw-r--r--core/java/android/app/Activity.java24
-rw-r--r--core/java/android/app/ActivityManager.java36
-rw-r--r--core/java/android/app/ActivityManagerInternal.java19
-rw-r--r--core/java/android/app/ActivityThread.java80
-rw-r--r--core/java/android/app/ActivityView.java10
-rw-r--r--core/java/android/app/AppOpsManager.java48
-rw-r--r--core/java/android/app/ApplicationPackageManager.java7
-rw-r--r--core/java/android/app/ContextImpl.java2
-rw-r--r--core/java/android/app/Fragment.java41
-rw-r--r--core/java/android/app/ITaskStackListener.aidl12
-rw-r--r--core/java/android/app/Instrumentation.java12
-rw-r--r--core/java/android/app/LoadedApk.java28
-rw-r--r--core/java/android/app/Notification.java6
-rw-r--r--core/java/android/app/PendingIntent.java8
-rw-r--r--core/java/android/app/ResourcesManager.java53
-rw-r--r--core/java/android/app/TaskStackListener.java4
-rw-r--r--core/java/android/app/contentsuggestions/ContentSuggestionsManager.java15
-rw-r--r--core/java/android/content/Intent.java43
-rw-r--r--core/java/android/content/pm/PackageInstaller.java12
-rw-r--r--core/java/android/content/pm/PackageItemInfo.java12
-rw-r--r--core/java/android/content/pm/PackagePartitions.java9
-rw-r--r--core/java/android/content/pm/parsing/component/ParsedActivityUtils.java9
-rw-r--r--core/java/android/content/pm/parsing/component/ParsedComponentUtils.java29
-rw-r--r--core/java/android/hardware/biometrics/BiometricManager.java11
-rw-r--r--core/java/android/hardware/camera2/CameraManager.java19
-rw-r--r--core/java/android/hardware/hdmi/HdmiClient.java4
-rw-r--r--core/java/android/hardware/hdmi/HdmiControlManager.java120
-rw-r--r--core/java/android/hardware/hdmi/HdmiControlServiceWrapper.java469
-rw-r--r--core/java/android/hardware/hdmi/HdmiPortInfo.java9
-rw-r--r--core/java/android/hardware/hdmi/HdmiSwitchClient.java5
-rw-r--r--core/java/android/hardware/hdmi/IHdmiCecVolumeControlFeatureListener.aidl32
-rw-r--r--core/java/android/hardware/hdmi/IHdmiControlService.aidl3
-rw-r--r--core/java/android/hardware/soundtrigger/ConversionUtil.java18
-rw-r--r--core/java/android/hardware/soundtrigger/SoundTriggerModule.java2
-rw-r--r--core/java/android/inputmethodservice/AbstractInputMethodService.java6
-rw-r--r--core/java/android/net/NetworkAgent.java1
-rw-r--r--core/java/android/net/NetworkAgentConfig.java41
-rw-r--r--core/java/android/net/NetworkCapabilities.java12
-rw-r--r--core/java/android/net/NetworkRequest.java4
-rw-r--r--core/java/android/os/AppZygote.java5
-rw-r--r--core/java/android/os/GraphicsEnvironment.java166
-rw-r--r--core/java/android/os/StrictMode.java7
-rw-r--r--core/java/android/os/UserManager.java7
-rw-r--r--core/java/android/os/ZygoteProcess.java6
-rw-r--r--core/java/android/os/storage/StorageManager.java2
-rwxr-xr-xcore/java/android/provider/Settings.java18
-rw-r--r--core/java/android/provider/Telephony.java40
-rw-r--r--core/java/android/service/autofill/InlineSuggestionRoot.java4
-rw-r--r--core/java/android/service/autofill/augmented/FillCallback.java3
-rw-r--r--core/java/android/service/controls/Control.java20
-rw-r--r--core/java/android/service/notification/ZenModeConfig.java43
-rw-r--r--core/java/android/service/notification/ZenPolicy.java35
-rw-r--r--core/java/android/service/voice/VoiceInteractionSession.java4
-rw-r--r--core/java/android/telephony/PhoneStateListener.java8
-rw-r--r--core/java/android/view/GestureDetector.java26
-rw-r--r--core/java/android/view/ImeFocusController.java8
-rw-r--r--core/java/android/view/InsetsController.java14
-rw-r--r--core/java/android/view/InsetsSourceConsumer.java10
-rw-r--r--core/java/android/view/InsetsState.java38
-rw-r--r--core/java/android/view/SurfaceControl.java37
-rw-r--r--core/java/android/view/SurfaceView.java17
-rw-r--r--core/java/android/view/WindowlessWindowManager.java6
-rw-r--r--core/java/android/view/accessibility/AccessibilityNodeInfo.java23
-rw-r--r--core/java/android/view/autofill/AutofillId.java5
-rw-r--r--core/java/android/view/autofill/AutofillManager.java51
-rw-r--r--core/java/android/view/contentcapture/ContentCaptureManager.java47
-rw-r--r--core/java/android/view/inputmethod/InlineSuggestion.java22
-rw-r--r--core/java/android/view/inputmethod/InputMethodManager.java26
-rw-r--r--core/java/android/view/textclassifier/TEST_MAPPING16
-rw-r--r--core/java/android/webkit/WebChromeClient.java8
-rw-r--r--core/java/android/widget/inline/InlineContentView.java4
-rw-r--r--core/java/android/window/VirtualDisplayTaskEmbedder.java4
-rw-r--r--core/java/android/window/WindowContainerTransaction.java64
-rw-r--r--core/java/com/android/internal/accessibility/dialog/AccessibilityShortcutChooserActivity.java31
-rw-r--r--core/java/com/android/internal/accessibility/util/AccessibilityUtils.java12
-rw-r--r--core/java/com/android/internal/app/AbstractMultiProfilePagerAdapter.java18
-rw-r--r--core/java/com/android/internal/app/ChooserActivity.java121
-rw-r--r--core/java/com/android/internal/app/ChooserGridLayoutManager.java11
-rw-r--r--core/java/com/android/internal/app/ChooserListAdapter.java8
-rw-r--r--core/java/com/android/internal/app/ChooserMultiProfilePagerAdapter.java11
-rw-r--r--core/java/com/android/internal/app/ChooserTargetActionsDialogFragment.java112
-rw-r--r--core/java/com/android/internal/app/IAppOpsService.aidl1
-rw-r--r--core/java/com/android/internal/app/IVoiceInteractionManagerService.aidl12
-rw-r--r--core/java/com/android/internal/app/IntentForwarderActivity.java2
-rw-r--r--core/java/com/android/internal/app/ResolverActivity.java87
-rw-r--r--core/java/com/android/internal/app/ResolverListAdapter.java4
-rw-r--r--core/java/com/android/internal/app/ResolverViewPager.java12
-rw-r--r--core/java/com/android/internal/app/SimpleIconFactory.java64
-rw-r--r--core/java/com/android/internal/app/chooser/DisplayResolveInfo.java6
-rw-r--r--core/java/com/android/internal/app/chooser/MultiDisplayResolveInfo.java7
-rw-r--r--core/java/com/android/internal/app/procstats/ProcessState.java37
-rw-r--r--core/java/com/android/internal/app/procstats/ProcessStats.java37
-rw-r--r--core/java/com/android/internal/inputmethod/StartInputReason.java5
-rw-r--r--core/java/com/android/internal/logging/UiEventLogger.java24
-rw-r--r--core/java/com/android/internal/logging/UiEventLoggerImpl.java27
-rw-r--r--core/java/com/android/internal/logging/testing/UiEventLoggerFake.java30
-rw-r--r--core/java/com/android/internal/util/ScreenshotHelper.java56
-rw-r--r--core/java/com/android/internal/util/SyncResultReceiver.java2
-rw-r--r--core/java/com/android/internal/widget/ConversationLayout.java137
-rw-r--r--core/jni/android_media_AudioEffectDescriptor.cpp6
-rw-r--r--core/jni/com_android_internal_os_Zygote.cpp39
-rw-r--r--core/proto/android/server/connectivity/data_stall_event.proto1
-rw-r--r--core/proto/android/service/notification.proto72
-rw-r--r--core/proto/android/service/procstats.proto7
-rw-r--r--core/proto/android/stats/mediametrics/mediametrics.proto5
-rw-r--r--core/res/AndroidManifest.xml7
-rw-r--r--core/res/res/drawable/chooser_dialog_background.xml (renamed from packages/SystemUI/res/color/qs_user_detail_avatar_tint.xml)13
-rw-r--r--core/res/res/drawable/conversation_badge_background.xml4
-rw-r--r--core/res/res/drawable/conversation_badge_ring.xml15
-rw-r--r--core/res/res/layout/chooser_dialog.xml60
-rw-r--r--core/res/res/layout/chooser_dialog_item.xml29
-rw-r--r--core/res/res/layout/chooser_grid_preview_text.xml4
-rw-r--r--core/res/res/layout/notification_material_action_list.xml3
-rw-r--r--core/res/res/layout/notification_template_material_conversation.xml32
-rw-r--r--core/res/res/values-af/strings.xml6
-rw-r--r--core/res/res/values-am/strings.xml6
-rw-r--r--core/res/res/values-ar/strings.xml12
-rw-r--r--core/res/res/values-as/strings.xml6
-rw-r--r--core/res/res/values-az/strings.xml6
-rw-r--r--core/res/res/values-b+sr+Latn/strings.xml10
-rw-r--r--core/res/res/values-be/strings.xml6
-rw-r--r--core/res/res/values-bg/strings.xml6
-rw-r--r--core/res/res/values-bn/strings.xml10
-rw-r--r--core/res/res/values-bs/strings.xml18
-rw-r--r--core/res/res/values-ca/strings.xml6
-rw-r--r--core/res/res/values-cs/strings.xml6
-rw-r--r--core/res/res/values-da/strings.xml6
-rw-r--r--core/res/res/values-de/strings.xml6
-rw-r--r--core/res/res/values-el/strings.xml14
-rw-r--r--core/res/res/values-en-rAU/strings.xml6
-rw-r--r--core/res/res/values-en-rCA/strings.xml6
-rw-r--r--core/res/res/values-en-rGB/strings.xml6
-rw-r--r--core/res/res/values-en-rIN/strings.xml6
-rw-r--r--core/res/res/values-en-rXC/strings.xml6
-rw-r--r--core/res/res/values-es-rUS/strings.xml6
-rw-r--r--core/res/res/values-es/strings.xml12
-rw-r--r--core/res/res/values-et/strings.xml6
-rw-r--r--core/res/res/values-eu/strings.xml6
-rw-r--r--core/res/res/values-fa/strings.xml8
-rw-r--r--core/res/res/values-fi/strings.xml6
-rw-r--r--core/res/res/values-fr-rCA/strings.xml6
-rw-r--r--core/res/res/values-fr/strings.xml6
-rw-r--r--core/res/res/values-gl/strings.xml10
-rw-r--r--core/res/res/values-gu/strings.xml10
-rw-r--r--core/res/res/values-hi/strings.xml6
-rw-r--r--core/res/res/values-hr/strings.xml20
-rw-r--r--core/res/res/values-hu/strings.xml6
-rw-r--r--core/res/res/values-hy/strings.xml8
-rw-r--r--core/res/res/values-in/strings.xml8
-rw-r--r--core/res/res/values-is/strings.xml8
-rw-r--r--core/res/res/values-it/strings.xml14
-rw-r--r--core/res/res/values-iw/strings.xml6
-rw-r--r--core/res/res/values-ja/strings.xml8
-rw-r--r--core/res/res/values-ka/strings.xml6
-rw-r--r--core/res/res/values-kk/strings.xml6
-rw-r--r--core/res/res/values-km/strings.xml16
-rw-r--r--core/res/res/values-kn/strings.xml10
-rw-r--r--core/res/res/values-ko/strings.xml14
-rw-r--r--core/res/res/values-ky/strings.xml20
-rw-r--r--core/res/res/values-lo/strings.xml6
-rw-r--r--core/res/res/values-lt/strings.xml6
-rw-r--r--core/res/res/values-lv/strings.xml6
-rw-r--r--core/res/res/values-mk/strings.xml14
-rw-r--r--core/res/res/values-ml/strings.xml6
-rw-r--r--core/res/res/values-mn/strings.xml10
-rw-r--r--core/res/res/values-mr/strings.xml22
-rw-r--r--core/res/res/values-ms/strings.xml6
-rw-r--r--core/res/res/values-my/strings.xml10
-rw-r--r--core/res/res/values-nb/strings.xml6
-rw-r--r--core/res/res/values-ne/strings.xml6
-rw-r--r--core/res/res/values-nl/strings.xml18
-rw-r--r--core/res/res/values-or/strings.xml12
-rw-r--r--core/res/res/values-pa/strings.xml6
-rw-r--r--core/res/res/values-pl/strings.xml22
-rw-r--r--core/res/res/values-pt-rBR/strings.xml30
-rw-r--r--core/res/res/values-pt-rPT/strings.xml8
-rw-r--r--core/res/res/values-pt/strings.xml30
-rw-r--r--core/res/res/values-ro/strings.xml8
-rw-r--r--core/res/res/values-ru/strings.xml10
-rw-r--r--core/res/res/values-si/strings.xml6
-rw-r--r--core/res/res/values-sk/strings.xml24
-rw-r--r--core/res/res/values-sl/strings.xml6
-rw-r--r--core/res/res/values-sq/strings.xml8
-rw-r--r--core/res/res/values-sr/strings.xml10
-rw-r--r--core/res/res/values-sv/strings.xml6
-rw-r--r--core/res/res/values-sw/strings.xml10
-rw-r--r--core/res/res/values-ta/strings.xml6
-rw-r--r--core/res/res/values-te/strings.xml10
-rw-r--r--core/res/res/values-television/themes_device_defaults.xml3
-rw-r--r--core/res/res/values-th/strings.xml6
-rw-r--r--core/res/res/values-tl/strings.xml6
-rw-r--r--core/res/res/values-tr/strings.xml6
-rw-r--r--core/res/res/values-uk/strings.xml10
-rw-r--r--core/res/res/values-ur/strings.xml14
-rw-r--r--core/res/res/values-uz/strings.xml10
-rw-r--r--core/res/res/values-vi/strings.xml10
-rw-r--r--core/res/res/values-zh-rCN/strings.xml6
-rw-r--r--core/res/res/values-zh-rHK/strings.xml6
-rw-r--r--core/res/res/values-zh-rTW/strings.xml6
-rw-r--r--core/res/res/values-zu/strings.xml6
-rw-r--r--core/res/res/values/attrs_manifest.xml25
-rw-r--r--core/res/res/values/config.xml11
-rw-r--r--core/res/res/values/dimens.xml21
-rw-r--r--core/res/res/values/strings.xml6
-rw-r--r--core/res/res/values/styles_device_defaults.xml7
-rw-r--r--core/res/res/values/styles_material.xml4
-rw-r--r--core/res/res/values/symbols.xml23
-rw-r--r--core/res/res/values/themes_leanback.xml4
-rw-r--r--core/res/res/xml/sms_short_codes.xml4
-rw-r--r--core/tests/PackageInstallerSessions/Android.bp42
-rw-r--r--core/tests/PackageInstallerSessions/AndroidManifest.xml29
-rw-r--r--core/tests/PackageInstallerSessions/src/android/content/pm/PackageSessionTests.kt188
-rw-r--r--core/tests/coretests/src/android/content/ContextTest.java9
-rw-r--r--core/tests/coretests/src/android/view/InsetsSourceConsumerTest.java49
-rw-r--r--core/tests/coretests/src/android/view/InsetsStateTest.java22
-rw-r--r--core/tests/coretests/src/android/view/autofill/AutofillIdTest.java26
-rw-r--r--core/tests/coretests/src/com/android/internal/app/ChooserActivityTest.java60
-rw-r--r--core/tests/coretests/src/com/android/internal/app/ChooserWrapperActivity.java21
-rw-r--r--core/tests/coretests/src/com/android/internal/app/ResolverActivityTest.java7
-rw-r--r--core/tests/hdmitests/src/android/hardware/hdmi/HdmiAudioSystemClientTest.java10
-rw-r--r--core/tests/overlaytests/remount/Android.bp4
-rw-r--r--core/tests/overlaytests/remount/src/com/android/overlaytest/remounted/OverlayRemountedTestBase.java1
-rw-r--r--core/tests/overlaytests/remount/src/com/android/overlaytest/remounted/RegenerateIdmapTest.java (renamed from core/tests/overlaytests/remount/src/com/android/overlaytest/remounted/PackagedUpgradedTest.java)32
-rw-r--r--core/tests/overlaytests/remount/src/com/android/overlaytest/remounted/SystemPreparer.java151
-rw-r--r--core/tests/overlaytests/remount/test-apps/Overlay/Android.bp6
-rw-r--r--core/tests/overlaytests/remount/test-apps/Overlay/res/values/values.xml1
-rw-r--r--core/tests/overlaytests/remount/test-apps/Target/Android.bp2
-rw-r--r--core/tests/overlaytests/remount/test-apps/Target/res/values/overlayable.xml3
-rw-r--r--core/tests/overlaytests/remount/test-apps/Target/res/values/values.xml2
-rw-r--r--core/tests/overlaytests/remount/test-apps/certs/Android.bp19
-rw-r--r--core/tests/overlaytests/remount/test-apps/certs/rro-remounted-test-a.pk8bin0 -> 1218 bytes
-rw-r--r--core/tests/overlaytests/remount/test-apps/certs/rro-remounted-test-a.x509.pem19
-rw-r--r--core/tests/screenshothelpertests/src/com/android/internal/util/ScreenshotHelperTest.java6
-rw-r--r--data/etc/car/Android.bp7
-rw-r--r--data/etc/car/com.android.car.bugreport.xml (renamed from packages/CarSystemUI/res/drawable/nav_button_background.xml)20
-rw-r--r--data/etc/preinstalled-packages-platform.xml6
-rw-r--r--data/etc/privapp-permissions-platform.xml5
-rw-r--r--data/keyboards/Vendor_045e_Product_0b12.kl59
-rw-r--r--identity/java/android/security/identity/IdentityCredential.java27
-rw-r--r--identity/java/android/security/identity/WritableIdentityCredential.java8
-rw-r--r--libs/androidfw/include/androidfw/ResourceTypes.h5
-rw-r--r--libs/androidfw/tests/data/overlay/overlay.apkbin2988 -> 2992 bytes
-rw-r--r--libs/androidfw/tests/data/overlay/overlay.idmapbin1137 -> 1090 bytes
-rw-r--r--location/java/com/android/internal/location/GpsNetInitiatedHandler.java7
-rw-r--r--location/java/com/android/internal/location/gnssmetrics/GnssMetrics.java24
-rw-r--r--media/java/android/media/IMediaRouter2.aidl2
-rw-r--r--media/java/android/media/IMediaRouter2Manager.aidl5
-rw-r--r--media/java/android/media/MediaCas.java23
-rw-r--r--media/java/android/media/MediaRoute2ProviderService.java173
-rw-r--r--media/java/android/media/MediaRouter2.java144
-rw-r--r--media/java/android/media/MediaRouter2Manager.java174
-rw-r--r--media/java/android/media/SoundPool.java80
-rw-r--r--media/java/android/media/projection/MediaProjectionManager.java11
-rw-r--r--media/java/android/media/soundtrigger_middleware/RecognitionEvent.aidl4
-rw-r--r--media/java/android/media/tv/TvRecordingClient.java2
-rw-r--r--media/java/android/media/tv/tuner/dvr/DvrPlayback.java28
-rw-r--r--media/java/android/media/tv/tuner/dvr/DvrRecorder.java28
-rw-r--r--media/jni/android_media_MediaCodec.cpp16
-rw-r--r--media/jni/android_media_MediaCodec.h2
-rw-r--r--media/jni/soundpool/Sound.cpp2
-rw-r--r--media/tests/MediaRouter/src/com/android/mediaroutertest/MediaRouter2ManagerTest.java125
-rw-r--r--media/tests/MediaRouter/src/com/android/mediaroutertest/StubMediaRoute2ProviderService.java13
-rw-r--r--packages/CarSystemUI/Android.bp2
-rw-r--r--packages/CarSystemUI/res/layout/car_left_navigation_bar.xml2
-rw-r--r--packages/CarSystemUI/res/layout/car_navigation_bar.xml10
-rw-r--r--packages/CarSystemUI/res/layout/car_navigation_button.xml4
-rw-r--r--packages/CarSystemUI/res/layout/car_right_navigation_bar.xml2
-rw-r--r--packages/CarSystemUI/res/layout/car_top_navigation_bar.xml3
-rw-r--r--packages/CarSystemUI/res/layout/headsup_container_bottom.xml9
-rw-r--r--packages/CarSystemUI/res/values/styles.xml2
-rw-r--r--packages/CarSystemUI/src/com/android/systemui/car/keyguard/CarKeyguardViewController.java21
-rw-r--r--packages/CarSystemUI/src/com/android/systemui/car/navigationbar/CarNavigationBarView.java4
-rw-r--r--packages/CarSystemUI/src/com/android/systemui/car/navigationbar/CarNavigationButton.java6
-rw-r--r--packages/CarSystemUI/src/com/android/systemui/car/navigationbar/NavigationBarViewFactory.java7
-rw-r--r--packages/CarSystemUI/src/com/android/systemui/car/notification/CarHeadsUpNotificationSystemContainer.java3
-rw-r--r--packages/CarSystemUI/src/com/android/systemui/car/window/OverlayViewController.java7
-rw-r--r--packages/CarSystemUI/src/com/android/systemui/car/window/OverlayViewGlobalStateController.java56
-rw-r--r--packages/CarSystemUI/tests/src/com/android/systemui/car/keyguard/CarKeyguardViewControllerTest.java13
-rw-r--r--packages/CarSystemUI/tests/src/com/android/systemui/car/navigationbar/CarNavigationButtonTest.java22
-rw-r--r--packages/CarSystemUI/tests/src/com/android/systemui/car/window/OverlayViewGlobalStateControllerTest.java75
-rw-r--r--packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java6
-rw-r--r--packages/PackageInstaller/res/values-or/strings.xml2
-rw-r--r--packages/SettingsLib/AdaptiveIcon/res/values/colors.xml4
-rw-r--r--packages/SettingsLib/AdaptiveIcon/res/values/dimens.xml2
-rw-r--r--packages/SettingsLib/AdaptiveIcon/src/com/android/settingslib/widget/AdaptiveOutlineDrawable.java101
-rw-r--r--packages/SettingsLib/OWNERS1
-rw-r--r--packages/SettingsLib/SearchWidget/res/values-fa/strings.xml2
-rw-r--r--packages/SettingsLib/SearchWidget/res/values-tl/strings.xml2
-rw-r--r--packages/SettingsLib/res/values-ar/strings.xml2
-rw-r--r--packages/SettingsLib/res/values-be/strings.xml4
-rw-r--r--packages/SettingsLib/res/values-bn/arrays.xml2
-rw-r--r--packages/SettingsLib/res/values-el/strings.xml2
-rw-r--r--packages/SettingsLib/res/values-en-rAU/strings.xml2
-rw-r--r--packages/SettingsLib/res/values-en-rCA/strings.xml2
-rw-r--r--packages/SettingsLib/res/values-en-rGB/strings.xml2
-rw-r--r--packages/SettingsLib/res/values-en-rIN/strings.xml2
-rw-r--r--packages/SettingsLib/res/values-et/strings.xml2
-rw-r--r--packages/SettingsLib/res/values-in/arrays.xml2
-rw-r--r--packages/SettingsLib/res/values-it/strings.xml12
-rw-r--r--packages/SettingsLib/res/values-vi/strings.xml2
-rw-r--r--packages/SettingsLib/res/values/dimens.xml3
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/applications/AppUtils.java30
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/applications/ApplicationsState.java10
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothUtils.java43
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/media/BluetoothMediaDevice.java13
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/media/InfoMediaDevice.java6
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/media/MediaDevice.java13
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/media/PhoneMediaDevice.java7
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/notification/ConversationIconFactory.java4
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java6
-rw-r--r--packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/PhoneMediaDeviceTest.java6
-rw-r--r--packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java1
-rw-r--r--packages/Shell/AndroidManifest.xml6
-rw-r--r--packages/Shell/res/layout/dialog_bugreport_info.xml107
-rw-r--r--packages/SystemUI/res-keyguard/values-ko/strings.xml2
-rw-r--r--packages/SystemUI/res-keyguard/values-ur/strings.xml2
-rw-r--r--packages/SystemUI/res-keyguard/values-uz/strings.xml2
-rw-r--r--packages/SystemUI/res-product/values-af/strings.xml9
-rw-r--r--packages/SystemUI/res-product/values-am/strings.xml9
-rw-r--r--packages/SystemUI/res-product/values-ar/strings.xml9
-rw-r--r--packages/SystemUI/res-product/values-as/strings.xml9
-rw-r--r--packages/SystemUI/res-product/values-az/strings.xml9
-rw-r--r--packages/SystemUI/res-product/values-b+sr+Latn/strings.xml9
-rw-r--r--packages/SystemUI/res-product/values-be/strings.xml9
-rw-r--r--packages/SystemUI/res-product/values-bg/strings.xml9
-rw-r--r--packages/SystemUI/res-product/values-bn/strings.xml9
-rw-r--r--packages/SystemUI/res-product/values-bs/strings.xml9
-rw-r--r--packages/SystemUI/res-product/values-ca/strings.xml9
-rw-r--r--packages/SystemUI/res-product/values-cs/strings.xml9
-rw-r--r--packages/SystemUI/res-product/values-da/strings.xml9
-rw-r--r--packages/SystemUI/res-product/values-de/strings.xml9
-rw-r--r--packages/SystemUI/res-product/values-el/strings.xml9
-rw-r--r--packages/SystemUI/res-product/values-en-rAU/strings.xml9
-rw-r--r--packages/SystemUI/res-product/values-en-rCA/strings.xml9
-rw-r--r--packages/SystemUI/res-product/values-en-rGB/strings.xml9
-rw-r--r--packages/SystemUI/res-product/values-en-rIN/strings.xml9
-rw-r--r--packages/SystemUI/res-product/values-en-rXC/strings.xml9
-rw-r--r--packages/SystemUI/res-product/values-es-rUS/strings.xml9
-rw-r--r--packages/SystemUI/res-product/values-es/strings.xml9
-rw-r--r--packages/SystemUI/res-product/values-et/strings.xml9
-rw-r--r--packages/SystemUI/res-product/values-eu/strings.xml9
-rw-r--r--packages/SystemUI/res-product/values-fa/strings.xml9
-rw-r--r--packages/SystemUI/res-product/values-fi/strings.xml9
-rw-r--r--packages/SystemUI/res-product/values-fr-rCA/strings.xml9
-rw-r--r--packages/SystemUI/res-product/values-fr/strings.xml9
-rw-r--r--packages/SystemUI/res-product/values-gl/strings.xml9
-rw-r--r--packages/SystemUI/res-product/values-gu/strings.xml9
-rw-r--r--packages/SystemUI/res-product/values-hi/strings.xml9
-rw-r--r--packages/SystemUI/res-product/values-hr/strings.xml9
-rw-r--r--packages/SystemUI/res-product/values-hu/strings.xml9
-rw-r--r--packages/SystemUI/res-product/values-hy/strings.xml9
-rw-r--r--packages/SystemUI/res-product/values-in/strings.xml9
-rw-r--r--packages/SystemUI/res-product/values-is/strings.xml9
-rw-r--r--packages/SystemUI/res-product/values-it/strings.xml9
-rw-r--r--packages/SystemUI/res-product/values-iw/strings.xml9
-rw-r--r--packages/SystemUI/res-product/values-ja/strings.xml9
-rw-r--r--packages/SystemUI/res-product/values-ka/strings.xml9
-rw-r--r--packages/SystemUI/res-product/values-kk/strings.xml9
-rw-r--r--packages/SystemUI/res-product/values-km/strings.xml9
-rw-r--r--packages/SystemUI/res-product/values-kn/strings.xml9
-rw-r--r--packages/SystemUI/res-product/values-ko/strings.xml9
-rw-r--r--packages/SystemUI/res-product/values-ky/strings.xml9
-rw-r--r--packages/SystemUI/res-product/values-lo/strings.xml9
-rw-r--r--packages/SystemUI/res-product/values-lt/strings.xml9
-rw-r--r--packages/SystemUI/res-product/values-lv/strings.xml9
-rw-r--r--packages/SystemUI/res-product/values-mk/strings.xml9
-rw-r--r--packages/SystemUI/res-product/values-ml/strings.xml9
-rw-r--r--packages/SystemUI/res-product/values-mn/strings.xml9
-rw-r--r--packages/SystemUI/res-product/values-mr/strings.xml9
-rw-r--r--packages/SystemUI/res-product/values-ms/strings.xml9
-rw-r--r--packages/SystemUI/res-product/values-my/strings.xml9
-rw-r--r--packages/SystemUI/res-product/values-nb/strings.xml9
-rw-r--r--packages/SystemUI/res-product/values-ne/strings.xml9
-rw-r--r--packages/SystemUI/res-product/values-nl/strings.xml9
-rw-r--r--packages/SystemUI/res-product/values-or/strings.xml9
-rw-r--r--packages/SystemUI/res-product/values-pa/strings.xml9
-rw-r--r--packages/SystemUI/res-product/values-pl/strings.xml9
-rw-r--r--packages/SystemUI/res-product/values-pt-rBR/strings.xml9
-rw-r--r--packages/SystemUI/res-product/values-pt-rPT/strings.xml9
-rw-r--r--packages/SystemUI/res-product/values-pt/strings.xml9
-rw-r--r--packages/SystemUI/res-product/values-ro/strings.xml9
-rw-r--r--packages/SystemUI/res-product/values-ru/strings.xml9
-rw-r--r--packages/SystemUI/res-product/values-si/strings.xml9
-rw-r--r--packages/SystemUI/res-product/values-sk/strings.xml9
-rw-r--r--packages/SystemUI/res-product/values-sl/strings.xml9
-rw-r--r--packages/SystemUI/res-product/values-sq/strings.xml9
-rw-r--r--packages/SystemUI/res-product/values-sr/strings.xml9
-rw-r--r--packages/SystemUI/res-product/values-sv/strings.xml9
-rw-r--r--packages/SystemUI/res-product/values-sw/strings.xml9
-rw-r--r--packages/SystemUI/res-product/values-ta/strings.xml9
-rw-r--r--packages/SystemUI/res-product/values-te/strings.xml9
-rw-r--r--packages/SystemUI/res-product/values-th/strings.xml9
-rw-r--r--packages/SystemUI/res-product/values-tl/strings.xml9
-rw-r--r--packages/SystemUI/res-product/values-tr/strings.xml9
-rw-r--r--packages/SystemUI/res-product/values-uk/strings.xml9
-rw-r--r--packages/SystemUI/res-product/values-ur/strings.xml9
-rw-r--r--packages/SystemUI/res-product/values-uz/strings.xml9
-rw-r--r--packages/SystemUI/res-product/values-vi/strings.xml9
-rw-r--r--packages/SystemUI/res-product/values-zh-rCN/strings.xml9
-rw-r--r--packages/SystemUI/res-product/values-zh-rHK/strings.xml9
-rw-r--r--packages/SystemUI/res-product/values-zh-rTW/strings.xml9
-rw-r--r--packages/SystemUI/res-product/values-zu/strings.xml9
-rw-r--r--packages/SystemUI/res/drawable/dismiss_circle_background.xml4
-rw-r--r--packages/SystemUI/res/drawable/floating_dismiss_gradient.xml24
-rw-r--r--packages/SystemUI/res/drawable/floating_dismiss_gradient_transition.xml19
-rw-r--r--packages/SystemUI/res/drawable/ic_create_bubble.xml8
-rw-r--r--packages/SystemUI/res/drawable/ic_error_outline.xml25
-rw-r--r--packages/SystemUI/res/drawable/ic_music_note.xml (renamed from packages/SystemUI/res/drawable/dismiss_target_x.xml)18
-rw-r--r--packages/SystemUI/res/drawable/ic_settings_power.xml25
-rw-r--r--packages/SystemUI/res/drawable/ic_stop_bubble.xml6
-rw-r--r--packages/SystemUI/res/layout-sw600dp/keyguard_user_switcher_item.xml2
-rw-r--r--packages/SystemUI/res/layout/bubbles_manage_button_education.xml68
-rw-r--r--packages/SystemUI/res/layout/controls_base_item.xml3
-rw-r--r--packages/SystemUI/res/layout/controls_detail_dialog.xml1
-rw-r--r--packages/SystemUI/res/layout/controls_more_item.xml3
-rw-r--r--packages/SystemUI/res/layout/global_screenshot.xml5
-rw-r--r--packages/SystemUI/res/layout/global_screenshot_static.xml9
-rw-r--r--packages/SystemUI/res/layout/keyguard_user_switcher_item.xml2
-rw-r--r--packages/SystemUI/res/layout/notification_conversation_info.xml42
-rw-r--r--packages/SystemUI/res/layout/notification_info.xml41
-rw-r--r--packages/SystemUI/res/layout/partial_conversation_info.xml65
-rw-r--r--packages/SystemUI/res/layout/priority_onboarding_half_shell.xml222
-rw-r--r--packages/SystemUI/res/layout/qs_user_detail_item.xml3
-rw-r--r--packages/SystemUI/res/layout/quick_qs_status_icons.xml2
-rw-r--r--packages/SystemUI/res/layout/quick_settings_brightness_dialog.xml2
-rw-r--r--packages/SystemUI/res/layout/quick_settings_footer.xml6
-rw-r--r--packages/SystemUI/res/layout/quick_settings_header_info.xml2
-rw-r--r--packages/SystemUI/res/layout/quick_status_bar_expanded_header.xml1
-rw-r--r--packages/SystemUI/res/layout/quick_status_bar_header_system_icons.xml2
-rw-r--r--packages/SystemUI/res/layout/screen_record_dialog_audio_source.xml9
-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.xml45
-rw-r--r--packages/SystemUI/res/values-as/strings.xml41
-rw-r--r--packages/SystemUI/res/values-az/strings.xml41
-rw-r--r--packages/SystemUI/res/values-b+sr+Latn/strings.xml23
-rw-r--r--packages/SystemUI/res/values-be/strings.xml19
-rw-r--r--packages/SystemUI/res/values-bg/strings.xml41
-rw-r--r--packages/SystemUI/res/values-bn/strings.xml17
-rw-r--r--packages/SystemUI/res/values-bs/strings.xml29
-rw-r--r--packages/SystemUI/res/values-ca/strings.xml19
-rw-r--r--packages/SystemUI/res/values-cs/strings.xml17
-rw-r--r--packages/SystemUI/res/values-da/strings.xml49
-rw-r--r--packages/SystemUI/res/values-de/strings.xml59
-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.xml17
-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-en-rXC/strings.xml13
-rw-r--r--packages/SystemUI/res/values-es-rUS/strings.xml19
-rw-r--r--packages/SystemUI/res/values-es/strings.xml41
-rw-r--r--packages/SystemUI/res/values-et/strings.xml47
-rw-r--r--packages/SystemUI/res/values-eu/strings.xml29
-rw-r--r--packages/SystemUI/res/values-fa/strings.xml17
-rw-r--r--packages/SystemUI/res/values-fi/strings.xml41
-rw-r--r--packages/SystemUI/res/values-fr-rCA/strings.xml47
-rw-r--r--packages/SystemUI/res/values-fr/strings.xml43
-rw-r--r--packages/SystemUI/res/values-gl/strings.xml17
-rw-r--r--packages/SystemUI/res/values-gu/strings.xml41
-rw-r--r--packages/SystemUI/res/values-hi/strings.xml41
-rw-r--r--packages/SystemUI/res/values-hr/strings.xml17
-rw-r--r--packages/SystemUI/res/values-hu/strings.xml19
-rw-r--r--packages/SystemUI/res/values-hy/strings.xml43
-rw-r--r--packages/SystemUI/res/values-in/strings.xml21
-rw-r--r--packages/SystemUI/res/values-is/strings.xml17
-rw-r--r--packages/SystemUI/res/values-it/strings.xml27
-rw-r--r--packages/SystemUI/res/values-iw/strings.xml41
-rw-r--r--packages/SystemUI/res/values-ja/strings.xml49
-rw-r--r--packages/SystemUI/res/values-ka/strings.xml41
-rw-r--r--packages/SystemUI/res/values-kk/strings.xml51
-rw-r--r--packages/SystemUI/res/values-km/strings.xml55
-rw-r--r--packages/SystemUI/res/values-kn/strings.xml43
-rw-r--r--packages/SystemUI/res/values-ko/strings.xml53
-rw-r--r--packages/SystemUI/res/values-ky/strings.xml57
-rw-r--r--packages/SystemUI/res/values-lo/strings.xml17
-rw-r--r--packages/SystemUI/res/values-lt/strings.xml41
-rw-r--r--packages/SystemUI/res/values-lv/strings.xml17
-rw-r--r--packages/SystemUI/res/values-mk/strings.xml47
-rw-r--r--packages/SystemUI/res/values-ml/strings.xml22
-rw-r--r--packages/SystemUI/res/values-mn/strings.xml45
-rw-r--r--packages/SystemUI/res/values-mr/strings.xml48
-rw-r--r--packages/SystemUI/res/values-ms/strings.xml41
-rw-r--r--packages/SystemUI/res/values-my/strings.xml23
-rw-r--r--packages/SystemUI/res/values-nb/strings.xml43
-rw-r--r--packages/SystemUI/res/values-ne/strings.xml44
-rw-r--r--packages/SystemUI/res/values-night/styles.xml5
-rw-r--r--packages/SystemUI/res/values-nl/strings.xml19
-rw-r--r--packages/SystemUI/res/values-or/strings.xml50
-rw-r--r--packages/SystemUI/res/values-pa/strings.xml21
-rw-r--r--packages/SystemUI/res/values-pl/strings.xml45
-rw-r--r--packages/SystemUI/res/values-pt-rBR/strings.xml21
-rw-r--r--packages/SystemUI/res/values-pt-rPT/strings.xml17
-rw-r--r--packages/SystemUI/res/values-pt/strings.xml21
-rw-r--r--packages/SystemUI/res/values-ro/strings.xml41
-rw-r--r--packages/SystemUI/res/values-ru/strings.xml21
-rw-r--r--packages/SystemUI/res/values-si/strings.xml17
-rw-r--r--packages/SystemUI/res/values-sk/strings.xml45
-rw-r--r--packages/SystemUI/res/values-sl/strings.xml41
-rw-r--r--packages/SystemUI/res/values-sq/strings.xml17
-rw-r--r--packages/SystemUI/res/values-sr/strings.xml23
-rw-r--r--packages/SystemUI/res/values-sv/strings.xml17
-rw-r--r--packages/SystemUI/res/values-sw/strings.xml45
-rw-r--r--packages/SystemUI/res/values-sw320dp/dimens.xml36
-rw-r--r--packages/SystemUI/res/values-sw372dp/dimens.xml1
-rw-r--r--packages/SystemUI/res/values-ta/strings.xml41
-rw-r--r--packages/SystemUI/res/values-te/strings.xml43
-rw-r--r--packages/SystemUI/res/values-th/strings.xml43
-rw-r--r--packages/SystemUI/res/values-tl/strings.xml41
-rw-r--r--packages/SystemUI/res/values-tr/strings.xml43
-rw-r--r--packages/SystemUI/res/values-uk/strings.xml51
-rw-r--r--packages/SystemUI/res/values-ur/strings.xml47
-rw-r--r--packages/SystemUI/res/values-uz/strings.xml52
-rw-r--r--packages/SystemUI/res/values-vi/strings.xml45
-rw-r--r--packages/SystemUI/res/values-zh-rCN/strings.xml53
-rw-r--r--packages/SystemUI/res/values-zh-rHK/strings.xml45
-rw-r--r--packages/SystemUI/res/values-zh-rTW/strings.xml43
-rw-r--r--packages/SystemUI/res/values-zu/strings.xml17
-rw-r--r--packages/SystemUI/res/values/colors.xml4
-rw-r--r--packages/SystemUI/res/values/dimens.xml35
-rw-r--r--packages/SystemUI/res/values/strings.xml21
-rw-r--r--packages/SystemUI/res/values/styles.xml12
-rw-r--r--packages/SystemUI/shared/src/com/android/systemui/shared/recents/ISystemUiProxy.aidl12
-rw-r--r--packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/Task.aidl19
-rw-r--r--packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/Task.java50
-rw-r--r--packages/SystemUI/shared/src/com/android/systemui/shared/recents/utilities/BitmapUtil.java86
-rw-r--r--packages/SystemUI/shared/src/com/android/systemui/shared/system/TaskStackChangeListener.java3
-rw-r--r--packages/SystemUI/shared/src/com/android/systemui/shared/system/TaskStackChangeListeners.java13
-rw-r--r--packages/SystemUI/shared/src/com/android/systemui/shared/system/ViewRootImplCompat.java9
-rw-r--r--packages/SystemUI/src/com/android/keyguard/KeyguardFaceListenModel.kt26
-rw-r--r--packages/SystemUI/src/com/android/keyguard/KeyguardSliceView.java8
-rw-r--r--packages/SystemUI/src/com/android/keyguard/KeyguardStatusView.java23
-rw-r--r--packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java75
-rw-r--r--packages/SystemUI/src/com/android/systemui/Prefs.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/SystemUIFactory.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/assist/AssistManager.java39
-rw-r--r--packages/SystemUI/src/com/android/systemui/assist/AssistantInvocationEvent.kt119
-rw-r--r--packages/SystemUI/src/com/android/systemui/assist/PhoneStateMonitor.java20
-rw-r--r--packages/SystemUI/src/com/android/systemui/biometrics/AuthContainerView.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/bubbles/Bubble.java83
-rw-r--r--packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java123
-rw-r--r--packages/SystemUI/src/com/android/systemui/bubbles/BubbleData.java86
-rw-r--r--packages/SystemUI/src/com/android/systemui/bubbles/BubbleDataRepository.kt6
-rw-r--r--packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedView.java178
-rw-r--r--packages/SystemUI/src/com/android/systemui/bubbles/BubbleFlyoutView.java3
-rw-r--r--packages/SystemUI/src/com/android/systemui/bubbles/BubbleManageEducationView.java24
-rw-r--r--packages/SystemUI/src/com/android/systemui/bubbles/BubbleOverflow.java3
-rw-r--r--packages/SystemUI/src/com/android/systemui/bubbles/BubbleOverflowActivity.java33
-rw-r--r--packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java687
-rw-r--r--packages/SystemUI/src/com/android/systemui/bubbles/animation/AnimatableScaleMatrix.java137
-rw-r--r--packages/SystemUI/src/com/android/systemui/bubbles/animation/ExpandedAnimationController.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/bubbles/animation/StackAnimationController.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/bubbles/dagger/BubbleModule.java3
-rw-r--r--packages/SystemUI/src/com/android/systemui/bubbles/storage/BubbleEntity.kt5
-rw-r--r--packages/SystemUI/src/com/android/systemui/bubbles/storage/BubblePersistentRepository.kt1
-rw-r--r--packages/SystemUI/src/com/android/systemui/bubbles/storage/BubbleXmlHelper.kt8
-rw-r--r--packages/SystemUI/src/com/android/systemui/controls/controller/ControlsController.kt5
-rw-r--r--packages/SystemUI/src/com/android/systemui/controls/controller/ControlsControllerImpl.kt23
-rw-r--r--packages/SystemUI/src/com/android/systemui/controls/ui/ControlActionCoordinator.kt22
-rw-r--r--packages/SystemUI/src/com/android/systemui/controls/ui/ControlActionCoordinatorImpl.kt83
-rw-r--r--packages/SystemUI/src/com/android/systemui/controls/ui/ControlViewHolder.kt54
-rw-r--r--packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiControllerImpl.kt54
-rw-r--r--packages/SystemUI/src/com/android/systemui/controls/ui/DetailDialog.kt4
-rw-r--r--packages/SystemUI/src/com/android/systemui/controls/ui/RenderInfo.kt4
-rw-r--r--packages/SystemUI/src/com/android/systemui/controls/ui/StatusBehavior.kt58
-rw-r--r--packages/SystemUI/src/com/android/systemui/controls/ui/ToggleRangeBehavior.kt13
-rw-r--r--packages/SystemUI/src/com/android/systemui/controls/ui/Vibrations.kt26
-rw-r--r--packages/SystemUI/src/com/android/systemui/dagger/DefaultActivityBinder.java15
-rw-r--r--packages/SystemUI/src/com/android/systemui/doze/DozeFactory.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java230
-rw-r--r--packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsPopupMenu.java7
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/MediaControlPanel.java264
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/MediaData.kt8
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/MediaDataCombineLatest.kt24
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/MediaDataManager.kt192
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/MediaDeviceManager.kt56
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/MediaHost.kt2
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/MediaResumeListener.kt252
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/MediaTimeoutListener.kt19
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/MediaViewManager.kt27
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/ResumeMediaBrowser.java (renamed from packages/SystemUI/src/com/android/systemui/qs/QSMediaBrowser.java)66
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/SeekBarViewModel.kt60
-rw-r--r--packages/SystemUI/src/com/android/systemui/pip/PipTaskOrganizer.java14
-rw-r--r--packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivity.java8
-rw-r--r--packages/SystemUI/src/com/android/systemui/pip/phone/PipResizeGestureHandler.java27
-rw-r--r--packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java22
-rw-r--r--packages/SystemUI/src/com/android/systemui/power/EnhancedEstimatesImpl.java6
-rw-r--r--packages/SystemUI/src/com/android/systemui/power/PowerUI.java15
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/PageIndicator.java7
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/QSContainerImpl.java63
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/QSPanel.java75
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/QSTileHost.java15
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java36
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java86
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/TileLayout.java5
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/external/TileServices.java8
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tiles/ScreenRecordTile.java7
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tiles/UserDetailItemView.java11
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tiles/UserDetailView.java29
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java80
-rw-r--r--packages/SystemUI/src/com/android/systemui/screenrecord/Events.java45
-rw-r--r--packages/SystemUI/src/com/android/systemui/screenrecord/RecordingService.java129
-rw-r--r--packages/SystemUI/src/com/android/systemui/screenrecord/ScreenInternalAudioRecorder.java18
-rw-r--r--packages/SystemUI/src/com/android/systemui/screenrecord/ScreenMediaRecorder.java57
-rw-r--r--packages/SystemUI/src/com/android/systemui/screenrecord/ScreenRecordDialog.java5
-rw-r--r--packages/SystemUI/src/com/android/systemui/screenrecord/ScreenRecordingAdapter.java6
-rw-r--r--packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java184
-rw-r--r--packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshotLegacy.java7
-rw-r--r--packages/SystemUI/src/com/android/systemui/screenshot/SaveImageInBackgroundTask.java1
-rw-r--r--packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotNotificationsController.java60
-rw-r--r--packages/SystemUI/src/com/android/systemui/screenshot/TakeScreenshotService.java15
-rw-r--r--packages/SystemUI/src/com/android/systemui/stackdivider/Divider.java54
-rw-r--r--packages/SystemUI/src/com/android/systemui/stackdivider/DividerImeController.java3
-rw-r--r--packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java71
-rw-r--r--packages/SystemUI/src/com/android/systemui/stackdivider/SplitScreenTaskOrganizer.java3
-rw-r--r--packages/SystemUI/src/com/android/systemui/stackdivider/SyncTransactionQueue.java177
-rw-r--r--packages/SystemUI/src/com/android/systemui/stackdivider/WindowManagerProxy.java89
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java27
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/NotificationViewHierarchyManager.java22
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/dagger/StatusBarDependenciesModule.java9
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/ConversationNotifications.kt62
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationFilter.java13
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/MediaCoordinator.java52
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/NotifCoordinators.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/provider/HighPriorityProvider.java23
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/row/AppOpsInfo.java19
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ChannelEditorDialogController.kt1
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java5
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java18
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationConversationInfo.java73
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGuts.java52
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGutsManager.java14
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInfo.java28
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationSnooze.java10
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/row/PartialConversationInfo.java80
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/row/PriorityOnboardingDialogController.kt152
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationConversationTemplateViewWrapper.kt5
-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/row/wrapper/NotificationViewWrapper.java7
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManager.kt45
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/PeopleHubView.kt2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/AutoTileManager.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/LockscreenGestureLogger.java60
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/LockscreenLockIconController.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java48
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarInflaterView.java7
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java23
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java12
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java7
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelViewController.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java13
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/VerticalNavigationHandle.java15
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonView.java83
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcher.java39
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java9
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java12
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/tv/micdisclosure/AudioRecordingDisclosureBar.java12
-rw-r--r--packages/SystemUI/src/com/android/systemui/usb/UsbDebuggingActivity.java91
-rw-r--r--packages/SystemUI/src/com/android/systemui/usb/UsbDebuggingSecondaryUserActivity.java70
-rw-r--r--packages/SystemUI/src/com/android/systemui/util/DismissCircleView.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/util/Utils.java9
-rw-r--r--packages/SystemUI/src/com/android/systemui/util/animation/PhysicsAnimator.kt38
-rw-r--r--packages/SystemUI/src/com/android/systemui/util/magnetictarget/MagnetizedObject.kt68
-rw-r--r--packages/SystemUI/src/com/android/systemui/util/sensors/ProximitySensor.java38
-rw-r--r--packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java1
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthContainerViewTest.java9
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java56
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleDataTest.java4
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/bubbles/NewNotifPipelineBubbleControllerTest.java34
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/bubbles/TestableBubbleController.java4
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/bubbles/storage/BubblePersistentRepositoryTest.kt13
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/bubbles/storage/BubbleVolatileRepositoryTest.kt6
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/bubbles/storage/BubbleXmlHelperTest.kt18
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/globalactions/GlobalActionsDialogTest.java129
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/media/MediaControlPanelTest.kt31
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/media/MediaDataCombineLatestTest.java30
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/media/MediaDeviceManagerTest.kt110
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/media/MediaTimeoutListenerTest.kt49
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/media/SeekBarViewModelTest.kt3
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/qs/QSTileHostTest.java32
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/qs/external/TileServicesTest.java33
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/qs/tiles/ScreenRecordTileTest.java5
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/screenrecord/RecordingServiceTest.java114
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationFilterTest.java73
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/HighPriorityProviderTest.java27
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotificationRankingManagerTest.kt3
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/MediaCoordinatorTest.java126
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/AppOpsInfoTest.java2
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationContentViewTest.java41
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationConversationInfoTest.java97
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationInfoTest.java6
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/PartialConversationInfoTest.java122
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManagerTest.java10
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/AutoTileManagerTest.java5
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NavigationBarFragmentTest.java13
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationIconAreaControllerTest.java18
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/KeyButtonViewTest.java123
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/util/animation/PhysicsAnimatorTest.kt7
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/util/concurrency/FakeRepeatableExecutor.java34
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/util/sensors/ProximityCheckTest.java26
-rw-r--r--packages/Tethering/Android.bp4
-rw-r--r--packages/Tethering/common/TetheringLib/Android.bp5
-rw-r--r--packages/Tethering/src/android/net/ip/IpServer.java108
-rw-r--r--packages/Tethering/src/android/net/util/TetheringUtils.java77
-rw-r--r--packages/Tethering/src/com/android/networkstack/tethering/BpfCoordinator.java637
-rw-r--r--packages/Tethering/src/com/android/networkstack/tethering/Tethering.java9
-rw-r--r--packages/Tethering/src/com/android/networkstack/tethering/TetheringDependencies.java11
-rw-r--r--packages/Tethering/src/com/android/networkstack/tethering/TetheringNotificationUpdater.java22
-rw-r--r--packages/Tethering/src/com/android/networkstack/tethering/TetheringService.java17
-rw-r--r--packages/Tethering/tests/integration/src/android/net/EthernetTetheringTest.java4
-rw-r--r--packages/Tethering/tests/unit/Android.bp2
-rw-r--r--packages/Tethering/tests/unit/src/android/net/ip/IpServerTest.java176
-rw-r--r--packages/Tethering/tests/unit/src/com/android/networkstack/tethering/BpfCoordinatorTest.java246
-rw-r--r--packages/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringNotificationUpdaterTest.kt27
-rw-r--r--packages/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringServiceTest.java23
-rw-r--r--packages/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringTest.java7
-rw-r--r--packages/overlays/IconPackCircularLauncherOverlay/res/drawable/ic_select.xml13
-rw-r--r--packages/overlays/IconPackFilledLauncherOverlay/res/drawable/ic_select.xml13
-rw-r--r--packages/overlays/IconPackRoundedLauncherOverlay/res/drawable/ic_select.xml15
-rw-r--r--samples/demo/haptic-assessment/Android.bp34
-rw-r--r--samples/demo/haptic-assessment/AndroidManifest.xml38
-rw-r--r--samples/demo/haptic-assessment/README.txt13
-rw-r--r--samples/demo/haptic-assessment/res/drawable-v24/ic_launcher_foreground.xml46
-rw-r--r--samples/demo/haptic-assessment/res/drawable/bluebar.pngbin0 -> 3883 bytes
-rw-r--r--samples/demo/haptic-assessment/res/drawable/cross_60x60.gifbin0 -> 1252 bytes
-rw-r--r--samples/demo/haptic-assessment/res/drawable/ic_launcher_background.xml185
-rw-r--r--samples/demo/haptic-assessment/res/layout/activity_main.xml93
-rw-r--r--samples/demo/haptic-assessment/res/mipmap-anydpi-v26/ic_launcher.xml20
-rw-r--r--samples/demo/haptic-assessment/res/mipmap-anydpi-v26/ic_launcher_round.xml20
-rw-r--r--samples/demo/haptic-assessment/res/mipmap-hdpi/ic_launcher.pngbin0 -> 3593 bytes
-rw-r--r--samples/demo/haptic-assessment/res/mipmap-hdpi/ic_launcher_round.pngbin0 -> 5339 bytes
-rw-r--r--samples/demo/haptic-assessment/res/mipmap-mdpi/ic_launcher.pngbin0 -> 2636 bytes
-rw-r--r--samples/demo/haptic-assessment/res/mipmap-mdpi/ic_launcher_round.pngbin0 -> 3388 bytes
-rw-r--r--samples/demo/haptic-assessment/res/mipmap-xhdpi/ic_launcher.pngbin0 -> 4926 bytes
-rw-r--r--samples/demo/haptic-assessment/res/mipmap-xhdpi/ic_launcher_round.pngbin0 -> 7472 bytes
-rw-r--r--samples/demo/haptic-assessment/res/mipmap-xxhdpi/ic_launcher.pngbin0 -> 7909 bytes
-rw-r--r--samples/demo/haptic-assessment/res/mipmap-xxhdpi/ic_launcher_round.pngbin0 -> 11873 bytes
-rw-r--r--samples/demo/haptic-assessment/res/mipmap-xxxhdpi/ic_launcher.pngbin0 -> 10652 bytes
-rw-r--r--samples/demo/haptic-assessment/res/mipmap-xxxhdpi/ic_launcher_round.pngbin0 -> 16570 bytes
-rw-r--r--samples/demo/haptic-assessment/res/values/colors.xml21
-rw-r--r--samples/demo/haptic-assessment/res/values/dimen.xml25
-rw-r--r--samples/demo/haptic-assessment/res/values/strings.xml24
-rw-r--r--samples/demo/haptic-assessment/res/values/styles.xml28
-rw-r--r--samples/demo/haptic-assessment/src/com/example/android/hapticassessment/MainActivity.kt71
-rw-r--r--services/Android.bp2
-rw-r--r--services/accessibility/java/com/android/server/accessibility/AccessibilityWindowManager.java3
-rw-r--r--services/autofill/java/com/android/server/autofill/AutofillInlineSessionController.java4
-rw-r--r--services/autofill/java/com/android/server/autofill/AutofillInlineSuggestionsRequestSession.java18
-rw-r--r--services/autofill/java/com/android/server/autofill/AutofillManagerService.java2
-rw-r--r--services/autofill/java/com/android/server/autofill/RemoteAugmentedAutofillService.java5
-rw-r--r--services/autofill/java/com/android/server/autofill/Session.java5
-rw-r--r--services/core/Android.bp4
-rw-r--r--services/core/java/android/content/pm/PackageManagerInternal.java10
-rw-r--r--services/core/java/com/android/server/AppStateTracker.java3
-rw-r--r--services/core/java/com/android/server/BluetoothManagerService.java12
-rw-r--r--services/core/java/com/android/server/ConnectivityService.java7
-rw-r--r--services/core/java/com/android/server/PackageWatchdog.java9
-rw-r--r--services/core/java/com/android/server/StorageManagerService.java33
-rw-r--r--services/core/java/com/android/server/SystemServiceManager.java6
-rw-r--r--services/core/java/com/android/server/VibratorService.java60
-rw-r--r--services/core/java/com/android/server/am/ActiveServices.java46
-rw-r--r--services/core/java/com/android/server/am/ActivityManagerService.java97
-rw-r--r--services/core/java/com/android/server/am/OomAdjuster.java31
-rw-r--r--services/core/java/com/android/server/am/PendingStartActivityUids.java78
-rw-r--r--services/core/java/com/android/server/am/ProcessList.java16
-rw-r--r--services/core/java/com/android/server/am/ServiceRecord.java5
-rw-r--r--services/core/java/com/android/server/am/UserController.java17
-rw-r--r--services/core/java/com/android/server/appop/AppOpsService.java135
-rw-r--r--services/core/java/com/android/server/appop/HistoricalRegistry.java39
-rw-r--r--services/core/java/com/android/server/audio/AudioDeviceBroker.java3
-rwxr-xr-xservices/core/java/com/android/server/audio/AudioService.java77
-rw-r--r--services/core/java/com/android/server/display/BrightnessMappingStrategy.java7
-rw-r--r--services/core/java/com/android/server/hdmi/Constants.java33
-rw-r--r--services/core/java/com/android/server/hdmi/HdmiCecLocalDevicePlayback.java79
-rw-r--r--services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceSource.java3
-rw-r--r--services/core/java/com/android/server/hdmi/HdmiControlService.java63
-rw-r--r--services/core/java/com/android/server/hdmi/SystemAudioStatusAction.java6
-rw-r--r--services/core/java/com/android/server/location/LocationManagerService.java98
-rw-r--r--services/core/java/com/android/server/location/UserInfoHelper.java213
-rw-r--r--services/core/java/com/android/server/locksettings/ManagedProfilePasswordCache.java14
-rw-r--r--services/core/java/com/android/server/media/MediaKeyDispatcher.java26
-rw-r--r--services/core/java/com/android/server/media/MediaRoute2ProviderServiceProxy.java3
-rw-r--r--services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java58
-rw-r--r--services/core/java/com/android/server/media/MediaSessionService.java28
-rw-r--r--services/core/java/com/android/server/notification/BadgeExtractor.java5
-rw-r--r--services/core/java/com/android/server/notification/NotificationHistoryDatabase.java58
-rwxr-xr-xservices/core/java/com/android/server/notification/NotificationManagerService.java44
-rw-r--r--services/core/java/com/android/server/notification/SysUiStatsEvent.java5
-rw-r--r--services/core/java/com/android/server/notification/ZenModeHelper.java76
-rw-r--r--services/core/java/com/android/server/om/IdmapManager.java9
-rw-r--r--services/core/java/com/android/server/om/OverlayManagerService.java27
-rw-r--r--services/core/java/com/android/server/om/OverlayManagerServiceImpl.java30
-rw-r--r--services/core/java/com/android/server/om/OverlayManagerSettings.java76
-rw-r--r--services/core/java/com/android/server/pm/DataLoaderManagerService.java15
-rw-r--r--services/core/java/com/android/server/pm/PackageInstallerService.java33
-rw-r--r--services/core/java/com/android/server/pm/PackageManagerService.java186
-rw-r--r--services/core/java/com/android/server/pm/PackageSettingBase.java5
-rw-r--r--services/core/java/com/android/server/pm/PersistentPreferredActivity.java19
-rw-r--r--services/core/java/com/android/server/pm/ShortcutService.java3
-rw-r--r--services/core/java/com/android/server/pm/StagingManager.java48
-rw-r--r--services/core/java/com/android/server/pm/TEST_MAPPING3
-rw-r--r--services/core/java/com/android/server/pm/UserManagerService.java27
-rw-r--r--services/core/java/com/android/server/pm/UserSystemPackageInstaller.java35
-rw-r--r--services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java2
-rw-r--r--services/core/java/com/android/server/pm/permission/PermissionManagerService.java20
-rw-r--r--services/core/java/com/android/server/pm/permission/PermissionManagerServiceInternal.java7
-rw-r--r--services/core/java/com/android/server/power/Notifier.java1
-rw-r--r--services/core/java/com/android/server/power/PreRebootLogger.java58
-rw-r--r--services/core/java/com/android/server/slice/SliceClientPermissions.java6
-rw-r--r--services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerModule.java51
-rw-r--r--services/core/java/com/android/server/stats/pull/StatsPullAtomService.java737
-rw-r--r--services/core/java/com/android/server/storage/StorageUserConnection.java20
-rw-r--r--services/core/java/com/android/server/textclassifier/FixedSizeQueue.java103
-rw-r--r--services/core/java/com/android/server/textclassifier/TEST_MAPPING7
-rw-r--r--services/core/java/com/android/server/textclassifier/TextClassificationManagerService.java33
-rw-r--r--services/core/java/com/android/server/uri/UriGrantsManagerService.java239
-rw-r--r--services/core/java/com/android/server/wm/AccessibilityController.java15
-rw-r--r--services/core/java/com/android/server/wm/ActivityRecord.java5
-rw-r--r--services/core/java/com/android/server/wm/ActivityStack.java88
-rw-r--r--services/core/java/com/android/server/wm/ActivityStackSupervisor.java2
-rw-r--r--services/core/java/com/android/server/wm/ActivityTaskManagerService.java9
-rw-r--r--services/core/java/com/android/server/wm/AlertWindowNotification.java4
-rw-r--r--services/core/java/com/android/server/wm/DisplayContent.java28
-rw-r--r--services/core/java/com/android/server/wm/EmulatorDisplayOverlay.java3
-rw-r--r--services/core/java/com/android/server/wm/InputMonitor.java26
-rw-r--r--services/core/java/com/android/server/wm/PinnedStackController.java21
-rw-r--r--services/core/java/com/android/server/wm/RootWindowContainer.java6
-rw-r--r--services/core/java/com/android/server/wm/StrictModeFlash.java4
-rw-r--r--services/core/java/com/android/server/wm/SurfaceAnimator.java30
-rw-r--r--services/core/java/com/android/server/wm/Task.java38
-rw-r--r--services/core/java/com/android/server/wm/TaskChangeNotificationController.java16
-rw-r--r--services/core/java/com/android/server/wm/TaskDisplayArea.java8
-rw-r--r--services/core/java/com/android/server/wm/TaskSnapshotSurface.java1
-rw-r--r--services/core/java/com/android/server/wm/WallpaperController.java14
-rw-r--r--services/core/java/com/android/server/wm/Watermark.java3
-rw-r--r--services/core/java/com/android/server/wm/WindowContainer.java11
-rw-r--r--services/core/java/com/android/server/wm/WindowManagerService.java22
-rw-r--r--services/core/java/com/android/server/wm/WindowProcessController.java7
-rw-r--r--services/core/java/com/android/server/wm/WindowState.java15
-rw-r--r--services/core/java/com/android/server/wm/WindowStateAnimator.java42
-rw-r--r--services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java74
-rw-r--r--services/tests/PackageManagerServiceTests/host/Android.bp33
-rw-r--r--services/tests/PackageManagerServiceTests/host/AndroidTest.xml26
-rw-r--r--services/tests/PackageManagerServiceTests/host/src/com/android/server/pm/test/HostUtils.kt46
-rw-r--r--services/tests/PackageManagerServiceTests/host/src/com/android/server/pm/test/OriginalPackageMigrationTest.kt98
-rw-r--r--services/tests/PackageManagerServiceTests/host/src/com/android/server/pm/test/Partition.kt31
-rw-r--r--services/tests/PackageManagerServiceTests/host/test-apps/Android.bp33
-rw-r--r--services/tests/PackageManagerServiceTests/host/test-apps/AndroidManifestOriginalOverride.xml25
-rw-r--r--services/tests/PackageManagerServiceTests/host/test-apps/AndroidManifestVersion1.xml21
-rw-r--r--services/tests/PackageManagerServiceTests/host/test-apps/AndroidManifestVersion2.xml21
-rw-r--r--services/tests/PackageManagerServiceTests/host/test-apps/AndroidManifestVersion3.xml21
-rw-r--r--services/tests/mockingservicestests/Android.bp2
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/location/UserInfoHelperTest.java145
-rw-r--r--services/tests/servicestests/Android.bp2
-rw-r--r--services/tests/servicestests/assets/AppIntegrityManagerServiceImplTest/SourceStampTestApk.apkbin16854 -> 2075621 bytes
-rw-r--r--services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceMigrationTest.java88
-rw-r--r--services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java53
-rw-r--r--services/tests/servicestests/src/com/android/server/devicepolicy/DpmTestBase.java19
-rw-r--r--services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDevicePlaybackTest.java205
-rw-r--r--services/tests/servicestests/src/com/android/server/hdmi/HdmiControlServiceTest.java86
-rw-r--r--services/tests/servicestests/src/com/android/server/integrity/AppIntegrityManagerServiceImplTest.java2
-rw-r--r--services/tests/servicestests/src/com/android/server/om/OverlayManagerServiceImplTests.java135
-rw-r--r--services/tests/servicestests/src/com/android/server/om/OverlayManagerServiceImplTestsBase.java23
-rw-r--r--services/tests/servicestests/src/com/android/server/om/OverlayManagerSettingsTests.java4
-rw-r--r--services/tests/servicestests/src/com/android/server/pm/UserSystemPackageInstallerTest.java66
-rw-r--r--services/tests/servicestests/src/com/android/server/pm/parsing/AndroidPackageParsingEquivalenceTest.kt85
-rw-r--r--services/tests/servicestests/src/com/android/server/pm/parsing/AndroidPackageParsingTestBase.kt174
-rw-r--r--services/tests/servicestests/src/com/android/server/power/PreRebootLoggerTest.java50
-rw-r--r--services/tests/servicestests/src/com/android/server/textclassifier/FixedSizeQueueTest.java109
-rw-r--r--services/tests/servicestests/src/com/android/server/uri/UriGrantsManagerServiceTest.java74
-rw-r--r--services/tests/uiservicestests/src/com/android/server/notification/BadgeExtractorTest.java49
-rw-r--r--services/tests/uiservicestests/src/com/android/server/notification/NotificationHistoryDatabaseTest.java7
-rwxr-xr-xservices/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java270
-rw-r--r--services/tests/uiservicestests/src/com/android/server/notification/WrappedSysUiStatsEvent.java12
-rw-r--r--services/tests/uiservicestests/src/com/android/server/notification/ZenModeConfigTest.java30
-rw-r--r--services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java198
-rw-r--r--services/tests/uiservicestests/src/com/android/server/notification/ZenPolicyTest.java165
-rw-r--r--services/tests/wmtests/AndroidManifest.xml1
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/ActivityLeakTests.java184
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/ActivityTaskManagerServiceTests.java16
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/AppWindowTokenTests.java22
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java56
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java5
-rw-r--r--services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java40
-rw-r--r--services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceShellCommand.java15
-rw-r--r--telephony/common/com/android/internal/telephony/CarrierAppUtils.java8
-rwxr-xr-xtelephony/java/android/telephony/CarrierConfigManager.java4
-rw-r--r--telephony/java/android/telephony/SmsCbMessage.java8
-rw-r--r--tests/PackageWatchdog/src/com/android/server/PackageWatchdogTest.java1
-rw-r--r--tests/RollbackTest/MultiUserRollbackTest.xml6
-rw-r--r--tests/RollbackTest/MultiUserRollbackTest/src/com/android/tests/rollback/host/MultiUserRollbackTest.java9
-rw-r--r--tests/RollbackTest/NetworkStagedRollbackTest/src/com/android/tests/rollback/host/NetworkStagedRollbackTest.java2
-rw-r--r--tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/MultiUserRollbackTest.java12
-rw-r--r--tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/NetworkStagedRollbackTest.java20
-rw-r--r--tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/RollbackTest.java17
-rw-r--r--tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/StagedRollbackTest.java5
-rw-r--r--tests/RollbackTest/StagedRollbackTest.xml6
-rw-r--r--tests/net/common/java/android/net/NetworkAgentConfigTest.kt2
-rw-r--r--tests/utils/hostutils/Android.bp28
-rw-r--r--tests/utils/hostutils/src/com/android/internal/util/test/SystemPreparer.java362
-rw-r--r--tools/aapt2/Debug.cpp25
-rw-r--r--wifi/Android.bp6
-rw-r--r--wifi/java/android/net/wifi/WifiEnterpriseConfig.java22
-rw-r--r--wifi/java/android/net/wifi/WifiInfo.java9
-rw-r--r--wifi/java/android/net/wifi/WifiNetworkSuggestion.java14
-rw-r--r--wifi/java/android/net/wifi/hotspot2/omadm/PpsMoParser.java22
-rw-r--r--wifi/tests/src/android/net/wifi/WifiEnterpriseConfigTest.java27
-rw-r--r--wifi/tests/src/android/net/wifi/WifiNetworkSuggestionTest.java37
961 files changed, 21371 insertions, 8543 deletions
diff --git a/Android.bp b/Android.bp
index 557c3209248d..632f49da5df9 100644
--- a/Android.bp
+++ b/Android.bp
@@ -292,13 +292,13 @@ filegroup {
java_library {
name: "framework-updatable-stubs-module_libs_api",
static_libs: [
- "framework-media-stubs-module_libs_api",
- "framework-mediaprovider-stubs-module_libs_api",
- "framework-permission-stubs-module_libs_api",
- "framework-sdkextensions-stubs-module_libs_api",
- "framework-statsd-stubs-module_libs_api",
- "framework-tethering-stubs-module_libs_api",
- "framework-wifi-stubs-module_libs_api",
+ "framework-media.stubs.module_lib",
+ "framework-mediaprovider.stubs.module_lib",
+ "framework-permission.stubs.module_lib",
+ "framework-sdkextensions.stubs.module_lib",
+ "framework-statsd.stubs.module_lib",
+ "framework-tethering.stubs.module_lib",
+ "framework-wifi.stubs.module_lib",
],
sdk_version: "module_current",
visibility: [":__pkg__"],
diff --git a/StubLibraries.bp b/StubLibraries.bp
index c0197c4b2acf..ef4e202fdfe2 100644
--- a/StubLibraries.bp
+++ b/StubLibraries.bp
@@ -329,13 +329,13 @@ java_library_static {
srcs: [ ":api-stubs-docs-non-updatable" ],
static_libs: [
"conscrypt.module.public.api.stubs",
- "framework-media-stubs-publicapi",
- "framework-mediaprovider-stubs-publicapi",
- "framework-permission-stubs-publicapi",
- "framework-sdkextensions-stubs-publicapi",
- "framework-statsd-stubs-publicapi",
- "framework-tethering-stubs-publicapi",
- "framework-wifi-stubs-publicapi",
+ "framework-media.stubs",
+ "framework-mediaprovider.stubs",
+ "framework-permission.stubs",
+ "framework-sdkextensions.stubs",
+ "framework-statsd.stubs",
+ "framework-tethering.stubs",
+ "framework-wifi.stubs",
"private-stub-annotations-jar",
],
defaults: ["android_defaults_stubs_current"],
@@ -359,13 +359,13 @@ java_library_static {
srcs: [ ":system-api-stubs-docs-non-updatable" ],
static_libs: [
"conscrypt.module.public.api.stubs",
- "framework-media-stubs-systemapi",
- "framework-mediaprovider-stubs-systemapi",
- "framework-permission-stubs-systemapi",
- "framework-sdkextensions-stubs-systemapi",
- "framework-statsd-stubs-systemapi",
- "framework-tethering-stubs-systemapi",
- "framework-wifi-stubs-systemapi",
+ "framework-media.stubs.system",
+ "framework-mediaprovider.stubs.system",
+ "framework-permission.stubs.system",
+ "framework-sdkextensions.stubs.system",
+ "framework-statsd.stubs.system",
+ "framework-tethering.stubs.system",
+ "framework-wifi.stubs.system",
"private-stub-annotations-jar",
],
defaults: ["android_defaults_stubs_current"],
diff --git a/apex/Android.bp b/apex/Android.bp
index c1715a002d6d..371bd7fc9479 100644
--- a/apex/Android.bp
+++ b/apex/Android.bp
@@ -63,9 +63,9 @@ mainline_service_stubs_args =
"--hide-annotation android.annotation.Hide " +
"--hide InternalClasses " // com.android.* classes are okay in this interface
-// Defaults for mainline module provided java_sdk_library instances.
+// Defaults common to all mainline module java_sdk_library instances.
java_defaults {
- name: "framework-module-defaults",
+ name: "framework-module-common-defaults",
// Additional annotations used for compiling both the implementation and the
// stubs libraries.
@@ -88,14 +88,6 @@ java_defaults {
enabled: true,
sdk_version: "module_current",
},
- system: {
- enabled: true,
- sdk_version: "module_current",
- },
- module_lib: {
- enabled: true,
- sdk_version: "module_current",
- },
// Configure framework module specific metalava options.
droiddoc_options: [mainline_stubs_args],
@@ -127,6 +119,32 @@ java_defaults {
sdk_version: "module_current",
}
+// Defaults for mainline module provided java_sdk_library instances.
+java_defaults {
+ name: "framework-module-defaults",
+ defaults: ["framework-module-common-defaults"],
+
+ system: {
+ enabled: true,
+ sdk_version: "module_current",
+ },
+ module_lib: {
+ enabled: true,
+ sdk_version: "module_current",
+ },
+}
+
+// Defaults for mainline module system server provided java_sdk_library instances.
+java_defaults {
+ name: "framework-system-server-module-defaults",
+ defaults: ["framework-module-common-defaults"],
+
+ system_server: {
+ enabled: true,
+ sdk_version: "module_current",
+ },
+}
+
stubs_defaults {
name: "framework-module-stubs-defaults-publicapi",
args: mainline_framework_stubs_args,
diff --git a/apex/blobstore/framework/java/android/app/blob/BlobHandle.java b/apex/blobstore/framework/java/android/app/blob/BlobHandle.java
index bcef8ceaa941..ecc78ce7cf34 100644
--- a/apex/blobstore/framework/java/android/app/blob/BlobHandle.java
+++ b/apex/blobstore/framework/java/android/app/blob/BlobHandle.java
@@ -219,7 +219,7 @@ public final class BlobHandle implements Parcelable {
public void dump(IndentingPrintWriter fout, boolean dumpFull) {
if (dumpFull) {
fout.println("algo: " + algorithm);
- fout.println("digest: " + (dumpFull ? encodeDigest() : safeDigest()));
+ fout.println("digest: " + (dumpFull ? encodeDigest(digest) : safeDigest(digest)));
fout.println("label: " + label);
fout.println("expiryMs: " + expiryTimeMillis);
fout.println("tag: " + tag);
@@ -243,19 +243,20 @@ public final class BlobHandle implements Parcelable {
public String toString() {
return "BlobHandle {"
+ "algo:" + algorithm + ","
- + "digest:" + safeDigest() + ","
+ + "digest:" + safeDigest(digest) + ","
+ "label:" + label + ","
+ "expiryMs:" + expiryTimeMillis + ","
+ "tag:" + tag
+ "}";
}
- private String safeDigest() {
- final String digestStr = encodeDigest();
+ /** @hide */
+ public static String safeDigest(@NonNull byte[] digest) {
+ final String digestStr = encodeDigest(digest);
return digestStr.substring(0, 2) + ".." + digestStr.substring(digestStr.length() - 2);
}
- private String encodeDigest() {
+ private static String encodeDigest(@NonNull byte[] digest) {
return Base64.encodeToString(digest, Base64.NO_WRAP);
}
diff --git a/apex/blobstore/framework/java/android/app/blob/BlobInfo.java b/apex/blobstore/framework/java/android/app/blob/BlobInfo.java
index 80062d5d245f..ba92d95b483e 100644
--- a/apex/blobstore/framework/java/android/app/blob/BlobInfo.java
+++ b/apex/blobstore/framework/java/android/app/blob/BlobInfo.java
@@ -16,9 +16,13 @@
package android.app.blob;
+import static android.text.format.Formatter.FLAG_IEC_UNITS;
+
import android.annotation.NonNull;
+import android.app.AppGlobals;
import android.os.Parcel;
import android.os.Parcelable;
+import android.text.format.Formatter;
import java.util.Collections;
import java.util.List;
@@ -32,13 +36,15 @@ public final class BlobInfo implements Parcelable {
private final long mId;
private final long mExpiryTimeMs;
private final CharSequence mLabel;
+ private final long mSizeBytes;
private final List<LeaseInfo> mLeaseInfos;
- public BlobInfo(long id, long expiryTimeMs, CharSequence label,
+ public BlobInfo(long id, long expiryTimeMs, CharSequence label, long sizeBytes,
List<LeaseInfo> leaseInfos) {
mId = id;
mExpiryTimeMs = expiryTimeMs;
mLabel = label;
+ mSizeBytes = sizeBytes;
mLeaseInfos = leaseInfos;
}
@@ -46,6 +52,7 @@ public final class BlobInfo implements Parcelable {
mId = in.readLong();
mExpiryTimeMs = in.readLong();
mLabel = in.readCharSequence();
+ mSizeBytes = in.readLong();
mLeaseInfos = in.readArrayList(null /* classloader */);
}
@@ -61,6 +68,10 @@ public final class BlobInfo implements Parcelable {
return mLabel;
}
+ public long getSizeBytes() {
+ return mSizeBytes;
+ }
+
public List<LeaseInfo> getLeases() {
return Collections.unmodifiableList(mLeaseInfos);
}
@@ -70,6 +81,7 @@ public final class BlobInfo implements Parcelable {
dest.writeLong(mId);
dest.writeLong(mExpiryTimeMs);
dest.writeCharSequence(mLabel);
+ dest.writeLong(mSizeBytes);
dest.writeList(mLeaseInfos);
}
@@ -83,10 +95,16 @@ public final class BlobInfo implements Parcelable {
+ "id: " + mId + ","
+ "expiryMs: " + mExpiryTimeMs + ","
+ "label: " + mLabel + ","
+ + "size: " + formatBlobSize(mSizeBytes) + ","
+ "leases: " + LeaseInfo.toShortString(mLeaseInfos) + ","
+ "}";
}
+ private static String formatBlobSize(long sizeBytes) {
+ return Formatter.formatFileSize(AppGlobals.getInitialApplication(),
+ sizeBytes, FLAG_IEC_UNITS);
+ }
+
@Override
public int describeContents() {
return 0;
diff --git a/apex/blobstore/service/java/com/android/server/blob/BlobStoreManagerService.java b/apex/blobstore/service/java/com/android/server/blob/BlobStoreManagerService.java
index 8fff0d9c950b..68c4bb675907 100644
--- a/apex/blobstore/service/java/com/android/server/blob/BlobStoreManagerService.java
+++ b/apex/blobstore/service/java/com/android/server/blob/BlobStoreManagerService.java
@@ -478,11 +478,14 @@ public class BlobStoreManagerService extends SystemService {
? Resources.ID_NULL
: getDescriptionResourceId(resourcesGetter.apply(leasee.packageName),
leasee.descriptionResEntryName, leasee.packageName);
- leaseInfos.add(new LeaseInfo(leasee.packageName, leasee.expiryTimeMillis,
+ final long expiryTimeMs = leasee.expiryTimeMillis == 0
+ ? blobHandle.getExpiryTimeMillis() : leasee.expiryTimeMillis;
+ leaseInfos.add(new LeaseInfo(leasee.packageName, expiryTimeMs,
descriptionResId, leasee.description));
});
blobInfos.add(new BlobInfo(blobMetadata.getBlobId(),
- blobHandle.getExpiryTimeMillis(), blobHandle.getLabel(), leaseInfos));
+ blobHandle.getExpiryTimeMillis(), blobHandle.getLabel(),
+ blobMetadata.getSize(), leaseInfos));
});
}
return blobInfos;
@@ -591,6 +594,7 @@ public class BlobStoreManagerService extends SystemService {
} else {
blob.addOrReplaceCommitter(existingCommitter);
}
+ Slog.d(TAG, "Error committing the blob", e);
session.sendCommitCallbackResult(COMMIT_RESULT_ERROR);
}
getUserSessionsLocked(UserHandle.getUserId(session.getOwnerUid()))
diff --git a/apex/blobstore/service/java/com/android/server/blob/BlobStoreSession.java b/apex/blobstore/service/java/com/android/server/blob/BlobStoreSession.java
index 2b0458303a23..22d5d11e9ccb 100644
--- a/apex/blobstore/service/java/com/android/server/blob/BlobStoreSession.java
+++ b/apex/blobstore/service/java/com/android/server/blob/BlobStoreSession.java
@@ -28,7 +28,6 @@ import static android.system.OsConstants.O_RDONLY;
import static android.system.OsConstants.O_RDWR;
import static android.system.OsConstants.SEEK_SET;
-import static com.android.server.blob.BlobStoreConfig.LOGV;
import static com.android.server.blob.BlobStoreConfig.TAG;
import static com.android.server.blob.BlobStoreConfig.XML_VERSION_ADD_SESSION_CREATION_TIME;
import static com.android.server.blob.BlobStoreConfig.hasSessionExpired;
@@ -423,9 +422,10 @@ class BlobStoreSession extends IBlobStoreSession.Stub {
mState = STATE_VERIFIED_VALID;
// Commit callback will be sent once the data is persisted.
} else {
- if (LOGV) {
- Slog.v(TAG, "Digest of the data didn't match the given BlobHandle.digest");
- }
+ Slog.d(TAG, "Digest of the data ("
+ + (mDataDigest == null ? "null" : BlobHandle.safeDigest(mDataDigest))
+ + ") didn't match the given BlobHandle.digest ("
+ + BlobHandle.safeDigest(mBlobHandle.digest) + ")");
mState = STATE_VERIFIED_INVALID;
sendCommitCallbackResult(COMMIT_RESULT_ERROR);
}
diff --git a/apex/media/framework/Android.bp b/apex/media/framework/Android.bp
index ac501a510e80..4417b681efc3 100644
--- a/apex/media/framework/Android.bp
+++ b/apex/media/framework/Android.bp
@@ -96,11 +96,6 @@ java_sdk_library {
":updatable-media-srcs",
],
- // TODO(b/155480189) - Remove naming_scheme once references have been resolved.
- // Temporary java_sdk_library component naming scheme to use to ease the transition from separate
- // modules to java_sdk_library.
- naming_scheme: "framework-modules",
-
libs: [
"framework_media_annotation",
],
diff --git a/apex/media/framework/java/android/media/MediaParser.java b/apex/media/framework/java/android/media/MediaParser.java
index 070b13b9e592..19f578ecfc66 100644
--- a/apex/media/framework/java/android/media/MediaParser.java
+++ b/apex/media/framework/java/android/media/MediaParser.java
@@ -203,6 +203,15 @@ public final class MediaParser {
/** Returned by {@link #getDurationMicros()} when the duration is unknown. */
public static final int UNKNOWN_DURATION = Integer.MIN_VALUE;
+ /**
+ * For each {@link #getSeekPoints} call, returns a single {@link SeekPoint} whose {@link
+ * SeekPoint#timeMicros} matches the requested timestamp, and whose {@link
+ * SeekPoint#position} is 0.
+ *
+ * @hide
+ */
+ public static final SeekMap DUMMY = new SeekMap(new DummyExoPlayerSeekMap());
+
private final com.google.android.exoplayer2.extractor.SeekMap mExoPlayerSeekMap;
private SeekMap(com.google.android.exoplayer2.extractor.SeekMap exoplayerSeekMap) {
@@ -219,7 +228,8 @@ public final class MediaParser {
* duration is unknown.
*/
public long getDurationMicros() {
- return mExoPlayerSeekMap.getDurationUs();
+ long durationUs = mExoPlayerSeekMap.getDurationUs();
+ return durationUs != C.TIME_UNSET ? durationUs : UNKNOWN_DURATION;
}
/**
@@ -794,6 +804,18 @@ public final class MediaParser {
*/
public static final String PARAMETER_EAGERLY_EXPOSE_TRACKTYPE =
"android.media.mediaparser.eagerlyExposeTrackType";
+ /**
+ * Sets whether a dummy {@link SeekMap} should be exposed before starting extraction. {@code
+ * boolean} expected. Default value is {@code false}.
+ *
+ * <p>For each {@link SeekMap#getSeekPoints} call, the dummy {@link SeekMap} returns a single
+ * {@link SeekPoint} whose {@link SeekPoint#timeMicros} matches the requested timestamp, and
+ * whose {@link SeekPoint#position} is 0.
+ *
+ * @hide
+ */
+ public static final String PARAMETER_EXPOSE_DUMMY_SEEKMAP =
+ "android.media.mediaparser.exposeDummySeekMap";
// Private constants.
@@ -957,6 +979,7 @@ public final class MediaParser {
private boolean mIncludeSupplementalData;
private boolean mIgnoreTimestampOffset;
private boolean mEagerlyExposeTrackType;
+ private boolean mExposeDummySeekMap;
private String mParserName;
private Extractor mExtractor;
private ExtractorInput mExtractorInput;
@@ -1016,6 +1039,9 @@ public final class MediaParser {
if (PARAMETER_EAGERLY_EXPOSE_TRACKTYPE.equals(parameterName)) {
mEagerlyExposeTrackType = (boolean) value;
}
+ if (PARAMETER_EXPOSE_DUMMY_SEEKMAP.equals(parameterName)) {
+ mExposeDummySeekMap = (boolean) value;
+ }
mParserParameters.put(parameterName, value);
return this;
}
@@ -1077,11 +1103,10 @@ public final class MediaParser {
}
mExoDataReader.mInputReader = seekableInputReader;
- // TODO: Apply parameters when creating extractor instances.
if (mExtractor == null) {
+ mPendingExtractorInit = true;
if (!mParserName.equals(PARSER_NAME_UNKNOWN)) {
mExtractor = createExtractor(mParserName);
- mExtractor.init(new ExtractorOutputAdapter());
} else {
for (String parserName : mParserNamesPool) {
Extractor extractor = createExtractor(parserName);
@@ -1106,9 +1131,18 @@ public final class MediaParser {
}
if (mPendingExtractorInit) {
+ if (mExposeDummySeekMap) {
+ // We propagate the dummy seek map before initializing the extractor, in case the
+ // extractor initialization outputs a seek map.
+ mOutputConsumer.onSeekMapFound(SeekMap.DUMMY);
+ }
mExtractor.init(new ExtractorOutputAdapter());
mPendingExtractorInit = false;
+ // We return after initialization to allow clients use any output information before
+ // starting actual extraction.
+ return true;
}
+
if (isPendingSeek()) {
mExtractor.seek(mPendingSeekPosition, mPendingSeekTimeMicros);
removePendingSeek();
@@ -1682,6 +1716,28 @@ public final class MediaParser {
}
}
+ private static final class DummyExoPlayerSeekMap
+ implements com.google.android.exoplayer2.extractor.SeekMap {
+
+ @Override
+ public boolean isSeekable() {
+ return true;
+ }
+
+ @Override
+ public long getDurationUs() {
+ return C.TIME_UNSET;
+ }
+
+ @Override
+ public SeekPoints getSeekPoints(long timeUs) {
+ com.google.android.exoplayer2.extractor.SeekPoint seekPoint =
+ new com.google.android.exoplayer2.extractor.SeekPoint(
+ timeUs, /* position= */ 0);
+ return new SeekPoints(seekPoint, seekPoint);
+ }
+ }
+
/** Creates extractor instances. */
private interface ExtractorFactory {
@@ -1922,6 +1978,7 @@ public final class MediaParser {
expectedTypeByParameterName.put(PARAMETER_INCLUDE_SUPPLEMENTAL_DATA, Boolean.class);
expectedTypeByParameterName.put(PARAMETER_IGNORE_TIMESTAMP_OFFSET, Boolean.class);
expectedTypeByParameterName.put(PARAMETER_EAGERLY_EXPOSE_TRACKTYPE, Boolean.class);
+ expectedTypeByParameterName.put(PARAMETER_EXPOSE_DUMMY_SEEKMAP, Boolean.class);
EXPECTED_TYPE_BY_PARAMETER_NAME = Collections.unmodifiableMap(expectedTypeByParameterName);
}
}
diff --git a/apex/permission/framework/Android.bp b/apex/permission/framework/Android.bp
index 732caecbd4a7..be553feb1d34 100644
--- a/apex/permission/framework/Android.bp
+++ b/apex/permission/framework/Android.bp
@@ -38,11 +38,6 @@ java_sdk_library {
":framework-permission-sources",
],
- // TODO(b/155480189) - Remove naming_scheme once references have been resolved.
- // Temporary java_sdk_library component naming scheme to use to ease the transition from separate
- // modules to java_sdk_library.
- naming_scheme: "framework-modules",
-
apex_available: [
"com.android.permission",
"test_com.android.permission",
diff --git a/apex/permission/service/Android.bp b/apex/permission/service/Android.bp
index 61449763540b..7f3187949712 100644
--- a/apex/permission/service/Android.bp
+++ b/apex/permission/service/Android.bp
@@ -20,14 +20,26 @@ filegroup {
path: "java",
}
-java_library {
+java_sdk_library {
name: "service-permission",
+ defaults: ["framework-system-server-module-defaults"],
+ visibility: [
+ "//frameworks/base/services/core",
+ "//frameworks/base/apex/permission",
+ "//frameworks/base/apex/permission/testing",
+ "//frameworks/base/apex/permission/tests",
+ "//frameworks/base/services/tests/mockingservicestests",
+ ],
+ impl_library_visibility: [
+ "//visibility:override",
+ "//frameworks/base/apex/permission/tests",
+ "//frameworks/base/services/tests/mockingservicestests",
+ "//frameworks/base/services/tests/servicestests",
+ ],
srcs: [
":service-permission-sources",
],
- sdk_version: "module_current",
libs: [
- "framework-annotations-lib",
"framework-permission",
],
apex_available: [
@@ -36,28 +48,3 @@ java_library {
],
installable: true,
}
-
-droidstubs {
- name: "service-permission-stubs-srcs",
- srcs: [ ":service-permission-sources" ],
- defaults: ["service-module-stubs-srcs-defaults"],
- check_api: {
- last_released: {
- api_file: ":service-permission.api.system-server.latest",
- removed_api_file: ":service-permission-removed.api.system-server.latest",
- },
- api_lint: {
- new_since: ":service-permission.api.system-server.latest",
- },
- },
- visibility: ["//visibility:private"],
- dist: { dest: "service-permission.txt" },
-}
-
-java_library {
- name: "service-permission-stubs",
- srcs: [":service-permission-stubs-srcs"],
- defaults: ["service-module-stubs-defaults"],
- visibility: ["//frameworks/base/services/core"],
- dist: { dest: "service-permission.jar" },
-}
diff --git a/apex/permission/service/api/current.txt b/apex/permission/service/api/current.txt
index c76cc3275737..d802177e249b 100644
--- a/apex/permission/service/api/current.txt
+++ b/apex/permission/service/api/current.txt
@@ -1,46 +1 @@
// Signature format: 2.0
-package com.android.permission.persistence {
-
- public interface RuntimePermissionsPersistence {
- method @NonNull public static com.android.permission.persistence.RuntimePermissionsPersistence createInstance();
- method public void deleteForUser(@NonNull android.os.UserHandle);
- method @Nullable public com.android.permission.persistence.RuntimePermissionsState readForUser(@NonNull android.os.UserHandle);
- method public void writeForUser(@NonNull com.android.permission.persistence.RuntimePermissionsState, @NonNull android.os.UserHandle);
- }
-
- public final class RuntimePermissionsState {
- ctor public RuntimePermissionsState(int, @Nullable String, @NonNull java.util.Map<java.lang.String,java.util.List<com.android.permission.persistence.RuntimePermissionsState.PermissionState>>, @NonNull java.util.Map<java.lang.String,java.util.List<com.android.permission.persistence.RuntimePermissionsState.PermissionState>>);
- method @Nullable public String getFingerprint();
- method @NonNull public java.util.Map<java.lang.String,java.util.List<com.android.permission.persistence.RuntimePermissionsState.PermissionState>> getPackagePermissions();
- method @NonNull public java.util.Map<java.lang.String,java.util.List<com.android.permission.persistence.RuntimePermissionsState.PermissionState>> getSharedUserPermissions();
- method public int getVersion();
- field public static final int NO_VERSION = -1; // 0xffffffff
- }
-
- public static final class RuntimePermissionsState.PermissionState {
- ctor public RuntimePermissionsState.PermissionState(@NonNull String, boolean, int);
- method public int getFlags();
- method @NonNull public String getName();
- method public boolean isGranted();
- }
-
-}
-
-package com.android.role.persistence {
-
- public interface RolesPersistence {
- method @NonNull public static com.android.role.persistence.RolesPersistence createInstance();
- method public void deleteForUser(@NonNull android.os.UserHandle);
- method @Nullable public com.android.role.persistence.RolesState readForUser(@NonNull android.os.UserHandle);
- method public void writeForUser(@NonNull com.android.role.persistence.RolesState, @NonNull android.os.UserHandle);
- }
-
- public final class RolesState {
- ctor public RolesState(int, @Nullable String, @NonNull java.util.Map<java.lang.String,java.util.Set<java.lang.String>>);
- method @Nullable public String getPackagesHash();
- method @NonNull public java.util.Map<java.lang.String,java.util.Set<java.lang.String>> getRoles();
- method public int getVersion();
- }
-
-}
-
diff --git a/apex/permission/service/api/system-server-current.txt b/apex/permission/service/api/system-server-current.txt
new file mode 100644
index 000000000000..c76cc3275737
--- /dev/null
+++ b/apex/permission/service/api/system-server-current.txt
@@ -0,0 +1,46 @@
+// Signature format: 2.0
+package com.android.permission.persistence {
+
+ public interface RuntimePermissionsPersistence {
+ method @NonNull public static com.android.permission.persistence.RuntimePermissionsPersistence createInstance();
+ method public void deleteForUser(@NonNull android.os.UserHandle);
+ method @Nullable public com.android.permission.persistence.RuntimePermissionsState readForUser(@NonNull android.os.UserHandle);
+ method public void writeForUser(@NonNull com.android.permission.persistence.RuntimePermissionsState, @NonNull android.os.UserHandle);
+ }
+
+ public final class RuntimePermissionsState {
+ ctor public RuntimePermissionsState(int, @Nullable String, @NonNull java.util.Map<java.lang.String,java.util.List<com.android.permission.persistence.RuntimePermissionsState.PermissionState>>, @NonNull java.util.Map<java.lang.String,java.util.List<com.android.permission.persistence.RuntimePermissionsState.PermissionState>>);
+ method @Nullable public String getFingerprint();
+ method @NonNull public java.util.Map<java.lang.String,java.util.List<com.android.permission.persistence.RuntimePermissionsState.PermissionState>> getPackagePermissions();
+ method @NonNull public java.util.Map<java.lang.String,java.util.List<com.android.permission.persistence.RuntimePermissionsState.PermissionState>> getSharedUserPermissions();
+ method public int getVersion();
+ field public static final int NO_VERSION = -1; // 0xffffffff
+ }
+
+ public static final class RuntimePermissionsState.PermissionState {
+ ctor public RuntimePermissionsState.PermissionState(@NonNull String, boolean, int);
+ method public int getFlags();
+ method @NonNull public String getName();
+ method public boolean isGranted();
+ }
+
+}
+
+package com.android.role.persistence {
+
+ public interface RolesPersistence {
+ method @NonNull public static com.android.role.persistence.RolesPersistence createInstance();
+ method public void deleteForUser(@NonNull android.os.UserHandle);
+ method @Nullable public com.android.role.persistence.RolesState readForUser(@NonNull android.os.UserHandle);
+ method public void writeForUser(@NonNull com.android.role.persistence.RolesState, @NonNull android.os.UserHandle);
+ }
+
+ public final class RolesState {
+ ctor public RolesState(int, @Nullable String, @NonNull java.util.Map<java.lang.String,java.util.Set<java.lang.String>>);
+ method @Nullable public String getPackagesHash();
+ method @NonNull public java.util.Map<java.lang.String,java.util.Set<java.lang.String>> getRoles();
+ method public int getVersion();
+ }
+
+}
+
diff --git a/apex/permission/service/api/system-server-removed.txt b/apex/permission/service/api/system-server-removed.txt
new file mode 100644
index 000000000000..d802177e249b
--- /dev/null
+++ b/apex/permission/service/api/system-server-removed.txt
@@ -0,0 +1 @@
+// Signature format: 2.0
diff --git a/apex/permission/service/java/com/android/permission/persistence/IoUtils.java b/apex/permission/service/java/com/android/permission/persistence/IoUtils.java
index 0ae44603516e..569a78c0ab41 100644
--- a/apex/permission/service/java/com/android/permission/persistence/IoUtils.java
+++ b/apex/permission/service/java/com/android/permission/persistence/IoUtils.java
@@ -20,6 +20,8 @@ import android.annotation.NonNull;
/**
* Utility class for IO.
+ *
+ * @hide
*/
public class IoUtils {
diff --git a/apex/permission/tests/Android.bp b/apex/permission/tests/Android.bp
index a1f7a544434c..271e328c1139 100644
--- a/apex/permission/tests/Android.bp
+++ b/apex/permission/tests/Android.bp
@@ -19,7 +19,7 @@ android_test {
"java/**/*.kt",
],
static_libs: [
- "service-permission",
+ "service-permission.impl",
"androidx.test.rules",
"androidx.test.ext.junit",
"androidx.test.ext.truth",
diff --git a/apex/statsd/framework/Android.bp b/apex/statsd/framework/Android.bp
index 78496c4074f8..15a2f22e0fea 100644
--- a/apex/statsd/framework/Android.bp
+++ b/apex/statsd/framework/Android.bp
@@ -20,8 +20,8 @@ genrule {
name: "statslog-statsd-java-gen",
tools: ["stats-log-api-gen"],
cmd: "$(location stats-log-api-gen) --java $(out) --module statsd" +
- " --javaPackage com.android.internal.util --javaClass StatsdStatsLog",
- out: ["com/android/internal/util/StatsdStatsLog.java"],
+ " --javaPackage com.android.internal.statsd --javaClass StatsdStatsLog",
+ out: ["com/android/internal/statsd/StatsdStatsLog.java"],
}
java_library_static {
@@ -51,11 +51,6 @@ java_sdk_library {
defaults: ["framework-module-defaults"],
installable: true,
- // TODO(b/155480189) - Remove naming_scheme once references have been resolved.
- // Temporary java_sdk_library component naming scheme to use to ease the transition from separate
- // modules to java_sdk_library.
- naming_scheme: "framework-modules",
-
srcs: [
":framework-statsd-sources",
],
@@ -65,7 +60,7 @@ java_sdk_library {
"android.os",
"android.util",
// From :statslog-statsd-java-gen
- "com.android.internal.util",
+ "com.android.internal.statsd",
],
api_packages: [
diff --git a/apex/statsd/framework/java/android/util/StatsEvent.java b/apex/statsd/framework/java/android/util/StatsEvent.java
index 8bd36a516b12..8be5c63f31e3 100644
--- a/apex/statsd/framework/java/android/util/StatsEvent.java
+++ b/apex/statsd/framework/java/android/util/StatsEvent.java
@@ -26,6 +26,8 @@ import android.os.SystemClock;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
+import java.util.Arrays;
+
/**
* StatsEvent builds and stores the buffer sent over the statsd socket.
* This class defines and encapsulates the socket protocol.
@@ -224,7 +226,9 @@ public final class StatsEvent {
// Max payload size is 4 bytes less as 4 bytes are reserved for statsEventTag.
// See android_util_StatsLog.cpp.
- private static final int MAX_PAYLOAD_SIZE = LOGGER_ENTRY_MAX_PAYLOAD - 4;
+ private static final int MAX_PUSH_PAYLOAD_SIZE = LOGGER_ENTRY_MAX_PAYLOAD - 4;
+
+ private static final int MAX_PULL_PAYLOAD_SIZE = 50 * 1024; // 50 KB
private final int mAtomId;
private final byte[] mPayload;
@@ -619,6 +623,7 @@ public final class StatsEvent {
@NonNull
public Builder usePooledBuffer() {
mUsePooledBuffer = true;
+ mBuffer.setMaxSize(MAX_PUSH_PAYLOAD_SIZE, mPos);
return this;
}
@@ -694,8 +699,9 @@ public final class StatsEvent {
@GuardedBy("sLock")
private static Buffer sPool;
- private final byte[] mBytes = new byte[MAX_PAYLOAD_SIZE];
+ private byte[] mBytes = new byte[MAX_PUSH_PAYLOAD_SIZE];
private boolean mOverflow = false;
+ private int mMaxSize = MAX_PULL_PAYLOAD_SIZE;
@NonNull
private static Buffer obtain() {
@@ -717,15 +723,26 @@ public final class StatsEvent {
}
private void release() {
- synchronized (sLock) {
- if (null == sPool) {
- sPool = this;
+ // Recycle this Buffer if its size is MAX_PUSH_PAYLOAD_SIZE or under.
+ if (mBytes.length <= MAX_PUSH_PAYLOAD_SIZE) {
+ synchronized (sLock) {
+ if (null == sPool) {
+ sPool = this;
+ }
}
}
}
private void reset() {
mOverflow = false;
+ mMaxSize = MAX_PULL_PAYLOAD_SIZE;
+ }
+
+ private void setMaxSize(final int maxSize, final int numBytesWritten) {
+ mMaxSize = maxSize;
+ if (numBytesWritten > maxSize) {
+ mOverflow = true;
+ }
}
private boolean hasOverflowed() {
@@ -740,11 +757,28 @@ public final class StatsEvent {
* @return true if space is available, false otherwise.
**/
private boolean hasEnoughSpace(final int index, final int numBytes) {
- final boolean result = index + numBytes < MAX_PAYLOAD_SIZE;
- if (!result) {
+ final int totalBytesNeeded = index + numBytes;
+
+ if (totalBytesNeeded > mMaxSize) {
mOverflow = true;
+ return false;
}
- return result;
+
+ // Expand buffer if needed.
+ if (mBytes.length < mMaxSize && totalBytesNeeded > mBytes.length) {
+ int newSize = mBytes.length;
+ do {
+ newSize *= 2;
+ } while (newSize <= totalBytesNeeded);
+
+ if (newSize > mMaxSize) {
+ newSize = mMaxSize;
+ }
+
+ mBytes = Arrays.copyOf(mBytes, newSize);
+ }
+
+ return true;
}
/**
diff --git a/apex/statsd/framework/java/android/util/StatsLog.java b/apex/statsd/framework/java/android/util/StatsLog.java
index 4eeae57fe195..0a9f4ebabdf0 100644
--- a/apex/statsd/framework/java/android/util/StatsLog.java
+++ b/apex/statsd/framework/java/android/util/StatsLog.java
@@ -28,7 +28,7 @@ import android.os.IStatsd;
import android.os.Process;
import android.util.proto.ProtoOutputStream;
-import com.android.internal.util.StatsdStatsLog;
+import com.android.internal.statsd.StatsdStatsLog;
/**
* StatsLog provides an API for developers to send events to statsd. The events can be used to
diff --git a/apex/statsd/framework/test/src/android/util/StatsEventTest.java b/apex/statsd/framework/test/src/android/util/StatsEventTest.java
index 7b511553a26f..8d263699d9c8 100644
--- a/apex/statsd/framework/test/src/android/util/StatsEventTest.java
+++ b/apex/statsd/framework/test/src/android/util/StatsEventTest.java
@@ -33,6 +33,7 @@ import org.junit.runner.RunWith;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
+import java.util.Random;
/**
* Internal tests for {@link StatsEvent}.
@@ -644,6 +645,165 @@ public class StatsEventTest {
statsEvent.release();
}
+ @Test
+ public void testLargePulledEvent() {
+ final int expectedAtomId = 10_020;
+ byte[] field1 = new byte[10 * 1024];
+ new Random().nextBytes(field1);
+
+ final long minTimestamp = SystemClock.elapsedRealtimeNanos();
+ final StatsEvent statsEvent =
+ StatsEvent.newBuilder().setAtomId(expectedAtomId).writeByteArray(field1).build();
+ final long maxTimestamp = SystemClock.elapsedRealtimeNanos();
+
+ assertThat(statsEvent.getAtomId()).isEqualTo(expectedAtomId);
+
+ final ByteBuffer buffer =
+ ByteBuffer.wrap(statsEvent.getBytes()).order(ByteOrder.LITTLE_ENDIAN);
+
+ assertWithMessage("Root element in buffer is not TYPE_OBJECT")
+ .that(buffer.get())
+ .isEqualTo(StatsEvent.TYPE_OBJECT);
+
+ assertWithMessage("Incorrect number of elements in root object")
+ .that(buffer.get())
+ .isEqualTo(3);
+
+ assertWithMessage("First element is not timestamp")
+ .that(buffer.get())
+ .isEqualTo(StatsEvent.TYPE_LONG);
+
+ assertWithMessage("Incorrect timestamp")
+ .that(buffer.getLong())
+ .isIn(Range.closed(minTimestamp, maxTimestamp));
+
+ assertWithMessage("Second element is not atom id")
+ .that(buffer.get())
+ .isEqualTo(StatsEvent.TYPE_INT);
+
+ assertWithMessage("Incorrect atom id").that(buffer.getInt()).isEqualTo(expectedAtomId);
+
+ assertWithMessage("Third element is not byte array")
+ .that(buffer.get())
+ .isEqualTo(StatsEvent.TYPE_BYTE_ARRAY);
+
+ final byte[] field1Actual = getByteArrayFromByteBuffer(buffer);
+ assertWithMessage("Incorrect field 1").that(field1Actual).isEqualTo(field1);
+
+ assertThat(statsEvent.getNumBytes()).isEqualTo(buffer.position());
+
+ statsEvent.release();
+ }
+
+ @Test
+ public void testPulledEventOverflow() {
+ final int expectedAtomId = 10_020;
+ byte[] field1 = new byte[50 * 1024];
+ new Random().nextBytes(field1);
+
+ final long minTimestamp = SystemClock.elapsedRealtimeNanos();
+ final StatsEvent statsEvent =
+ StatsEvent.newBuilder().setAtomId(expectedAtomId).writeByteArray(field1).build();
+ final long maxTimestamp = SystemClock.elapsedRealtimeNanos();
+
+ assertThat(statsEvent.getAtomId()).isEqualTo(expectedAtomId);
+
+ final ByteBuffer buffer =
+ ByteBuffer.wrap(statsEvent.getBytes()).order(ByteOrder.LITTLE_ENDIAN);
+
+ assertWithMessage("Root element in buffer is not TYPE_OBJECT")
+ .that(buffer.get())
+ .isEqualTo(StatsEvent.TYPE_OBJECT);
+
+ assertWithMessage("Incorrect number of elements in root object")
+ .that(buffer.get())
+ .isEqualTo(3);
+
+ assertWithMessage("First element is not timestamp")
+ .that(buffer.get())
+ .isEqualTo(StatsEvent.TYPE_LONG);
+
+ assertWithMessage("Incorrect timestamp")
+ .that(buffer.getLong())
+ .isIn(Range.closed(minTimestamp, maxTimestamp));
+
+ assertWithMessage("Second element is not atom id")
+ .that(buffer.get())
+ .isEqualTo(StatsEvent.TYPE_INT);
+
+ assertWithMessage("Incorrect atom id").that(buffer.getInt()).isEqualTo(expectedAtomId);
+
+ assertWithMessage("Third element is not errors type")
+ .that(buffer.get())
+ .isEqualTo(StatsEvent.TYPE_ERRORS);
+
+ final int errorMask = buffer.getInt();
+
+ assertWithMessage("ERROR_OVERFLOW should be the only error in the error mask")
+ .that(errorMask)
+ .isEqualTo(StatsEvent.ERROR_OVERFLOW);
+
+ assertThat(statsEvent.getNumBytes()).isEqualTo(buffer.position());
+
+ statsEvent.release();
+ }
+
+ @Test
+ public void testPushedEventOverflow() {
+ final int expectedAtomId = 10_020;
+ byte[] field1 = new byte[10 * 1024];
+ new Random().nextBytes(field1);
+
+ final long minTimestamp = SystemClock.elapsedRealtimeNanos();
+ final StatsEvent statsEvent = StatsEvent.newBuilder()
+ .setAtomId(expectedAtomId)
+ .writeByteArray(field1)
+ .usePooledBuffer()
+ .build();
+ final long maxTimestamp = SystemClock.elapsedRealtimeNanos();
+
+ assertThat(statsEvent.getAtomId()).isEqualTo(expectedAtomId);
+
+ final ByteBuffer buffer =
+ ByteBuffer.wrap(statsEvent.getBytes()).order(ByteOrder.LITTLE_ENDIAN);
+
+ assertWithMessage("Root element in buffer is not TYPE_OBJECT")
+ .that(buffer.get())
+ .isEqualTo(StatsEvent.TYPE_OBJECT);
+
+ assertWithMessage("Incorrect number of elements in root object")
+ .that(buffer.get())
+ .isEqualTo(3);
+
+ assertWithMessage("First element is not timestamp")
+ .that(buffer.get())
+ .isEqualTo(StatsEvent.TYPE_LONG);
+
+ assertWithMessage("Incorrect timestamp")
+ .that(buffer.getLong())
+ .isIn(Range.closed(minTimestamp, maxTimestamp));
+
+ assertWithMessage("Second element is not atom id")
+ .that(buffer.get())
+ .isEqualTo(StatsEvent.TYPE_INT);
+
+ assertWithMessage("Incorrect atom id").that(buffer.getInt()).isEqualTo(expectedAtomId);
+
+ assertWithMessage("Third element is not errors type")
+ .that(buffer.get())
+ .isEqualTo(StatsEvent.TYPE_ERRORS);
+
+ final int errorMask = buffer.getInt();
+
+ assertWithMessage("ERROR_OVERFLOW should be the only error in the error mask")
+ .that(errorMask)
+ .isEqualTo(StatsEvent.ERROR_OVERFLOW);
+
+ assertThat(statsEvent.getNumBytes()).isEqualTo(buffer.position());
+
+ statsEvent.release();
+ }
+
private static byte[] getByteArrayFromByteBuffer(final ByteBuffer buffer) {
final int numBytes = buffer.getInt();
byte[] bytes = new byte[numBytes];
diff --git a/api/test-current.txt b/api/test-current.txt
index ed4c9b13dacd..1142fb631891 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -193,6 +193,7 @@ package android.app {
method public static int opToDefaultMode(@NonNull String);
method public static String opToPermission(int);
method public static int permissionToOpCode(String);
+ method @RequiresPermission("android.permission.MANAGE_APPOPS") public void rebootHistory(long);
method @RequiresPermission("android.permission.MANAGE_APPOPS") public void reloadNonHistoricalState();
method @RequiresPermission("android.permission.MANAGE_APPOPS") public void resetHistoryParameters();
method @RequiresPermission("android.permission.MANAGE_APPOPS") public void setHistoryParameters(int, long, int);
@@ -1298,6 +1299,130 @@ package android.hardware.display {
}
+package android.hardware.hdmi {
+
+ public final class HdmiControlManager {
+ method @Nullable public android.hardware.hdmi.HdmiSwitchClient getSwitchClient();
+ method @RequiresPermission("android.permission.HDMI_CEC") public void setStandbyMode(boolean);
+ field public static final String ACTION_OSD_MESSAGE = "android.hardware.hdmi.action.OSD_MESSAGE";
+ field public static final int AVR_VOLUME_MUTED = 101; // 0x65
+ field public static final int CLEAR_TIMER_STATUS_CEC_DISABLE = 162; // 0xa2
+ field public static final int CLEAR_TIMER_STATUS_CHECK_RECORDER_CONNECTION = 160; // 0xa0
+ field public static final int CLEAR_TIMER_STATUS_FAIL_TO_CLEAR_SELECTED_SOURCE = 161; // 0xa1
+ field public static final int CLEAR_TIMER_STATUS_TIMER_CLEARED = 128; // 0x80
+ field public static final int CLEAR_TIMER_STATUS_TIMER_NOT_CLEARED_NO_INFO_AVAILABLE = 2; // 0x2
+ field public static final int CLEAR_TIMER_STATUS_TIMER_NOT_CLEARED_NO_MATCHING = 1; // 0x1
+ field public static final int CLEAR_TIMER_STATUS_TIMER_NOT_CLEARED_RECORDING = 0; // 0x0
+ field public static final int CONTROL_STATE_CHANGED_REASON_SETTING = 1; // 0x1
+ field public static final int CONTROL_STATE_CHANGED_REASON_STANDBY = 3; // 0x3
+ field public static final int CONTROL_STATE_CHANGED_REASON_START = 0; // 0x0
+ field public static final int CONTROL_STATE_CHANGED_REASON_WAKEUP = 2; // 0x2
+ field public static final int DEVICE_EVENT_ADD_DEVICE = 1; // 0x1
+ field public static final int DEVICE_EVENT_REMOVE_DEVICE = 2; // 0x2
+ field public static final int DEVICE_EVENT_UPDATE_DEVICE = 3; // 0x3
+ field public static final String EXTRA_MESSAGE_EXTRA_PARAM1 = "android.hardware.hdmi.extra.MESSAGE_EXTRA_PARAM1";
+ field public static final String EXTRA_MESSAGE_ID = "android.hardware.hdmi.extra.MESSAGE_ID";
+ field public static final int ONE_TOUCH_RECORD_ALREADY_RECORDING = 18; // 0x12
+ field public static final int ONE_TOUCH_RECORD_CEC_DISABLED = 51; // 0x33
+ field public static final int ONE_TOUCH_RECORD_CHECK_RECORDER_CONNECTION = 49; // 0x31
+ field public static final int ONE_TOUCH_RECORD_DISALLOW_TO_COPY = 13; // 0xd
+ field public static final int ONE_TOUCH_RECORD_DISALLOW_TO_FUTHER_COPIES = 14; // 0xe
+ field public static final int ONE_TOUCH_RECORD_FAIL_TO_RECORD_DISPLAYED_SCREEN = 50; // 0x32
+ field public static final int ONE_TOUCH_RECORD_INVALID_EXTERNAL_PHYSICAL_ADDRESS = 10; // 0xa
+ field public static final int ONE_TOUCH_RECORD_INVALID_EXTERNAL_PLUG_NUMBER = 9; // 0x9
+ field public static final int ONE_TOUCH_RECORD_MEDIA_PROBLEM = 21; // 0x15
+ field public static final int ONE_TOUCH_RECORD_MEDIA_PROTECTED = 19; // 0x13
+ field public static final int ONE_TOUCH_RECORD_NOT_ENOUGH_SPACE = 22; // 0x16
+ field public static final int ONE_TOUCH_RECORD_NO_MEDIA = 16; // 0x10
+ field public static final int ONE_TOUCH_RECORD_NO_OR_INSUFFICIENT_CA_ENTITLEMENTS = 12; // 0xc
+ field public static final int ONE_TOUCH_RECORD_NO_SOURCE_SIGNAL = 20; // 0x14
+ field public static final int ONE_TOUCH_RECORD_OTHER_REASON = 31; // 0x1f
+ field public static final int ONE_TOUCH_RECORD_PARENT_LOCK_ON = 23; // 0x17
+ field public static final int ONE_TOUCH_RECORD_PLAYING = 17; // 0x11
+ field public static final int ONE_TOUCH_RECORD_PREVIOUS_RECORDING_IN_PROGRESS = 48; // 0x30
+ field public static final int ONE_TOUCH_RECORD_RECORDING_ALREADY_TERMINATED = 27; // 0x1b
+ field public static final int ONE_TOUCH_RECORD_RECORDING_ANALOGUE_SERVICE = 3; // 0x3
+ field public static final int ONE_TOUCH_RECORD_RECORDING_CURRENTLY_SELECTED_SOURCE = 1; // 0x1
+ field public static final int ONE_TOUCH_RECORD_RECORDING_DIGITAL_SERVICE = 2; // 0x2
+ field public static final int ONE_TOUCH_RECORD_RECORDING_EXTERNAL_INPUT = 4; // 0x4
+ field public static final int ONE_TOUCH_RECORD_RECORDING_TERMINATED_NORMALLY = 26; // 0x1a
+ field public static final int ONE_TOUCH_RECORD_UNABLE_ANALOGUE_SERVICE = 6; // 0x6
+ field public static final int ONE_TOUCH_RECORD_UNABLE_DIGITAL_SERVICE = 5; // 0x5
+ field public static final int ONE_TOUCH_RECORD_UNABLE_SELECTED_SERVICE = 7; // 0x7
+ field public static final int ONE_TOUCH_RECORD_UNSUPPORTED_CA = 11; // 0xb
+ field public static final int OSD_MESSAGE_ARC_CONNECTED_INVALID_PORT = 1; // 0x1
+ field public static final int OSD_MESSAGE_AVR_VOLUME_CHANGED = 2; // 0x2
+ field public static final int POWER_STATUS_ON = 0; // 0x0
+ field public static final int POWER_STATUS_STANDBY = 1; // 0x1
+ field public static final int POWER_STATUS_TRANSIENT_TO_ON = 2; // 0x2
+ field public static final int POWER_STATUS_TRANSIENT_TO_STANDBY = 3; // 0x3
+ field public static final int POWER_STATUS_UNKNOWN = -1; // 0xffffffff
+ field @Deprecated public static final int RESULT_ALREADY_IN_PROGRESS = 4; // 0x4
+ field public static final int RESULT_COMMUNICATION_FAILED = 7; // 0x7
+ field public static final int RESULT_EXCEPTION = 5; // 0x5
+ field public static final int RESULT_INCORRECT_MODE = 6; // 0x6
+ field public static final int RESULT_SOURCE_NOT_AVAILABLE = 2; // 0x2
+ field public static final int RESULT_SUCCESS = 0; // 0x0
+ field public static final int RESULT_TARGET_NOT_AVAILABLE = 3; // 0x3
+ field public static final int RESULT_TIMEOUT = 1; // 0x1
+ field public static final int TIMER_RECORDING_RESULT_EXTRA_CEC_DISABLED = 3; // 0x3
+ field public static final int TIMER_RECORDING_RESULT_EXTRA_CHECK_RECORDER_CONNECTION = 1; // 0x1
+ field public static final int TIMER_RECORDING_RESULT_EXTRA_FAIL_TO_RECORD_SELECTED_SOURCE = 2; // 0x2
+ field public static final int TIMER_RECORDING_RESULT_EXTRA_NO_ERROR = 0; // 0x0
+ field public static final int TIMER_RECORDING_TYPE_ANALOGUE = 2; // 0x2
+ field public static final int TIMER_RECORDING_TYPE_DIGITAL = 1; // 0x1
+ field public static final int TIMER_RECORDING_TYPE_EXTERNAL = 3; // 0x3
+ field public static final int TIMER_STATUS_MEDIA_INFO_NOT_PRESENT = 2; // 0x2
+ field public static final int TIMER_STATUS_MEDIA_INFO_PRESENT_NOT_PROTECTED = 0; // 0x0
+ field public static final int TIMER_STATUS_MEDIA_INFO_PRESENT_PROTECTED = 1; // 0x1
+ field public static final int TIMER_STATUS_NOT_PROGRAMMED_CA_NOT_SUPPORTED = 6; // 0x6
+ field public static final int TIMER_STATUS_NOT_PROGRAMMED_CLOCK_FAILURE = 10; // 0xa
+ field public static final int TIMER_STATUS_NOT_PROGRAMMED_DATE_OUT_OF_RANGE = 2; // 0x2
+ field public static final int TIMER_STATUS_NOT_PROGRAMMED_DUPLICATED = 14; // 0xe
+ field public static final int TIMER_STATUS_NOT_PROGRAMMED_INVALID_EXTERNAL_PHYSICAL_NUMBER = 5; // 0x5
+ field public static final int TIMER_STATUS_NOT_PROGRAMMED_INVALID_EXTERNAL_PLUG_NUMBER = 4; // 0x4
+ field public static final int TIMER_STATUS_NOT_PROGRAMMED_INVALID_SEQUENCE = 3; // 0x3
+ field public static final int TIMER_STATUS_NOT_PROGRAMMED_NO_CA_ENTITLEMENTS = 7; // 0x7
+ field public static final int TIMER_STATUS_NOT_PROGRAMMED_NO_FREE_TIME = 1; // 0x1
+ field public static final int TIMER_STATUS_NOT_PROGRAMMED_PARENTAL_LOCK_ON = 9; // 0x9
+ field public static final int TIMER_STATUS_NOT_PROGRAMMED_UNSUPPORTED_RESOLUTION = 8; // 0x8
+ field public static final int TIMER_STATUS_PROGRAMMED_INFO_ENOUGH_SPACE = 8; // 0x8
+ field public static final int TIMER_STATUS_PROGRAMMED_INFO_MIGHT_NOT_ENOUGH_SPACE = 11; // 0xb
+ field public static final int TIMER_STATUS_PROGRAMMED_INFO_NOT_ENOUGH_SPACE = 9; // 0x9
+ field public static final int TIMER_STATUS_PROGRAMMED_INFO_NO_MEDIA_INFO = 10; // 0xa
+ }
+
+ public final class HdmiControlServiceWrapper {
+ ctor public HdmiControlServiceWrapper();
+ method @NonNull public android.hardware.hdmi.HdmiControlManager createHdmiControlManager();
+ method @BinderThread public void setDeviceTypes(@NonNull int[]);
+ method @BinderThread public void setPortInfo(@NonNull java.util.List<android.hardware.hdmi.HdmiPortInfo>);
+ field public static final int DEVICE_PURE_CEC_SWITCH = 6; // 0x6
+ }
+
+ public final class HdmiPortInfo implements android.os.Parcelable {
+ ctor public HdmiPortInfo(int, int, int, boolean, boolean, boolean);
+ method public int describeContents();
+ method public int getAddress();
+ method public int getId();
+ method public int getType();
+ method public boolean isArcSupported();
+ method public boolean isCecSupported();
+ method public boolean isMhlSupported();
+ field @NonNull public static final android.os.Parcelable.Creator<android.hardware.hdmi.HdmiPortInfo> CREATOR;
+ field public static final int PORT_INPUT = 0; // 0x0
+ field public static final int PORT_OUTPUT = 1; // 0x1
+ }
+
+ public class HdmiSwitchClient {
+ method public int getDeviceType();
+ method @NonNull public java.util.List<android.hardware.hdmi.HdmiPortInfo> getPortInfo();
+ method public void sendKeyEvent(int, boolean);
+ method public void sendVendorCommand(int, byte[], boolean);
+ }
+
+}
+
package android.hardware.lights {
public final class Light implements android.os.Parcelable {
diff --git a/cmds/bootanimation/BootAnimation.cpp b/cmds/bootanimation/BootAnimation.cpp
index 3bcabe56f89e..bb2de17b42f3 100644
--- a/cmds/bootanimation/BootAnimation.cpp
+++ b/cmds/bootanimation/BootAnimation.cpp
@@ -349,6 +349,25 @@ EGLConfig BootAnimation::getEglConfig(const EGLDisplay& display) {
return config;
}
+ui::Size BootAnimation::limitSurfaceSize(int width, int height) const {
+ ui::Size limited(width, height);
+ bool wasLimited = false;
+ const float aspectRatio = float(width) / float(height);
+ if (mMaxWidth != 0 && width > mMaxWidth) {
+ limited.height = mMaxWidth / aspectRatio;
+ limited.width = mMaxWidth;
+ wasLimited = true;
+ }
+ if (mMaxHeight != 0 && limited.height > mMaxHeight) {
+ limited.height = mMaxHeight;
+ limited.width = mMaxHeight * aspectRatio;
+ wasLimited = true;
+ }
+ SLOGV_IF(wasLimited, "Surface size has been limited to [%dx%d] from [%dx%d]",
+ limited.width, limited.height, width, height);
+ return limited;
+}
+
status_t BootAnimation::readyToRun() {
mAssets.addDefaultAssets();
@@ -362,8 +381,10 @@ status_t BootAnimation::readyToRun() {
if (error != NO_ERROR)
return error;
- const ui::Size& resolution = displayConfig.resolution;
-
+ mMaxWidth = android::base::GetIntProperty("ro.surface_flinger.max_graphics_width", 0);
+ mMaxHeight = android::base::GetIntProperty("ro.surface_flinger.max_graphics_height", 0);
+ ui::Size resolution = displayConfig.resolution;
+ resolution = limitSurfaceSize(resolution.width, resolution.height);
// create the native surface
sp<SurfaceControl> control = session()->createSurface(String8("BootAnimation"),
resolution.getWidth(), resolution.getHeight(), PIXEL_FORMAT_RGB_565);
@@ -459,8 +480,9 @@ void BootAnimation::resizeSurface(int newWidth, int newHeight) {
eglMakeCurrent(mDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
eglDestroySurface(mDisplay, mSurface);
- mWidth = newWidth;
- mHeight = newHeight;
+ const auto limitedSize = limitSurfaceSize(newWidth, newHeight);
+ mWidth = limitedSize.width;
+ mHeight = limitedSize.height;
SurfaceComposerClient::Transaction t;
t.setSize(mFlingerSurfaceControl, mWidth, mHeight);
diff --git a/cmds/bootanimation/BootAnimation.h b/cmds/bootanimation/BootAnimation.h
index 36cd91bdee0d..6ba7fd450fbb 100644
--- a/cmds/bootanimation/BootAnimation.h
+++ b/cmds/bootanimation/BootAnimation.h
@@ -170,6 +170,7 @@ private:
bool findBootAnimationFileInternal(const std::vector<std::string>& files);
bool preloadAnimation();
EGLConfig getEglConfig(const EGLDisplay&);
+ ui::Size limitSurfaceSize(int width, int height) const;
void resizeSurface(int newWidth, int newHeight);
void checkExit();
@@ -181,6 +182,8 @@ private:
Texture mAndroid[2];
int mWidth;
int mHeight;
+ int mMaxWidth = 0;
+ int mMaxHeight = 0;
int mCurrentInset;
int mTargetInset;
bool mUseNpotTextures = false;
diff --git a/cmds/idmap2/Android.bp b/cmds/idmap2/Android.bp
index ef5c4cec9166..fb5830506925 100644
--- a/cmds/idmap2/Android.bp
+++ b/cmds/idmap2/Android.bp
@@ -168,13 +168,13 @@ cc_binary {
],
host_supported: true,
srcs: [
+ "idmap2/CommandUtils.cpp",
"idmap2/Create.cpp",
"idmap2/CreateMultiple.cpp",
"idmap2/Dump.cpp",
"idmap2/Lookup.cpp",
"idmap2/Main.cpp",
"idmap2/Scan.cpp",
- "idmap2/Verify.cpp",
],
target: {
android: {
diff --git a/cmds/idmap2/idmap2/Verify.cpp b/cmds/idmap2/idmap2/CommandUtils.cpp
index 9cb67b33e6cf..8f5845bf2e53 100644
--- a/cmds/idmap2/idmap2/Verify.cpp
+++ b/cmds/idmap2/idmap2/CommandUtils.cpp
@@ -19,30 +19,19 @@
#include <string>
#include <vector>
-#include "idmap2/CommandLineOptions.h"
#include "idmap2/Idmap.h"
#include "idmap2/Result.h"
#include "idmap2/SysTrace.h"
-using android::idmap2::CommandLineOptions;
using android::idmap2::Error;
using android::idmap2::IdmapHeader;
using android::idmap2::Result;
using android::idmap2::Unit;
-Result<Unit> Verify(const std::vector<std::string>& args) {
- SYSTRACE << "Verify " << args;
- std::string idmap_path;
-
- const CommandLineOptions opts =
- CommandLineOptions("idmap2 verify")
- .MandatoryOption("--idmap-path", "input: path to idmap file to verify", &idmap_path);
-
- const auto opts_ok = opts.Parse(args);
- if (!opts_ok) {
- return opts_ok.GetError();
- }
-
+Result<Unit> Verify(const std::string& idmap_path, const std::string& target_path,
+ const std::string& overlay_path, PolicyBitmask fulfilled_policies,
+ bool enforce_overlayable) {
+ SYSTRACE << "Verify " << idmap_path;
std::ifstream fin(idmap_path);
const std::unique_ptr<const IdmapHeader> header = IdmapHeader::FromBinaryStream(fin);
fin.close();
@@ -50,7 +39,8 @@ Result<Unit> Verify(const std::vector<std::string>& args) {
return Error("failed to parse idmap header");
}
- const auto header_ok = header->IsUpToDate();
+ const auto header_ok = header->IsUpToDate(target_path.c_str(), overlay_path.c_str(),
+ fulfilled_policies, enforce_overlayable);
if (!header_ok) {
return Error(header_ok.GetError(), "idmap not up to date");
}
diff --git a/cmds/idmap2/idmap2/CommandUtils.h b/cmds/idmap2/idmap2/CommandUtils.h
new file mode 100644
index 000000000000..e717e046d15d
--- /dev/null
+++ b/cmds/idmap2/idmap2/CommandUtils.h
@@ -0,0 +1,29 @@
+/*
+ * 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.
+ */
+
+#ifndef IDMAP2_IDMAP2_COMMAND_UTILS_H_
+#define IDMAP2_IDMAP2_COMMAND_UTILS_H_
+
+#include "idmap2/PolicyUtils.h"
+#include "idmap2/Result.h"
+
+android::idmap2::Result<android::idmap2::Unit> Verify(const std::string& idmap_path,
+ const std::string& target_path,
+ const std::string& overlay_path,
+ PolicyBitmask fulfilled_policies,
+ bool enforce_overlayable);
+
+#endif // IDMAP2_IDMAP2_COMMAND_UTILS_H_
diff --git a/cmds/idmap2/idmap2/Commands.h b/cmds/idmap2/idmap2/Commands.h
index e626738a2895..69eea8d262d2 100644
--- a/cmds/idmap2/idmap2/Commands.h
+++ b/cmds/idmap2/idmap2/Commands.h
@@ -27,6 +27,5 @@ android::idmap2::Result<android::idmap2::Unit> CreateMultiple(const std::vector<
android::idmap2::Result<android::idmap2::Unit> Dump(const std::vector<std::string>& args);
android::idmap2::Result<android::idmap2::Unit> Lookup(const std::vector<std::string>& args);
android::idmap2::Result<android::idmap2::Unit> Scan(const std::vector<std::string>& args);
-android::idmap2::Result<android::idmap2::Unit> Verify(const std::vector<std::string>& args);
#endif // IDMAP2_IDMAP2_COMMANDS_H_
diff --git a/cmds/idmap2/idmap2/CreateMultiple.cpp b/cmds/idmap2/idmap2/CreateMultiple.cpp
index 4b70acc2969c..abdfaf4dccab 100644
--- a/cmds/idmap2/idmap2/CreateMultiple.cpp
+++ b/cmds/idmap2/idmap2/CreateMultiple.cpp
@@ -26,6 +26,7 @@
#include "android-base/stringprintf.h"
#include "idmap2/BinaryStreamVisitor.h"
#include "idmap2/CommandLineOptions.h"
+#include "idmap2/CommandUtils.h"
#include "idmap2/FileUtils.h"
#include "idmap2/Idmap.h"
#include "idmap2/Policies.h"
@@ -103,7 +104,8 @@ Result<Unit> CreateMultiple(const std::vector<std::string>& args) {
continue;
}
- if (!Verify(std::vector<std::string>({"--idmap-path", idmap_path}))) {
+ if (!Verify(idmap_path, target_apk_path, overlay_apk_path, fulfilled_policies,
+ !ignore_overlayable)) {
const std::unique_ptr<const ApkAssets> overlay_apk = ApkAssets::Load(overlay_apk_path);
if (!overlay_apk) {
LOG(WARNING) << "failed to load apk " << overlay_apk_path.c_str();
diff --git a/cmds/idmap2/idmap2/Main.cpp b/cmds/idmap2/idmap2/Main.cpp
index a07e793d9f47..fb093f0f22a4 100644
--- a/cmds/idmap2/idmap2/Main.cpp
+++ b/cmds/idmap2/idmap2/Main.cpp
@@ -53,9 +53,8 @@ void PrintUsage(const NameToFunctionMap& commands, std::ostream& out) {
int main(int argc, char** argv) {
SYSTRACE << "main";
const NameToFunctionMap commands = {
- {"create", Create}, {"create-multiple", CreateMultiple},
- {"dump", Dump}, {"lookup", Lookup},
- {"scan", Scan}, {"verify", Verify},
+ {"create", Create}, {"create-multiple", CreateMultiple}, {"dump", Dump}, {"lookup", Lookup},
+ {"scan", Scan},
};
if (argc <= 1) {
PrintUsage(commands, std::cerr);
diff --git a/cmds/idmap2/idmap2/Scan.cpp b/cmds/idmap2/idmap2/Scan.cpp
index da0453216f03..36250450cc74 100644
--- a/cmds/idmap2/idmap2/Scan.cpp
+++ b/cmds/idmap2/idmap2/Scan.cpp
@@ -27,8 +27,11 @@
#include "Commands.h"
#include "android-base/properties.h"
#include "idmap2/CommandLineOptions.h"
+#include "idmap2/CommandUtils.h"
#include "idmap2/FileUtils.h"
#include "idmap2/Idmap.h"
+#include "idmap2/Policies.h"
+#include "idmap2/PolicyUtils.h"
#include "idmap2/ResourceUtils.h"
#include "idmap2/Result.h"
#include "idmap2/SysTrace.h"
@@ -48,6 +51,7 @@ using android::idmap2::policy::kPolicyVendor;
using android::idmap2::utils::ExtractOverlayManifestInfo;
using android::idmap2::utils::FindFiles;
using android::idmap2::utils::OverlayManifestInfo;
+using android::idmap2::utils::PoliciesToBitmaskResult;
using PolicyBitmask = android::ResTable_overlayable_policy_header::PolicyBitmask;
@@ -215,7 +219,15 @@ Result<Unit> Scan(const std::vector<std::string>& args) {
std::stringstream stream;
for (const auto& overlay : interesting_apks) {
- if (!Verify(std::vector<std::string>({"--idmap-path", overlay.idmap_path}))) {
+ const auto policy_bitmask = PoliciesToBitmaskResult(overlay.policies);
+ if (!policy_bitmask) {
+ LOG(WARNING) << "failed to create idmap for overlay apk path \"" << overlay.apk_path
+ << "\": " << policy_bitmask.GetErrorMessage();
+ continue;
+ }
+
+ if (!Verify(overlay.idmap_path, target_apk_path, overlay.apk_path, *policy_bitmask,
+ !overlay.ignore_overlayable)) {
std::vector<std::string> create_args = {"--target-apk-path", target_apk_path,
"--overlay-apk-path", overlay.apk_path,
"--idmap-path", overlay.idmap_path};
diff --git a/cmds/idmap2/idmap2d/Idmap2Service.cpp b/cmds/idmap2/idmap2d/Idmap2Service.cpp
index a93184ff4787..f95b73f17222 100644
--- a/cmds/idmap2/idmap2d/Idmap2Service.cpp
+++ b/cmds/idmap2/idmap2d/Idmap2Service.cpp
@@ -33,16 +33,19 @@
#include "idmap2/BinaryStreamVisitor.h"
#include "idmap2/FileUtils.h"
#include "idmap2/Idmap.h"
+#include "idmap2/Result.h"
#include "idmap2/SysTrace.h"
#include "idmap2/ZipFile.h"
#include "utils/String8.h"
using android::IPCThreadState;
+using android::base::StringPrintf;
using android::binder::Status;
using android::idmap2::BinaryStreamVisitor;
using android::idmap2::GetPackageCrc;
using android::idmap2::Idmap;
using android::idmap2::IdmapHeader;
+using android::idmap2::ZipFile;
using android::idmap2::utils::kIdmapCacheDir;
using android::idmap2::utils::kIdmapFilePermissionMask;
using android::idmap2::utils::UidHasWriteAccessToPath;
@@ -66,6 +69,21 @@ PolicyBitmask ConvertAidlArgToPolicyBitmask(int32_t arg) {
return static_cast<PolicyBitmask>(arg);
}
+Status GetCrc(const std::string& apk_path, uint32_t* out_crc) {
+ const auto zip = ZipFile::Open(apk_path);
+ if (!zip) {
+ return error(StringPrintf("failed to open apk %s", apk_path.c_str()));
+ }
+
+ const auto crc = GetPackageCrc(*zip);
+ if (!crc) {
+ return error(crc.GetErrorMessage());
+ }
+
+ *out_crc = *crc;
+ return ok();
+}
+
} // namespace
namespace android::os {
@@ -98,12 +116,12 @@ Status Idmap2Service::removeIdmap(const std::string& overlay_apk_path,
}
Status Idmap2Service::verifyIdmap(const std::string& target_apk_path,
- const std::string& overlay_apk_path,
- int32_t fulfilled_policies ATTRIBUTE_UNUSED,
- bool enforce_overlayable ATTRIBUTE_UNUSED,
- int32_t user_id ATTRIBUTE_UNUSED, bool* _aidl_return) {
+ const std::string& overlay_apk_path, int32_t fulfilled_policies,
+ bool enforce_overlayable, int32_t user_id ATTRIBUTE_UNUSED,
+ bool* _aidl_return) {
SYSTRACE << "Idmap2Service::verifyIdmap " << overlay_apk_path;
assert(_aidl_return);
+
const std::string idmap_path = Idmap::CanonicalIdmapPathFor(kIdmapCacheDir, overlay_apk_path);
std::ifstream fin(idmap_path);
const std::unique_ptr<const IdmapHeader> header = IdmapHeader::FromBinaryStream(fin);
@@ -113,35 +131,36 @@ Status Idmap2Service::verifyIdmap(const std::string& target_apk_path,
return error("failed to parse idmap header");
}
- if (strcmp(header->GetTargetPath().data(), target_apk_path.data()) != 0) {
- *_aidl_return = false;
- return ok();
- }
-
- if (target_apk_path != kFrameworkPath) {
- *_aidl_return = (bool) header->IsUpToDate();
+ uint32_t target_crc;
+ if (target_apk_path == kFrameworkPath && android_crc_) {
+ target_crc = *android_crc_;
} else {
- if (!android_crc_) {
- // Loading the framework zip can take several milliseconds. Cache the crc of the framework
- // resource APK to reduce repeated work during boot.
- const auto target_zip = idmap2::ZipFile::Open(target_apk_path);
- if (!target_zip) {
- return error(base::StringPrintf("failed to open target %s", target_apk_path.c_str()));
- }
-
- const auto target_crc = GetPackageCrc(*target_zip);
- if (!target_crc) {
- return error(target_crc.GetErrorMessage());
- }
-
- android_crc_ = *target_crc;
+ auto target_crc_status = GetCrc(target_apk_path, &target_crc);
+ if (!target_crc_status.isOk()) {
+ *_aidl_return = false;
+ return target_crc_status;
+ }
+
+ // Loading the framework zip can take several milliseconds. Cache the crc of the framework
+ // resource APK to reduce repeated work during boot.
+ if (target_apk_path == kFrameworkPath) {
+ android_crc_ = target_crc;
}
+ }
- *_aidl_return = (bool) header->IsUpToDate(android_crc_.value());
+ uint32_t overlay_crc;
+ auto overlay_crc_status = GetCrc(overlay_apk_path, &overlay_crc);
+ if (!overlay_crc_status.isOk()) {
+ *_aidl_return = false;
+ return overlay_crc_status;
}
- // TODO(b/119328308): Check that the set of fulfilled policies of the overlay has not changed
- return ok();
+ auto up_to_date =
+ header->IsUpToDate(target_apk_path.c_str(), overlay_apk_path.c_str(), target_crc, overlay_crc,
+ ConvertAidlArgToPolicyBitmask(fulfilled_policies), enforce_overlayable);
+
+ *_aidl_return = static_cast<bool>(up_to_date);
+ return *_aidl_return ? ok() : error(up_to_date.GetErrorMessage());
}
Status Idmap2Service::createIdmap(const std::string& target_apk_path,
diff --git a/cmds/idmap2/include/idmap2/Idmap.h b/cmds/idmap2/include/idmap2/Idmap.h
index 77a7b30a230e..0f05592b70f3 100644
--- a/cmds/idmap2/include/idmap2/Idmap.h
+++ b/cmds/idmap2/include/idmap2/Idmap.h
@@ -117,6 +117,14 @@ class IdmapHeader {
return overlay_crc_;
}
+ inline uint32_t GetFulfilledPolicies() const {
+ return fulfilled_policies_;
+ }
+
+ bool GetEnforceOverlayable() const {
+ return enforce_overlayable_;
+ }
+
inline StringPiece GetTargetPath() const {
return StringPiece(target_path_);
}
@@ -132,8 +140,11 @@ class IdmapHeader {
// Invariant: anytime the idmap data encoding is changed, the idmap version
// field *must* be incremented. Because of this, we know that if the idmap
// header is up-to-date the entire file is up-to-date.
- Result<Unit> IsUpToDate() const;
- Result<Unit> IsUpToDate(uint32_t target_crc_) const;
+ Result<Unit> IsUpToDate(const char* target_path, const char* overlay_path,
+ PolicyBitmask fulfilled_policies, bool enforce_overlayable) const;
+ Result<Unit> IsUpToDate(const char* target_path, const char* overlay_path, uint32_t target_crc,
+ uint32_t overlay_crc, PolicyBitmask fulfilled_policies,
+ bool enforce_overlayable) const;
void accept(Visitor* v) const;
@@ -145,6 +156,8 @@ class IdmapHeader {
uint32_t version_;
uint32_t target_crc_;
uint32_t overlay_crc_;
+ uint32_t fulfilled_policies_;
+ bool enforce_overlayable_;
char target_path_[kIdmapStringLength];
char overlay_path_[kIdmapStringLength];
std::string debug_info_;
diff --git a/cmds/idmap2/libidmap2/BinaryStreamVisitor.cpp b/cmds/idmap2/libidmap2/BinaryStreamVisitor.cpp
index 362dcb36007a..255212ad4c66 100644
--- a/cmds/idmap2/libidmap2/BinaryStreamVisitor.cpp
+++ b/cmds/idmap2/libidmap2/BinaryStreamVisitor.cpp
@@ -66,6 +66,8 @@ void BinaryStreamVisitor::visit(const IdmapHeader& header) {
Write32(header.GetVersion());
Write32(header.GetTargetCrc());
Write32(header.GetOverlayCrc());
+ Write32(header.GetFulfilledPolicies());
+ Write8(static_cast<uint8_t>(header.GetEnforceOverlayable()));
WriteString256(header.GetTargetPath());
WriteString256(header.GetOverlayPath());
WriteString(header.GetDebugInfo());
diff --git a/cmds/idmap2/libidmap2/Idmap.cpp b/cmds/idmap2/libidmap2/Idmap.cpp
index 706b842b3b47..23c25a7089de 100644
--- a/cmds/idmap2/libidmap2/Idmap.cpp
+++ b/cmds/idmap2/libidmap2/Idmap.cpp
@@ -112,14 +112,17 @@ Result<uint32_t> GetPackageCrc(const ZipFile& zip) {
std::unique_ptr<const IdmapHeader> IdmapHeader::FromBinaryStream(std::istream& stream) {
std::unique_ptr<IdmapHeader> idmap_header(new IdmapHeader());
-
+ uint8_t enforce_overlayable;
if (!Read32(stream, &idmap_header->magic_) || !Read32(stream, &idmap_header->version_) ||
!Read32(stream, &idmap_header->target_crc_) || !Read32(stream, &idmap_header->overlay_crc_) ||
+ !Read32(stream, &idmap_header->fulfilled_policies_) || !Read8(stream, &enforce_overlayable) ||
!ReadString256(stream, idmap_header->target_path_) ||
!ReadString256(stream, idmap_header->overlay_path_)) {
return nullptr;
}
+ idmap_header->enforce_overlayable_ = static_cast<bool>(enforce_overlayable);
+
auto debug_str = ReadString(stream);
if (!debug_str) {
return nullptr;
@@ -129,21 +132,37 @@ std::unique_ptr<const IdmapHeader> IdmapHeader::FromBinaryStream(std::istream& s
return std::move(idmap_header);
}
-Result<Unit> IdmapHeader::IsUpToDate() const {
- const std::unique_ptr<const ZipFile> target_zip = ZipFile::Open(target_path_);
+Result<Unit> IdmapHeader::IsUpToDate(const char* target_path, const char* overlay_path,
+ PolicyBitmask fulfilled_policies,
+ bool enforce_overlayable) const {
+ const std::unique_ptr<const ZipFile> target_zip = ZipFile::Open(target_path);
if (!target_zip) {
- return Error("failed to open target %s", GetTargetPath().to_string().c_str());
+ return Error("failed to open target %s", target_path);
}
- Result<uint32_t> target_crc = GetPackageCrc(*target_zip);
+ const Result<uint32_t> target_crc = GetPackageCrc(*target_zip);
if (!target_crc) {
return Error("failed to get target crc");
}
- return IsUpToDate(*target_crc);
+ const std::unique_ptr<const ZipFile> overlay_zip = ZipFile::Open(overlay_path);
+ if (!overlay_zip) {
+ return Error("failed to overlay target %s", overlay_path);
+ }
+
+ const Result<uint32_t> overlay_crc = GetPackageCrc(*overlay_zip);
+ if (!overlay_crc) {
+ return Error("failed to get overlay crc");
+ }
+
+ return IsUpToDate(target_path, overlay_path, *target_crc, *overlay_crc, fulfilled_policies,
+ enforce_overlayable);
}
-Result<Unit> IdmapHeader::IsUpToDate(uint32_t target_crc) const {
+Result<Unit> IdmapHeader::IsUpToDate(const char* target_path, const char* overlay_path,
+ uint32_t target_crc, uint32_t overlay_crc,
+ PolicyBitmask fulfilled_policies,
+ bool enforce_overlayable) const {
if (magic_ != kIdmapMagic) {
return Error("bad magic: actual 0x%08x, expected 0x%08x", magic_, kIdmapMagic);
}
@@ -157,19 +176,29 @@ Result<Unit> IdmapHeader::IsUpToDate(uint32_t target_crc) const {
target_crc);
}
- const std::unique_ptr<const ZipFile> overlay_zip = ZipFile::Open(overlay_path_);
- if (!overlay_zip) {
- return Error("failed to open overlay %s", GetOverlayPath().to_string().c_str());
+ if (overlay_crc_ != overlay_crc) {
+ return Error("bad overlay crc: idmap version 0x%08x, file system version 0x%08x", overlay_crc_,
+ overlay_crc);
}
- Result<uint32_t> overlay_crc = GetPackageCrc(*overlay_zip);
- if (!overlay_crc) {
- return Error("failed to get overlay crc");
+ if (fulfilled_policies_ != fulfilled_policies) {
+ return Error("bad fulfilled policies: idmap version 0x%08x, file system version 0x%08x",
+ fulfilled_policies, fulfilled_policies_);
}
- if (overlay_crc_ != *overlay_crc) {
- return Error("bad overlay crc: idmap version 0x%08x, file system version 0x%08x", overlay_crc_,
- *overlay_crc);
+ if (enforce_overlayable != enforce_overlayable_) {
+ return Error("bad enforce overlayable: idmap version %s, file system version %s",
+ enforce_overlayable ? "true" : "false", enforce_overlayable_ ? "true" : "false");
+ }
+
+ if (strcmp(target_path, target_path_) != 0) {
+ return Error("bad target path: idmap version %s, file system version %s", target_path,
+ target_path_);
+ }
+
+ if (strcmp(overlay_path, overlay_path_) != 0) {
+ return Error("bad overlay path: idmap version %s, file system version %s", overlay_path,
+ overlay_path_);
}
return Unit{};
@@ -320,6 +349,9 @@ Result<std::unique_ptr<const Idmap>> Idmap::FromApkAssets(const ApkAssets& targe
}
header->overlay_crc_ = *crc;
+ header->fulfilled_policies_ = fulfilled_policies;
+ header->enforce_overlayable_ = enforce_overlayable;
+
if (target_apk_path.size() > sizeof(header->target_path_)) {
return Error("target apk path \"%s\" longer than maximum size %zu", target_apk_path.c_str(),
sizeof(header->target_path_));
diff --git a/cmds/idmap2/libidmap2/RawPrintVisitor.cpp b/cmds/idmap2/libidmap2/RawPrintVisitor.cpp
index 751c60c4add4..3f62a2ae2029 100644
--- a/cmds/idmap2/libidmap2/RawPrintVisitor.cpp
+++ b/cmds/idmap2/libidmap2/RawPrintVisitor.cpp
@@ -23,10 +23,12 @@
#include "android-base/macros.h"
#include "android-base/stringprintf.h"
#include "androidfw/ApkAssets.h"
+#include "idmap2/PolicyUtils.h"
#include "idmap2/ResourceUtils.h"
#include "idmap2/Result.h"
using android::ApkAssets;
+using android::idmap2::policy::PoliciesToDebugString;
namespace {
@@ -39,9 +41,6 @@ size_t StringSizeWhenEncoded(const std::string& s) {
namespace android::idmap2 {
-// verbatim copy fomr PrettyPrintVisitor.cpp, move to common utils
-#define RESID(pkg, type, entry) (((pkg) << 24) | ((type) << 16) | (entry))
-
void RawPrintVisitor::visit(const Idmap& idmap ATTRIBUTE_UNUSED) {
}
@@ -50,6 +49,9 @@ void RawPrintVisitor::visit(const IdmapHeader& header) {
print(header.GetVersion(), "version");
print(header.GetTargetCrc(), "target crc");
print(header.GetOverlayCrc(), "overlay crc");
+ print(header.GetFulfilledPolicies(), "fulfilled policies: %s",
+ PoliciesToDebugString(header.GetFulfilledPolicies()).c_str());
+ print(static_cast<uint8_t>(header.GetEnforceOverlayable()), "enforce overlayable");
print(header.GetTargetPath().to_string(), kIdmapStringLength, "target path");
print(header.GetOverlayPath().to_string(), kIdmapStringLength, "overlay path");
print("...", StringSizeWhenEncoded(header.GetDebugInfo()), "debug info");
diff --git a/cmds/idmap2/libidmap2/ResourceMapping.cpp b/cmds/idmap2/libidmap2/ResourceMapping.cpp
index 44acbcaf8ace..34589a1c39dc 100644
--- a/cmds/idmap2/libidmap2/ResourceMapping.cpp
+++ b/cmds/idmap2/libidmap2/ResourceMapping.cpp
@@ -61,8 +61,7 @@ Result<Unit> CheckOverlayable(const LoadedPackage& target_package,
const ResourceId& target_resource) {
static constexpr const PolicyBitmask sDefaultPolicies =
PolicyFlags::ODM_PARTITION | PolicyFlags::OEM_PARTITION | PolicyFlags::SYSTEM_PARTITION |
- PolicyFlags::VENDOR_PARTITION | PolicyFlags::PRODUCT_PARTITION | PolicyFlags::SIGNATURE |
- PolicyFlags::ACTOR_SIGNATURE;
+ PolicyFlags::VENDOR_PARTITION | PolicyFlags::PRODUCT_PARTITION | PolicyFlags::SIGNATURE;
// If the resource does not have an overlayable definition, allow the resource to be overlaid if
// the overlay is preinstalled or signed with the same signature as the target.
@@ -292,13 +291,6 @@ Result<ResourceMapping> ResourceMapping::FromApkAssets(const ApkAssets& target_a
const PolicyBitmask& fulfilled_policies,
bool enforce_overlayable,
LogInfo& log_info) {
- if (enforce_overlayable) {
- log_info.Info(LogMessage() << "fulfilled_policies="
- << ConcatPolicies(BitmaskToPolicies(fulfilled_policies))
- << " enforce_overlayable="
- << (enforce_overlayable ? "true" : "false"));
- }
-
AssetManager2 target_asset_manager;
if (!target_asset_manager.SetApkAssets({&target_apk_assets}, true /* invalidate_caches */,
false /* filter_incompatible_configs*/)) {
diff --git a/cmds/idmap2/libidmap2_policies/include/idmap2/Policies.h b/cmds/idmap2/libidmap2_policies/include/idmap2/Policies.h
index 4973b7638d10..5bd353af4ad3 100644
--- a/cmds/idmap2/libidmap2_policies/include/idmap2/Policies.h
+++ b/cmds/idmap2/libidmap2_policies/include/idmap2/Policies.h
@@ -21,9 +21,12 @@
#include <string>
#include <vector>
+#include "android-base/stringprintf.h"
#include "androidfw/ResourceTypes.h"
#include "androidfw/StringPiece.h"
+using android::base::StringPrintf;
+
using PolicyBitmask = android::ResTable_overlayable_policy_header::PolicyBitmask;
using PolicyFlags = android::ResTable_overlayable_policy_header::PolicyFlags;
@@ -48,6 +51,29 @@ inline static const std::array<std::pair<StringPiece, PolicyFlags>, 8> kPolicySt
{kPolicySystem, PolicyFlags::SYSTEM_PARTITION},
{kPolicyVendor, PolicyFlags::VENDOR_PARTITION},
};
+
+inline static std::string PoliciesToDebugString(PolicyBitmask policies) {
+ std::string str;
+ uint32_t remaining = policies;
+ for (auto const& policy : kPolicyStringToFlag) {
+ if ((policies & policy.second) != policy.second) {
+ continue;
+ }
+ if (!str.empty()) {
+ str.append("|");
+ }
+ str.append(policy.first.data());
+ remaining &= ~policy.second;
+ }
+ if (remaining != 0) {
+ if (!str.empty()) {
+ str.append("|");
+ }
+ str.append(StringPrintf("0x%08x", remaining));
+ }
+ return !str.empty() ? str : "none";
+}
+
} // namespace android::idmap2::policy
#endif // IDMAP2_INCLUDE_IDMAP2_POLICIES_H_
diff --git a/cmds/idmap2/tests/BinaryStreamVisitorTests.cpp b/cmds/idmap2/tests/BinaryStreamVisitorTests.cpp
index db4778c8ee09..5fea7bcdaac5 100644
--- a/cmds/idmap2/tests/BinaryStreamVisitorTests.cpp
+++ b/cmds/idmap2/tests/BinaryStreamVisitorTests.cpp
@@ -48,6 +48,11 @@ TEST(BinaryStreamVisitorTests, CreateBinaryStreamViaBinaryStreamVisitor) {
ASSERT_TRUE(result2);
const auto idmap2 = std::move(*result2);
+ ASSERT_EQ(idmap1->GetHeader()->GetFulfilledPolicies(),
+ idmap2->GetHeader()->GetFulfilledPolicies());
+ ASSERT_EQ(idmap1->GetHeader()->GetEnforceOverlayable(),
+ idmap2->GetHeader()->GetEnforceOverlayable());
+ ASSERT_EQ(idmap1->GetHeader()->GetTargetPath(), idmap2->GetHeader()->GetTargetPath());
ASSERT_EQ(idmap1->GetHeader()->GetTargetCrc(), idmap2->GetHeader()->GetTargetCrc());
ASSERT_EQ(idmap1->GetHeader()->GetTargetPath(), idmap2->GetHeader()->GetTargetPath());
ASSERT_EQ(idmap1->GetData().size(), 1U);
diff --git a/cmds/idmap2/tests/IdmapTests.cpp b/cmds/idmap2/tests/IdmapTests.cpp
index 87da36c01192..6fab5e0f8ae1 100644
--- a/cmds/idmap2/tests/IdmapTests.cpp
+++ b/cmds/idmap2/tests/IdmapTests.cpp
@@ -62,9 +62,11 @@ TEST(IdmapTests, CreateIdmapHeaderFromBinaryStream) {
std::unique_ptr<const IdmapHeader> header = IdmapHeader::FromBinaryStream(stream);
ASSERT_THAT(header, NotNull());
ASSERT_EQ(header->GetMagic(), 0x504d4449U);
- ASSERT_EQ(header->GetVersion(), 0x03U);
+ ASSERT_EQ(header->GetVersion(), 0x04U);
ASSERT_EQ(header->GetTargetCrc(), 0x1234U);
ASSERT_EQ(header->GetOverlayCrc(), 0x5678U);
+ ASSERT_EQ(header->GetFulfilledPolicies(), 0x11);
+ ASSERT_EQ(header->GetEnforceOverlayable(), true);
ASSERT_EQ(header->GetTargetPath().to_string(), "targetX.apk");
ASSERT_EQ(header->GetOverlayPath().to_string(), "overlayX.apk");
ASSERT_EQ(header->GetDebugInfo(), "debug");
@@ -73,7 +75,7 @@ TEST(IdmapTests, CreateIdmapHeaderFromBinaryStream) {
TEST(IdmapTests, FailToCreateIdmapHeaderFromBinaryStreamIfPathTooLong) {
std::string raw(reinterpret_cast<const char*>(idmap_raw_data), idmap_raw_data_len);
// overwrite the target path string, including the terminating null, with '.'
- for (size_t i = 0x10; i < 0x110; i++) {
+ for (size_t i = 0x15; i < 0x115; i++) {
raw[i] = '.';
}
std::istringstream stream(raw);
@@ -82,7 +84,7 @@ TEST(IdmapTests, FailToCreateIdmapHeaderFromBinaryStreamIfPathTooLong) {
}
TEST(IdmapTests, CreateIdmapDataHeaderFromBinaryStream) {
- const size_t offset = 0x21c;
+ const size_t offset = 0x221;
std::string raw(reinterpret_cast<const char*>(idmap_raw_data + offset),
idmap_raw_data_len - offset);
std::istringstream stream(raw);
@@ -94,7 +96,7 @@ TEST(IdmapTests, CreateIdmapDataHeaderFromBinaryStream) {
}
TEST(IdmapTests, CreateIdmapDataFromBinaryStream) {
- const size_t offset = 0x21c;
+ const size_t offset = 0x221;
std::string raw(reinterpret_cast<const char*>(idmap_raw_data + offset),
idmap_raw_data_len - offset);
std::istringstream stream(raw);
@@ -128,9 +130,11 @@ TEST(IdmapTests, CreateIdmapFromBinaryStream) {
ASSERT_THAT(idmap->GetHeader(), NotNull());
ASSERT_EQ(idmap->GetHeader()->GetMagic(), 0x504d4449U);
- ASSERT_EQ(idmap->GetHeader()->GetVersion(), 0x03U);
+ ASSERT_EQ(idmap->GetHeader()->GetVersion(), 0x04U);
ASSERT_EQ(idmap->GetHeader()->GetTargetCrc(), 0x1234U);
ASSERT_EQ(idmap->GetHeader()->GetOverlayCrc(), 0x5678U);
+ ASSERT_EQ(idmap->GetHeader()->GetFulfilledPolicies(), 0x11);
+ ASSERT_EQ(idmap->GetHeader()->GetEnforceOverlayable(), true);
ASSERT_EQ(idmap->GetHeader()->GetTargetPath().to_string(), "targetX.apk");
ASSERT_EQ(idmap->GetHeader()->GetOverlayPath().to_string(), "overlayX.apk");
@@ -180,9 +184,11 @@ TEST(IdmapTests, CreateIdmapHeaderFromApkAssets) {
ASSERT_THAT(idmap->GetHeader(), NotNull());
ASSERT_EQ(idmap->GetHeader()->GetMagic(), 0x504d4449U);
- ASSERT_EQ(idmap->GetHeader()->GetVersion(), 0x03U);
+ ASSERT_EQ(idmap->GetHeader()->GetVersion(), 0x04U);
ASSERT_EQ(idmap->GetHeader()->GetTargetCrc(), android::idmap2::TestConstants::TARGET_CRC);
ASSERT_EQ(idmap->GetHeader()->GetOverlayCrc(), android::idmap2::TestConstants::OVERLAY_CRC);
+ ASSERT_EQ(idmap->GetHeader()->GetFulfilledPolicies(), PolicyFlags::PUBLIC);
+ ASSERT_EQ(idmap->GetHeader()->GetEnforceOverlayable(), true);
ASSERT_EQ(idmap->GetHeader()->GetTargetPath().to_string(), target_apk_path);
ASSERT_EQ(idmap->GetHeader()->GetOverlayPath(), overlay_apk_path);
}
@@ -389,7 +395,8 @@ TEST(IdmapTests, IdmapHeaderIsUpToDate) {
std::unique_ptr<const IdmapHeader> header = IdmapHeader::FromBinaryStream(stream);
ASSERT_THAT(header, NotNull());
- ASSERT_TRUE(header->IsUpToDate());
+ ASSERT_TRUE(header->IsUpToDate(target_apk_path.c_str(), overlay_apk_path.c_str(),
+ PolicyFlags::PUBLIC, /* enforce_overlayable */ true));
// magic: bytes (0x0, 0x03)
std::string bad_magic_string(stream.str());
@@ -402,7 +409,8 @@ TEST(IdmapTests, IdmapHeaderIsUpToDate) {
IdmapHeader::FromBinaryStream(bad_magic_stream);
ASSERT_THAT(bad_magic_header, NotNull());
ASSERT_NE(header->GetMagic(), bad_magic_header->GetMagic());
- ASSERT_FALSE(bad_magic_header->IsUpToDate());
+ ASSERT_FALSE(bad_magic_header->IsUpToDate(target_apk_path.c_str(), overlay_apk_path.c_str(),
+ PolicyFlags::PUBLIC, /* enforce_overlayable */ true));
// version: bytes (0x4, 0x07)
std::string bad_version_string(stream.str());
@@ -415,7 +423,8 @@ TEST(IdmapTests, IdmapHeaderIsUpToDate) {
IdmapHeader::FromBinaryStream(bad_version_stream);
ASSERT_THAT(bad_version_header, NotNull());
ASSERT_NE(header->GetVersion(), bad_version_header->GetVersion());
- ASSERT_FALSE(bad_version_header->IsUpToDate());
+ ASSERT_FALSE(bad_magic_header->IsUpToDate(target_apk_path.c_str(), overlay_apk_path.c_str(),
+ PolicyFlags::PUBLIC, /* enforce_overlayable */ true));
// target crc: bytes (0x8, 0xb)
std::string bad_target_crc_string(stream.str());
@@ -428,7 +437,8 @@ TEST(IdmapTests, IdmapHeaderIsUpToDate) {
IdmapHeader::FromBinaryStream(bad_target_crc_stream);
ASSERT_THAT(bad_target_crc_header, NotNull());
ASSERT_NE(header->GetTargetCrc(), bad_target_crc_header->GetTargetCrc());
- ASSERT_FALSE(bad_target_crc_header->IsUpToDate());
+ ASSERT_FALSE(bad_magic_header->IsUpToDate(target_apk_path.c_str(), overlay_apk_path.c_str(),
+ PolicyFlags::PUBLIC, /* enforce_overlayable */ true));
// overlay crc: bytes (0xc, 0xf)
std::string bad_overlay_crc_string(stream.str());
@@ -441,27 +451,55 @@ TEST(IdmapTests, IdmapHeaderIsUpToDate) {
IdmapHeader::FromBinaryStream(bad_overlay_crc_stream);
ASSERT_THAT(bad_overlay_crc_header, NotNull());
ASSERT_NE(header->GetOverlayCrc(), bad_overlay_crc_header->GetOverlayCrc());
- ASSERT_FALSE(bad_overlay_crc_header->IsUpToDate());
-
- // target path: bytes (0x10, 0x10f)
+ ASSERT_FALSE(bad_magic_header->IsUpToDate(target_apk_path.c_str(), overlay_apk_path.c_str(),
+ PolicyFlags::PUBLIC, /* enforce_overlayable */ true));
+
+ // fulfilled policy: bytes (0x10, 0x13)
+ std::string bad_policy_string(stream.str());
+ bad_policy_string[0x10] = '.';
+ bad_policy_string[0x11] = '.';
+ bad_policy_string[0x12] = '.';
+ bad_policy_string[0x13] = '.';
+ std::stringstream bad_policy_stream(bad_policy_string);
+ std::unique_ptr<const IdmapHeader> bad_policy_header =
+ IdmapHeader::FromBinaryStream(bad_policy_stream);
+ ASSERT_THAT(bad_policy_header, NotNull());
+ ASSERT_NE(header->GetFulfilledPolicies(), bad_policy_header->GetFulfilledPolicies());
+ ASSERT_FALSE(bad_policy_header->IsUpToDate(target_apk_path.c_str(), overlay_apk_path.c_str(),
+ PolicyFlags::PUBLIC, /* enforce_overlayable */ true));
+
+ // enforce overlayable: bytes (0x14)
+ std::string bad_enforce_string(stream.str());
+ bad_enforce_string[0x14] = '\0';
+ std::stringstream bad_enforce_stream(bad_enforce_string);
+ std::unique_ptr<const IdmapHeader> bad_enforce_header =
+ IdmapHeader::FromBinaryStream(bad_enforce_stream);
+ ASSERT_THAT(bad_enforce_header, NotNull());
+ ASSERT_NE(header->GetEnforceOverlayable(), bad_enforce_header->GetEnforceOverlayable());
+ ASSERT_FALSE(bad_enforce_header->IsUpToDate(target_apk_path.c_str(), overlay_apk_path.c_str(),
+ PolicyFlags::PUBLIC, /* enforce_overlayable */ true));
+
+ // target path: bytes (0x15, 0x114)
std::string bad_target_path_string(stream.str());
- bad_target_path_string[0x10] = '\0';
+ bad_target_path_string[0x15] = '\0';
std::stringstream bad_target_path_stream(bad_target_path_string);
std::unique_ptr<const IdmapHeader> bad_target_path_header =
IdmapHeader::FromBinaryStream(bad_target_path_stream);
ASSERT_THAT(bad_target_path_header, NotNull());
ASSERT_NE(header->GetTargetPath(), bad_target_path_header->GetTargetPath());
- ASSERT_FALSE(bad_target_path_header->IsUpToDate());
+ ASSERT_FALSE(bad_magic_header->IsUpToDate(target_apk_path.c_str(), overlay_apk_path.c_str(),
+ PolicyFlags::PUBLIC, /* enforce_overlayable */ true));
- // overlay path: bytes (0x110, 0x20f)
+ // overlay path: bytes (0x115, 0x214)
std::string bad_overlay_path_string(stream.str());
- bad_overlay_path_string[0x110] = '\0';
+ bad_overlay_path_string[0x115] = '\0';
std::stringstream bad_overlay_path_stream(bad_overlay_path_string);
std::unique_ptr<const IdmapHeader> bad_overlay_path_header =
IdmapHeader::FromBinaryStream(bad_overlay_path_stream);
ASSERT_THAT(bad_overlay_path_header, NotNull());
ASSERT_NE(header->GetOverlayPath(), bad_overlay_path_header->GetOverlayPath());
- ASSERT_FALSE(bad_overlay_path_header->IsUpToDate());
+ ASSERT_FALSE(bad_magic_header->IsUpToDate(target_apk_path.c_str(), overlay_apk_path.c_str(),
+ PolicyFlags::PUBLIC, /* enforce_overlayable */ true));
}
class TestVisitor : public Visitor {
diff --git a/cmds/idmap2/tests/RawPrintVisitorTests.cpp b/cmds/idmap2/tests/RawPrintVisitorTests.cpp
index 5c5c81edee90..b268d5add141 100644
--- a/cmds/idmap2/tests/RawPrintVisitorTests.cpp
+++ b/cmds/idmap2/tests/RawPrintVisitorTests.cpp
@@ -43,6 +43,8 @@ namespace android::idmap2 {
<< str << "--------"; \
} while (0)
+#define ADDRESS "[0-9a-f]{8}: "
+
TEST(RawPrintVisitorTests, CreateRawPrintVisitor) {
fclose(stderr); // silence expected warnings
@@ -62,15 +64,16 @@ TEST(RawPrintVisitorTests, CreateRawPrintVisitor) {
RawPrintVisitor visitor(stream);
(*idmap)->accept(&visitor);
-#define ADDRESS "[0-9a-f]{8}: "
ASSERT_CONTAINS_REGEX(ADDRESS "504d4449 magic\n", stream.str());
- ASSERT_CONTAINS_REGEX(ADDRESS "00000003 version\n", stream.str());
+ ASSERT_CONTAINS_REGEX(ADDRESS "00000004 version\n", stream.str());
ASSERT_CONTAINS_REGEX(
StringPrintf(ADDRESS "%s target crc\n", android::idmap2::TestConstants::TARGET_CRC_STRING),
stream.str());
ASSERT_CONTAINS_REGEX(
StringPrintf(ADDRESS "%s overlay crc\n", android::idmap2::TestConstants::OVERLAY_CRC_STRING),
stream.str());
+ ASSERT_CONTAINS_REGEX(ADDRESS "00000001 fulfilled policies: public\n", stream.str());
+ ASSERT_CONTAINS_REGEX(ADDRESS " 01 enforce overlayable\n", stream.str());
ASSERT_CONTAINS_REGEX(ADDRESS " 7f target package id\n", stream.str());
ASSERT_CONTAINS_REGEX(ADDRESS " 7f overlay package id\n", stream.str());
ASSERT_CONTAINS_REGEX(ADDRESS "00000004 target entry count\n", stream.str());
@@ -83,7 +86,6 @@ TEST(RawPrintVisitorTests, CreateRawPrintVisitor) {
ASSERT_CONTAINS_REGEX(ADDRESS "7f010000 value: integer/int1\n", stream.str());
ASSERT_CONTAINS_REGEX(ADDRESS "7f010000 overlay id: integer/int1\n", stream.str());
ASSERT_CONTAINS_REGEX(ADDRESS "7f010000 target id: integer/int1\n", stream.str());
-#undef ADDRESS
}
TEST(RawPrintVisitorTests, CreateRawPrintVisitorWithoutAccessToApks) {
@@ -99,22 +101,23 @@ TEST(RawPrintVisitorTests, CreateRawPrintVisitorWithoutAccessToApks) {
RawPrintVisitor visitor(stream);
(*idmap)->accept(&visitor);
- ASSERT_NE(stream.str().find("00000000: 504d4449 magic\n"), std::string::npos);
- ASSERT_NE(stream.str().find("00000004: 00000003 version\n"), std::string::npos);
- ASSERT_NE(stream.str().find("00000008: 00001234 target crc\n"), std::string::npos);
- ASSERT_NE(stream.str().find("0000000c: 00005678 overlay crc\n"), std::string::npos);
- ASSERT_NE(stream.str().find("0000021c: 7f target package id\n"), std::string::npos);
- ASSERT_NE(stream.str().find("0000021d: 7f overlay package id\n"), std::string::npos);
- ASSERT_NE(stream.str().find("0000021e: 00000003 target entry count\n"), std::string::npos);
- ASSERT_NE(stream.str().find("00000222: 00000003 overlay entry count\n"), std::string::npos);
- ASSERT_NE(stream.str().find("00000226: 00000000 string pool index offset\n"), std::string::npos);
- ASSERT_NE(stream.str().find("0000022a: 00000000 string pool byte length\n"), std::string::npos);
- ASSERT_NE(stream.str().find("0000022e: 7f020000 target id\n"), std::string::npos);
- ASSERT_NE(stream.str().find("00000232: 01 type: reference\n"), std::string::npos);
- ASSERT_NE(stream.str().find("00000233: 7f020000 value\n"), std::string::npos);
-
- ASSERT_NE(stream.str().find("00000249: 7f020000 overlay id\n"), std::string::npos);
- ASSERT_NE(stream.str().find("0000024d: 7f020000 target id\n"), std::string::npos);
+ ASSERT_CONTAINS_REGEX(ADDRESS "504d4449 magic\n", stream.str());
+ ASSERT_CONTAINS_REGEX(ADDRESS "00000004 version\n", stream.str());
+ ASSERT_CONTAINS_REGEX(ADDRESS "00001234 target crc\n", stream.str());
+ ASSERT_CONTAINS_REGEX(ADDRESS "00005678 overlay crc\n", stream.str());
+ ASSERT_CONTAINS_REGEX(ADDRESS "00000011 fulfilled policies: public|signature\n", stream.str());
+ ASSERT_CONTAINS_REGEX(ADDRESS " 01 enforce overlayable\n", stream.str());
+ ASSERT_CONTAINS_REGEX(ADDRESS " 7f target package id\n", stream.str());
+ ASSERT_CONTAINS_REGEX(ADDRESS " 7f overlay package id\n", stream.str());
+ ASSERT_CONTAINS_REGEX(ADDRESS "00000003 target entry count\n", stream.str());
+ ASSERT_CONTAINS_REGEX(ADDRESS "00000003 overlay entry count\n", stream.str());
+ ASSERT_CONTAINS_REGEX(ADDRESS "00000000 string pool index offset\n", stream.str());
+ ASSERT_CONTAINS_REGEX(ADDRESS "00000000 string pool byte length\n", stream.str());
+ ASSERT_CONTAINS_REGEX(ADDRESS "7f020000 target id\n", stream.str());
+ ASSERT_CONTAINS_REGEX(ADDRESS " 01 type: reference\n", stream.str());
+ ASSERT_CONTAINS_REGEX(ADDRESS "7f020000 value\n", stream.str());
+ ASSERT_CONTAINS_REGEX(ADDRESS "7f020000 overlay id\n", stream.str());
+ ASSERT_CONTAINS_REGEX(ADDRESS "7f020000 target id\n", stream.str());
}
} // namespace android::idmap2
diff --git a/cmds/idmap2/tests/ResourceMappingTests.cpp b/cmds/idmap2/tests/ResourceMappingTests.cpp
index 5754eaf078a9..de039f440e33 100644
--- a/cmds/idmap2/tests/ResourceMappingTests.cpp
+++ b/cmds/idmap2/tests/ResourceMappingTests.cpp
@@ -287,26 +287,66 @@ TEST(ResourceMappingTests, ResourcesFromApkAssetsNoDefinedOverlayableAndNoTarget
R::overlay::string::str4, false /* rewrite */));
}
-
-// Overlays that are pre-installed or are signed with the same signature as the target/actor can
+// Overlays that are neither pre-installed nor signed with the same signature as the target cannot
// overlay packages that have not defined overlayable resources.
-TEST(ResourceMappingTests, ResourcesFromApkAssetsDefaultPolicies) {
- constexpr PolicyBitmask kDefaultPolicies =
- PolicyFlags::SIGNATURE | PolicyFlags::ACTOR_SIGNATURE | PolicyFlags::PRODUCT_PARTITION |
- PolicyFlags::SYSTEM_PARTITION | PolicyFlags::VENDOR_PARTITION | PolicyFlags::ODM_PARTITION |
- PolicyFlags::OEM_PARTITION;
+TEST(ResourceMappingTests, ResourcesFromApkAssetsDefaultPoliciesPublicFail) {
+ auto resources = TestGetResourceMapping("/target/target-no-overlayable.apk",
+ "/overlay/overlay-no-name.apk", PolicyFlags::PUBLIC,
+ /* enforce_overlayable */ true);
+
+ ASSERT_TRUE(resources) << resources.GetErrorMessage();
+ ASSERT_EQ(resources->GetTargetToOverlayMap().size(), 0U);
+}
- for (PolicyBitmask policy = 1U << (sizeof(PolicyBitmask) * 8 - 1); policy > 0;
- policy = policy >> 1U) {
+// Overlays that are pre-installed or are signed with the same signature as the target can overlay
+// packages that have not defined overlayable resources.
+TEST(ResourceMappingTests, ResourcesFromApkAssetsDefaultPolicies) {
+ auto CheckEntries = [&](const PolicyBitmask& fulfilled_policies) -> void {
auto resources = TestGetResourceMapping("/target/target-no-overlayable.apk",
"/system-overlay-invalid/system-overlay-invalid.apk",
- policy, /* enforce_overlayable */ true);
- ASSERT_TRUE(resources) << resources.GetErrorMessage();
+ fulfilled_policies,
+ /* enforce_overlayable */ true);
- const size_t expected_overlaid = (policy & kDefaultPolicies) != 0 ? 10U : 0U;
- ASSERT_EQ(expected_overlaid, resources->GetTargetToOverlayMap().size())
- << "Incorrect number of resources overlaid through policy " << policy;
- }
+ ASSERT_TRUE(resources) << resources.GetErrorMessage();
+ auto& res = *resources;
+ ASSERT_EQ(resources->GetTargetToOverlayMap().size(), 10U);
+ ASSERT_RESULT(MappingExists(res, R::target::string::not_overlayable, Res_value::TYPE_REFERENCE,
+ R::system_overlay_invalid::string::not_overlayable,
+ false /* rewrite */));
+ ASSERT_RESULT(MappingExists(res, R::target::string::other, Res_value::TYPE_REFERENCE,
+ R::system_overlay_invalid::string::other, false /* rewrite */));
+ ASSERT_RESULT(MappingExists(res, R::target::string::policy_actor, Res_value::TYPE_REFERENCE,
+ R::system_overlay_invalid::string::policy_actor,
+ false /* rewrite */));
+ ASSERT_RESULT(MappingExists(res, R::target::string::policy_odm, Res_value::TYPE_REFERENCE,
+ R::system_overlay_invalid::string::policy_odm,
+ false /* rewrite */));
+ ASSERT_RESULT(MappingExists(res, R::target::string::policy_oem, Res_value::TYPE_REFERENCE,
+ R::system_overlay_invalid::string::policy_oem,
+ false /* rewrite */));
+ ASSERT_RESULT(MappingExists(res, R::target::string::policy_product, Res_value::TYPE_REFERENCE,
+ R::system_overlay_invalid::string::policy_product,
+ false /* rewrite */));
+ ASSERT_RESULT(MappingExists(res, R::target::string::policy_public, Res_value::TYPE_REFERENCE,
+ R::system_overlay_invalid::string::policy_public,
+ false /* rewrite */));
+ ASSERT_RESULT(MappingExists(res, R::target::string::policy_signature, Res_value::TYPE_REFERENCE,
+ R::system_overlay_invalid::string::policy_signature,
+ false /* rewrite */));
+ ASSERT_RESULT(MappingExists(res, R::target::string::policy_system, Res_value::TYPE_REFERENCE,
+ R::system_overlay_invalid::string::policy_system,
+ false /* rewrite */));
+ ASSERT_RESULT(MappingExists(
+ res, R::target::string::policy_system_vendor, Res_value::TYPE_REFERENCE,
+ R::system_overlay_invalid::string::policy_system_vendor, false /* rewrite */));
+ };
+
+ CheckEntries(PolicyFlags::SIGNATURE);
+ CheckEntries(PolicyFlags::PRODUCT_PARTITION);
+ CheckEntries(PolicyFlags::SYSTEM_PARTITION);
+ CheckEntries(PolicyFlags::VENDOR_PARTITION);
+ CheckEntries(PolicyFlags::ODM_PARTITION);
+ CheckEntries(PolicyFlags::OEM_PARTITION);
}
} // namespace android::idmap2
diff --git a/cmds/idmap2/tests/TestHelpers.h b/cmds/idmap2/tests/TestHelpers.h
index e899589c7e61..b599dcb0069a 100644
--- a/cmds/idmap2/tests/TestHelpers.h
+++ b/cmds/idmap2/tests/TestHelpers.h
@@ -30,7 +30,7 @@ const unsigned char idmap_raw_data[] = {
0x49, 0x44, 0x4d, 0x50,
// 0x4: version
- 0x03, 0x00, 0x00, 0x00,
+ 0x04, 0x00, 0x00, 0x00,
// 0x8: target crc
0x34, 0x12, 0x00, 0x00,
@@ -38,7 +38,13 @@ const unsigned char idmap_raw_data[] = {
// 0xc: overlay crc
0x78, 0x56, 0x00, 0x00,
- // 0x10: target path "targetX.apk"
+ // 0x10: fulfilled policies
+ 0x11, 0x00, 0x00, 0x00,
+
+ // 0x14: enforce overlayable
+ 0x01,
+
+ // 0x15: target path "targetX.apk"
0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x58, 0x2e, 0x61, 0x70, 0x6b, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
@@ -56,7 +62,7 @@ const unsigned char idmap_raw_data[] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- // 0x110: overlay path "overlayX.apk"
+ // 0x115: overlay path "overlayX.apk"
0x6f, 0x76, 0x65, 0x72, 0x6c, 0x61, 0x79, 0x58, 0x2e, 0x61, 0x70, 0x6b, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
@@ -74,7 +80,7 @@ const unsigned char idmap_raw_data[] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- // 0x210: debug string
+ // 0x215: debug string
// string length, including terminating null
0x08, 0x00, 0x00, 0x00,
@@ -82,63 +88,63 @@ const unsigned char idmap_raw_data[] = {
0x64, 0x65, 0x62, 0x75, 0x67, 0x00, 0x00, 0x00,
// DATA HEADER
- // 0x21c: target_package_id
+ // 0x221: target_package_id
0x7f,
- // 0x21d: overlay_package_id
+ // 0x222: overlay_package_id
0x7f,
- // 0x21e: target_entry_count
+ // 0x223: target_entry_count
0x03, 0x00, 0x00, 0x00,
- // 0x222: overlay_entry_count
+ // 0x227: overlay_entry_count
0x03, 0x00, 0x00, 0x00,
- // 0x226: string_pool_offset
+ // 0x22b: string_pool_offset
0x00, 0x00, 0x00, 0x00,
- // 0x22a: string_pool_byte_length
+ // 0x22f: string_pool_byte_length
0x00, 0x00, 0x00, 0x00,
// TARGET ENTRIES
- // 0x22e: 0x7f020000
+ // 0x233: 0x7f020000
0x00, 0x00, 0x02, 0x7f,
- // 0x232: TYPE_REFERENCE
+ // 0x237: TYPE_REFERENCE
0x01,
- // 0x233: 0x7f020000
+ // 0x238: 0x7f020000
0x00, 0x00, 0x02, 0x7f,
- // 0x237: 0x7f030000
+ // 0x23c: 0x7f030000
0x00, 0x00, 0x03, 0x7f,
- // 0x23b: TYPE_REFERENCE
+ // 0x240: TYPE_REFERENCE
0x01,
- // 0x23c: 0x7f030000
+ // 0x241: 0x7f030000
0x00, 0x00, 0x03, 0x7f,
- // 0x240: 0x7f030002
+ // 0x245: 0x7f030002
0x02, 0x00, 0x03, 0x7f,
- // 0x244: TYPE_REFERENCE
+ // 0x249: TYPE_REFERENCE
0x01,
- // 0x245: 0x7f030001
+ // 0x24a: 0x7f030001
0x01, 0x00, 0x03, 0x7f,
// OVERLAY ENTRIES
- // 0x249: 0x7f020000 -> 0x7f020000
+ // 0x24e: 0x7f020000 -> 0x7f020000
0x00, 0x00, 0x02, 0x7f, 0x00, 0x00, 0x02, 0x7f,
- // 0x251: 0x7f030000 -> 0x7f030000
+ // 0x256: 0x7f030000 -> 0x7f030000
0x00, 0x00, 0x03, 0x7f, 0x00, 0x00, 0x03, 0x7f,
- // 0x259: 0x7f030001 -> 0x7f030002
+ // 0x25e: 0x7f030001 -> 0x7f030002
0x01, 0x00, 0x03, 0x7f, 0x02, 0x00, 0x03, 0x7f};
-const unsigned int idmap_raw_data_len = 0x261;
+const unsigned int idmap_raw_data_len = 0x266;
std::string GetTestDataPath();
diff --git a/cmds/incidentd/src/Section.cpp b/cmds/incidentd/src/Section.cpp
index 61e5eb07130c..33e764988b75 100644
--- a/cmds/incidentd/src/Section.cpp
+++ b/cmds/incidentd/src/Section.cpp
@@ -477,14 +477,15 @@ status_t TextDumpsysSection::Execute(ReportWriter* writer) const {
// Run dumping thread
const uint64_t start = Nanotime();
- std::thread worker([&]() {
+ std::thread worker([write_fd = std::move(dumpPipe.writeFd()), service = std::move(service),
+ this]() mutable {
// Don't crash the service if writing to a closed pipe (may happen if dumping times out)
signal(SIGPIPE, sigpipe_handler);
- status_t err = service->dump(dumpPipe.writeFd().get(), mArgs);
+ status_t err = service->dump(write_fd.get(), this->mArgs);
if (err != OK) {
ALOGW("[%s] dump thread failed. Error: %s", this->name.string(), strerror(-err));
}
- dumpPipe.writeFd().reset();
+ write_fd.reset();
});
// Collect dump content
diff --git a/cmds/statsd/src/atoms.proto b/cmds/statsd/src/atoms.proto
index 36a8b2cfc084..1823bad0076d 100644
--- a/cmds/statsd/src/atoms.proto
+++ b/cmds/statsd/src/atoms.proto
@@ -193,7 +193,7 @@ message Atom {
BiometricAcquired biometric_acquired = 87 [(module) = "framework"];
BiometricAuthenticated biometric_authenticated = 88 [(module) = "framework"];
BiometricErrorOccurred biometric_error_occurred = 89 [(module) = "framework"];
- UiEventReported ui_event_reported = 90 [(module) = "framework"];
+ UiEventReported ui_event_reported = 90 [(module) = "framework", (module) = "sysui"];
BatteryHealthSnapshot battery_health_snapshot = 91;
SlowIo slow_io = 92;
BatteryCausedShutdown battery_caused_shutdown = 93;
@@ -419,7 +419,7 @@ message Atom {
DisplayJankReported display_jank_reported = 257;
AppStandbyBucketChanged app_standby_bucket_changed = 258 [(module) = "framework"];
SharesheetStarted sharesheet_started = 259 [(module) = "framework"];
- RankingSelected ranking_selected = 260 [(module) = "framework"];
+ RankingSelected ranking_selected = 260 [(module) = "framework", (module) = "sysui"];
TvSettingsUIInteracted tvsettings_ui_interacted = 261 [(module) = "tv_settings"];
LauncherStaticLayout launcher_snapshot = 262 [(module) = "sysui"];
PackageInstallerV2Reported package_installer_v2_reported = 263 [(module) = "framework"];
@@ -444,13 +444,34 @@ message Atom {
TvTunerStateChanged tv_tuner_state_changed = 276 [(module) = "framework"];
MediaOutputOpSwitchReported mediaoutput_op_switch_reported =
277 [(module) = "settings"];
+ CellBroadcastMessageFiltered cb_message_filtered =
+ 278 [(module) = "cellbroadcast"];
+ TvTunerDvrStatus tv_tuner_dvr_status = 279 [(module) = "framework"];
+ TvCasSessionOpenStatus tv_cas_session_open_status =
+ 280 [(module) = "framework"];
+ AssistantInvocationReported assistant_invocation_reported = 281 [(module) = "framework"];
+ DisplayWakeReported display_wake_reported = 282 [(module) = "framework"];
+ CarUserHalModifyUserRequestReported car_user_hal_modify_user_request_reported =
+ 283 [(module) = "car"];
+ CarUserHalModifyUserResponseReported car_user_hal_modify_user_response_reported =
+ 284 [(module) = "car"];
+ CarUserHalPostSwitchResponseReported car_user_hal_post_switch_response_reported =
+ 285 [(module) = "car"];
+ CarUserHalInitialUserInfoRequestReported car_user_hal_initial_user_info_request_reported =
+ 286 [(module) = "car"];
+ CarUserHalInitialUserInfoResponseReported car_user_hal_initial_user_info_response_reported =
+ 287 [(module) = "car"];
+ CarUserHalUserAssociationRequestReported car_user_hal_user_association_request_reported =
+ 288 [(module) = "car"];
+ CarUserHalSetUserAssociationResponseReported car_user_hal_set_user_association_response_reported =
+ 289 [(module) = "car"];
// StatsdStats tracks platform atoms with ids upto 500.
// Update StatsdStats::kMaxPushedAtomId when atom ids here approach that value.
}
// Pulled events will start at field 10000.
- // Next: 10084
+ // Next: 10081
oneof pulled {
WifiBytesTransfer wifi_bytes_transfer = 10000 [(module) = "framework"];
WifiBytesTransferByFgBg wifi_bytes_transfer_by_fg_bg = 10001 [(module) = "framework"];
@@ -541,10 +562,11 @@ message Atom {
SimSlotState sim_slot_state = 10078 [(module) = "telephony"];
SupportedRadioAccessFamily supported_radio_access_family = 10079 [(module) = "telephony"];
SettingSnapshot setting_snapshot = 10080 [(module) = "framework"];
- DisplayWakeReason display_wake_reason = 10081 [(module) = "framework"];
+ //10081 free for use
DataUsageBytesTransfer data_usage_bytes_transfer = 10082 [(module) = "framework"];
BytesTransferByTagAndMetered bytes_transfer_by_tag_and_metered =
10083 [(module) = "framework"];
+ DNDModeProto dnd_mode_rule = 10084 [(module) = "framework"];
}
// DO NOT USE field numbers above 100,000 in AOSP.
@@ -5798,7 +5820,7 @@ message ProcessStatsProto {
optional string process = 1;
// Uid of the process.
- optional int32 uid = 2;
+ optional int32 uid = 2 [(is_uid) = true];
// Information about how often kills occurred
message Kill {
@@ -5825,13 +5847,16 @@ message ProcessStatsProto {
repeated ProcessStatsAssociationProto assocs = 7;
}
-// Next Tag: 5
+// Next Tag: 6
message ProcessStatsAssociationProto {
// Procss Name of the associated process (client process of service binding)
optional string assoc_process_name = 1;
// Package Name of the associated package (client package of service binding)
- optional string assoc_package_name = 2;
+ optional string assoc_package_name = 2 [deprecated = true];
+
+ // UID of the associated process/package (client package of service binding)
+ optional int32 assoc_uid = 5 [(is_uid) = true];
// Total count of the times this association (service binding) appeared.
optional int32 total_count = 3;
@@ -6059,6 +6084,76 @@ message PackageNotificationChannelPreferences {
}
/**
+ * Atom that represents an item in the list of Do Not Disturb rules, pulled from
+ * NotificationManagerService.java.
+ */
+message DNDModeProto {
+ enum Mode {
+ ROOT_CONFIG = -1; // Used to distinguish the config (one per user) from the rules.
+ ZEN_MODE_OFF = 0;
+ ZEN_MODE_IMPORTANT_INTERRUPTIONS = 1;
+ ZEN_MODE_NO_INTERRUPTIONS = 2;
+ ZEN_MODE_ALARMS = 3;
+ }
+ optional int32 user = 1; // Android user ID (0, 1, 10, ...)
+ optional bool enabled = 2; // true for ROOT_CONFIG if a manualRule is enabled
+ optional bool channels_bypassing = 3; // only valid for ROOT_CONFIG
+ optional Mode zen_mode = 4;
+ // id is one of the system default rule IDs, or empty
+ // May also be "MANUAL_RULE" to indicate app-activation of the manual rule.
+ optional string id = 5;
+ optional int32 uid = 6 [(is_uid) = true]; // currently only SYSTEM_UID or 0 for other
+ optional DNDPolicyProto policy = 7;
+}
+
+/**
+ * Atom that represents a Do Not Disturb policy, an optional detail proto for DNDModeProto.
+ */
+message DNDPolicyProto {
+ enum State {
+ STATE_UNSET = 0;
+ STATE_ALLOW = 1;
+ STATE_DISALLOW = 2;
+ }
+ optional State calls = 1;
+ optional State repeat_callers = 2;
+ optional State messages = 3;
+ optional State conversations = 4;
+ optional State reminders = 5;
+ optional State events = 6;
+ optional State alarms = 7;
+ optional State media = 8;
+ optional State system = 9;
+ optional State fullscreen = 10;
+ optional State lights = 11;
+ optional State peek = 12;
+ optional State status_bar = 13;
+ optional State badge = 14;
+ optional State ambient = 15;
+ optional State notification_list = 16;
+
+ enum PeopleType {
+ PEOPLE_UNSET = 0;
+ PEOPLE_ANYONE = 1;
+ PEOPLE_CONTACTS = 2;
+ PEOPLE_STARRED = 3;
+ PEOPLE_NONE = 4;
+ }
+
+ optional PeopleType allow_calls_from = 17;
+ optional PeopleType allow_messages_from = 18;
+
+ enum ConversationType {
+ CONV_UNSET = 0;
+ CONV_ANYONE = 1;
+ CONV_IMPORTANT = 2;
+ CONV_NONE = 3;
+ }
+
+ optional ConversationType allow_conversations_from = 19;
+}
+
+/**
* Atom that contains a list of a package's channel group preferences, pulled from
* NotificationManagerService.java.
*/
@@ -6309,6 +6404,16 @@ message ContentCaptureServiceEvents {
SET_WHITELIST = 3;
SET_DISABLED = 4;
ON_USER_DATA_REMOVED = 5;
+ ON_DATA_SHARE_REQUEST = 6;
+ ACCEPT_DATA_SHARE_REQUEST = 7;
+ REJECT_DATA_SHARE_REQUEST = 8;
+ DATA_SHARE_WRITE_FINISHED = 9;
+ DATA_SHARE_ERROR_IOEXCEPTION = 10;
+ DATA_SHARE_ERROR_EMPTY_DATA = 11;
+ DATA_SHARE_ERROR_CLIENT_PIPE_FAIL = 12;
+ DATA_SHARE_ERROR_SERVICE_PIPE_FAIL = 13;
+ DATA_SHARE_ERROR_CONCURRENT_REQUEST = 14;
+ DATA_SHARE_ERROR_TIMEOUT_INTERRUPTED = 15;
}
optional Event event = 1;
// component/package of content capture service.
@@ -7992,6 +8097,245 @@ message CarPowerStateChanged {
}
/**
+ * Logs when Car User Hal is requested to switch/create/remove user.
+ *
+ * Logged from:
+ * packages/services/Car/service/src/com/android/car/hal/UserHalService.java
+ */
+message CarUserHalModifyUserRequestReported {
+ // Request id for the request.
+ optional int32 request_id = 1;
+ // Request type.
+ enum RequestType {
+ UNKNOWN = 0;
+ // Car user manager requested user switch.
+ SWITCH_REQUEST_ANDROID = 1;
+ // OEM requested User switch.
+ SWITCH_REQUEST_OEM = 2;
+ // Hal switch requested after android switch using activity manager.
+ SWITCH_REQUEST_LEGACY = 3;
+ // Create User
+ CREATE_REQUEST = 4;
+ // Remove User
+ REMOVE_REQUEST = 5;
+ }
+ optional RequestType request_type = 2;
+ // Android User id of the current user which can only be 0, 10, 11 and so on.
+ // -1 if not available.
+ optional int32 user_id = 3;
+ // VHAL flags of the current user. (-1 if not available)
+ optional int32 user_flags = 4;
+ // Android User id of the target user for switch/create/remove. It can only
+ // be 0, 10, 11 and so on. -1 if not available.
+ optional int32 target_user_id = 5;
+ // VHAL flags of the target user for switch/create/remove. (-1 if not available)
+ optional int32 target_user_flags = 6;
+ // Request timeout Milliseconds (-1 if not available)
+ optional int32 timeout_millis = 7;
+}
+
+/**
+ * Logs when Car User Hal responds to switch/create user request.
+ *
+ * Logged from:
+ * packages/services/Car/service/src/com/android/car/hal/UserHalService.java
+ */
+message CarUserHalModifyUserResponseReported {
+ // Request id of the request associated with the response.
+ optional int32 request_id = 1;
+ // Car user hal callback status.
+ enum CallbackStatus {
+ UNKNOWN = 0;
+ // Hal response was invalid.
+ INVALID = 1;
+ // Hal response was ok.
+ OK = 2;
+ // Hal timeout during set call.
+ HAL_SET_TIMEOUT = 3;
+ // Hal response timeout.
+ HAL_RESPONSE_TIMEOUT = 4;
+ // Hal responded with wrong info.
+ WRONG_HAL_RESPONSE = 5;
+ // Hal is processing multiple requests simultaneously.
+ CONCURRENT_OPERATION = 6;
+ }
+ optional CallbackStatus callback_status = 2;
+
+ // Hal request status for user switch/create/remove.
+ enum HalRequestStatus {
+ UNSPECIFIED = 0;
+ // Hal request for user switch/create is successful.
+ SUCCESS = 1;
+ // Hal request for user switch/create failed.
+ FAILURE = 2;
+ }
+ optional HalRequestStatus request_status = 3;
+}
+
+/**
+ * Logs when post switch response is posted to Car User Hal.
+ *
+ * Logged from:
+ * packages/services/Car/service/src/com/android/car/hal/UserHalService.java
+ */
+message CarUserHalPostSwitchResponseReported {
+ // Request id.
+ optional int32 request_id = 1;
+
+ // Android user switch status.
+ enum UserSwitchStatus {
+ UNKNOWN = 0;
+ // Android user switch is successful.
+ SUCCESS = 1;
+ // Android user switch failed.
+ FAILURE = 2;
+ }
+ optional UserSwitchStatus switch_status = 2;
+}
+
+/**
+ * Logs when initial user information is requested from Car User Hal.
+ *
+ * Logged from:
+ * packages/services/Car/service/src/com/android/car/hal/UserHalService.java
+ */
+message CarUserHalInitialUserInfoRequestReported {
+ // Request id for the request.
+ optional int32 request_id = 1;
+
+ // Request type for initial user information.
+ enum InitialUserInfoRequestType {
+ UNKNOWN = 0;
+ // At the first time Android was booted (or after a factory reset).
+ FIRST_BOOT = 1;
+ // At the first time Android was booted after the system was updated.
+ FIRST_BOOT_AFTER_OTA = 2;
+ // When Android was booted "from scratch".
+ COLD_BOOT = 3;
+ // When Android was resumed after the system was suspended to memory.
+ RESUME = 4;
+ }
+ optional InitialUserInfoRequestType request_type = 2;
+ // Request timeout Milliseconds (-1 if not available)
+ optional int32 timeout_millis = 3;
+}
+
+/**
+ * Logs when Car User Hal responds to initial user information requests.
+ *
+ * Logged from:
+ * packages/services/Car/service/src/com/android/car/hal/UserHalService.java
+ */
+message CarUserHalInitialUserInfoResponseReported {
+ // Request id of the request associated with the response.
+ optional int32 request_id = 1;
+ // Car user hal callback status.
+ enum CallbackStatus {
+ UNKNOWN = 0;
+ // Hal response was invalid.
+ INVALID = 1;
+ // Hal response was ok.
+ OK = 2;
+ // Hal timeout during set call.
+ HAL_SET_TIMEOUT = 3;
+ // Hal response timeout.
+ HAL_RESPONSE_TIMEOUT = 4;
+ // Hal responded with wrong info.
+ WRONG_HAL_RESPONSE = 5;
+ // Hal is processing multiple requests simultaneously.
+ CONCURRENT_OPERATION = 6;
+ }
+ optional CallbackStatus callback_status = 2;
+ // Response for initial user information request.
+ enum InitialUserInfoResponseAction {
+ UNSPECIFIED = 0;
+ // Let the Android System decide what to do.
+ DEFAULT = 1;
+ // Switch to an existing Android user.
+ SWITCH = 2;
+ // Create a new Android user (and switch to it).
+ CREATE = 3;
+ }
+ optional InitialUserInfoResponseAction response_action = 3;
+ // Android User id of the target user which can only be 0, 10, 11 and so on.
+ // -1 if not available.
+ optional int32 target_user = 4;
+ // VHAL flags of the current user. (-1 if not available)
+ optional int32 target_user_flags = 5;
+ // User locales
+ optional string user_locales = 6;
+}
+
+/**
+ * Logs when set user association is requested from Car User Hal.
+ *
+ * Logged from:
+ * packages/services/Car/service/src/com/android/car/hal/UserHalService.java
+ */
+message CarUserHalUserAssociationRequestReported {
+ // Request id for the request.
+ optional int32 request_id = 1;
+ // Request type.
+ enum RequestType {
+ UNKNOWN = 0;
+ // For setting user association information.
+ SET = 1;
+ // For getting user association information.
+ GET = 2;
+ }
+ optional RequestType request_type = 2;
+ // Android User id of the current user which can only be 0, 10, 11 and so on.
+ // -1 if not available.
+ optional int32 current_user_id = 3;
+ // VHAL flags of the current user. (-1 if not available)
+ optional int32 current_user_flags = 4;
+ // Number of the set associations requested.
+ optional int32 number_associations = 5;
+ // Concatenated string for the types from set associations request.
+ // This is a string converted from an array of integers.
+ optional string user_identification_association_types = 6;
+ // Concatenated string for the values from set associations request.
+ // This is a string converted from an array of integers.
+ optional string user_identification_association_values = 7;
+}
+
+/**
+ * Logs when Car User Hal responds to set user association requests.
+ *
+ * Logged from:
+ * packages/services/Car/service/src/com/android/car/hal/UserHalService.java
+ */
+message CarUserHalSetUserAssociationResponseReported {
+ // Request id of the request associated with the response.
+ optional int32 request_id = 1;
+ // Car user hal callback status.
+ enum CallbackStatus {
+ UNKNOWN = 0;
+ // Hal response was invalid.
+ INVALID = 1;
+ // Hal response was ok.
+ OK = 2;
+ // Hal timeout during set call.
+ HAL_SET_TIMEOUT = 3;
+ // Hal response timeout.
+ HAL_RESPONSE_TIMEOUT = 4;
+ // Hal responded with wrong info.
+ WRONG_HAL_RESPONSE = 5;
+ // Hal is processing multiple requests simultaneously.
+ CONCURRENT_OPERATION = 6;
+ }
+ optional CallbackStatus callback_status = 2;
+ // Number of the set associations in the response.
+ optional int32 number_associations = 3;
+ // Concatenated string for the types from set associations request.
+ // This is a string converted from an array of integers.
+ optional string user_identification_association_types = 4;
+ // Concatenated string for the values from set associations request.
+ // This is a string converted from an array of integers.
+ optional string user_identification_association_values = 5;
+}
+
+/**
* Logs whether GarageMode is entered.
*
* Logged from:
@@ -9134,8 +9478,10 @@ message IntegrityRulesPushed {
/**
* Logs when a cell broadcast message is received on the device.
*
- * Logged from CellBroadcastService module:
+ * Logged from Cell Broadcast module and platform:
* packages/modules/CellBroadcastService/src/com/android/cellbroadcastservice/
+ * packages/apps/CellBroadcastReceiver/
+ * frameworks/opt/telephony/src/java/com/android/internal/telephony/CellBroadcastServiceManager.java
*/
message CellBroadcastMessageReported {
// The type of Cell Broadcast message
@@ -9146,8 +9492,40 @@ message CellBroadcastMessageReported {
CDMA_SPC = 3;
}
+ // The parts of the cell broadcast message pipeline
+ enum ReportSource {
+ UNKNOWN_SOURCE = 0;
+ FRAMEWORK = 1;
+ CB_SERVICE = 2;
+ CB_RECEIVER_APP = 3;
+ }
+
// GSM, CDMA, CDMA-SCP
optional CbType type = 1;
+
+ // The source of the report
+ optional ReportSource source = 2;
+}
+
+/**
+ * Logs when a cell broadcast message is filtered out, or otherwise intentionally not sent to CBR.
+ *
+ * Logged from CellBroadcastService module:
+ * packages/modules/CellBroadcastService/src/com/android/cellbroadcastservice/
+ */
+message CellBroadcastMessageFiltered {
+ enum FilterReason {
+ NOT_FILTERED = 0;
+ DUPLICATE_MESSAGE = 1;
+ GEOFENCED_MESSAGE = 2;
+ AREA_INFO_MESSAGE = 3;
+ }
+
+ // GSM, CDMA, CDMA-SCP
+ optional CellBroadcastMessageReported.CbType type = 1;
+
+ // The source of the report
+ optional FilterReason filter = 2;
}
/**
@@ -9174,6 +9552,7 @@ message CellBroadcastMessageError {
UNEXPECTED_GSM_MESSAGE_TYPE_FROM_FWK = 12;
UNEXPECTED_CDMA_MESSAGE_TYPE_FROM_FWK = 13;
UNEXPECTED_CDMA_SCP_MESSAGE_TYPE_FROM_FWK = 14;
+ NO_CONNECTION_TO_CB_SERVICE = 15;
}
// What kind of error occurred
@@ -9205,6 +9584,58 @@ message TvTunerStateChanged {
// new state
optional State state = 2;
}
+
+/**
+ * Logs the status of a dvr playback or record.
+ * This is atom ID 279.
+ *
+ * Logged from:
+ * frameworks/base/media/java/android/media/tv/tuner/dvr
+ */
+message TvTunerDvrStatus {
+ enum Type {
+ UNKNOWN_TYPE = 0;
+ PLAYBACK = 1; // is a playback
+ RECORD = 2; // is a record
+ }
+ enum State {
+ UNKNOWN_STATE = 0;
+ STARTED = 1; // DVR is started
+ STOPPED = 2; // DVR is stopped
+ }
+ // The uid of the application that sent this custom atom.
+ optional int32 uid = 1 [(is_uid) = true];
+ // DVR type
+ optional Type type = 2;
+ // DVR state
+ optional State state = 3;
+ // Identify the segment of a record or playback
+ optional int32 segment_id = 4;
+ // indicate how many overflow or underflow happened between started to stopped
+ optional int32 overflow_underflow_count = 5;
+}
+
+/**
+ * Logs when a cas session opened through MediaCas.
+ * This is atom ID 280.
+ *
+ * Logged from:
+ * frameworks/base/media/java/android/media/MediaCas.java
+ */
+message TvCasSessionOpenStatus {
+ enum State {
+ UNKNOWN = 0;
+ SUCCEEDED = 1; // indicate that the session is opened successfully.
+ FAILED = 2; // indicate that the session isn’t opened successfully.
+ }
+ // The uid of the application that sent this custom atom.
+ optional int32 uid = 1 [(is_uid) = true];
+ // Cas system Id
+ optional int32 cas_system_id = 2;
+ // State of the session
+ optional State state = 3;
+}
+
/**
* Logs when an app is frozen or unfrozen.
*
@@ -9721,15 +10152,20 @@ message AccessibilityServiceReported {
optional android.stats.accessibility.ServiceStatus service_status = 2;
}
-message DisplayWakeReason {
+/**
+ * Logs when display wake up.
+ *
+ * Logged from:
+ * services/core/java/com/android/server/power/Notifier.java
+ */
+
+message DisplayWakeReported {
// Wake_up_reason code
// If LOWORD(wake_up_reason) = 0
// reference to HIWORD(wake_up_reason) PowerManager.WAKE_REASON_XXX
// else reference wake_up_reason to
- // frameworks/base/services/core/java/com/android/server/power/Notifier.java#DispWakeupReason
+ // services/core/java/com/android/server/power/Notifier.java#onWakeUp
optional int32 wake_up_reason = 1;
- // Count of wake up by reason
- optional int32 wake_times = 2;
}
/**
@@ -9903,3 +10339,42 @@ message MediaOutputOpSwitchReported {
// The amount of applied devices within a remote dynamic group after a switching is done.
optional int32 applied_device_count_within_remote_group = 9;
}
+
+/**
+ * Logs when the Assistant is invoked.
+ *
+ * Logged from:
+ * frameworks/base/packages/SystemUI/src/com/android/systemui/assist/AssistManager.java
+ */
+message AssistantInvocationReported {
+
+ // The event_id (as for UiEventReported).
+ optional int32 event_id = 1;
+
+ // The registered Assistant's uid and package (as for UiEventReported).
+ optional int32 uid = 2 [(is_uid) = true];
+ optional string package_name = 3;
+
+ // An identifier used to disambiguate which logs refer to a particular invocation of the
+ // Assistant (as for UiEventReported).
+ optional int32 instance_id = 4;
+
+ // The state of the device at the time of invocation.
+ enum DeviceState {
+ UNKNOWN_DEVICE_STATE = 0;
+ AOD1 = 1;
+ AOD2 = 2;
+ BOUNCER = 3;
+ UNLOCKED_LOCKSCREEN = 4;
+ LAUNCHER_HOME = 5;
+ LAUNCHER_OVERVIEW = 6;
+ LAUNCHER_ALL_APPS = 7;
+ APP_DEFAULT = 8;
+ APP_IMMERSIVE = 9;
+ APP_FULLSCREEN = 10;
+ }
+ optional DeviceState device_state = 5;
+
+ // Whether the Assistant handles were showing at the time of invocation.
+ optional bool assistant_handles_showing = 6;
+}
diff --git a/cmds/statsd/src/metrics/MetricProducer.cpp b/cmds/statsd/src/metrics/MetricProducer.cpp
index cdd20cdd70f9..fe143e496373 100644
--- a/cmds/statsd/src/metrics/MetricProducer.cpp
+++ b/cmds/statsd/src/metrics/MetricProducer.cpp
@@ -98,7 +98,7 @@ void MetricProducer::onMatchedLogEventLocked(const size_t matcherIndex, const Lo
// Stores atom id to primary key pairs for each state atom that the metric is
// sliced by.
- std::map<int, HashableDimensionKey> statePrimaryKeys;
+ std::map<int32_t, HashableDimensionKey> statePrimaryKeys;
// For states with primary fields, use MetricStateLinks to get the primary
// field values from the log event. These values will form a primary key
diff --git a/cmds/statsd/src/metrics/ValueMetricProducer.cpp b/cmds/statsd/src/metrics/ValueMetricProducer.cpp
index c0d117402314..8203f38de393 100644
--- a/cmds/statsd/src/metrics/ValueMetricProducer.cpp
+++ b/cmds/statsd/src/metrics/ValueMetricProducer.cpp
@@ -189,11 +189,6 @@ void ValueMetricProducer::onStateChanged(int64_t eventTimeNs, int32_t atomId,
VLOG("ValueMetric %lld onStateChanged time %lld, State %d, key %s, %d -> %d",
(long long)mMetricId, (long long)eventTimeNs, atomId, primaryKey.toString().c_str(),
oldState.mValue.int_value, newState.mValue.int_value);
- // If condition is not true or metric is not active, we do not need to pull
- // for this state change.
- if (mCondition != ConditionState::kTrue || !mIsActive) {
- return;
- }
// If old and new states are in the same StateGroup, then we do not need to
// pull for this state change.
@@ -205,6 +200,12 @@ void ValueMetricProducer::onStateChanged(int64_t eventTimeNs, int32_t atomId,
return;
}
+ // If condition is not true or metric is not active, we do not need to pull
+ // for this state change.
+ if (mCondition != ConditionState::kTrue || !mIsActive) {
+ return;
+ }
+
bool isEventLate = eventTimeNs < mCurrentBucketStartTimeNs;
if (isEventLate) {
VLOG("Skip event due to late arrival: %lld vs %lld", (long long)eventTimeNs,
@@ -412,7 +413,6 @@ void ValueMetricProducer::resetBase() {
for (auto& slice : mCurrentBaseInfo) {
for (auto& baseInfo : slice.second) {
baseInfo.hasBase = false;
- baseInfo.hasCurrentState = false;
}
}
mHasGlobalBase = false;
@@ -625,7 +625,6 @@ void ValueMetricProducer::accumulateEvents(const std::vector<std::shared_ptr<Log
auto it = mCurrentBaseInfo.find(whatKey);
for (auto& baseInfo : it->second) {
baseInfo.hasBase = false;
- baseInfo.hasCurrentState = false;
}
}
}
@@ -820,6 +819,8 @@ void ValueMetricProducer::onMatchedLogEventInternalLocked(
Interval& interval = intervals[i];
interval.valueIndex = i;
Value value;
+ baseInfo.hasCurrentState = true;
+ baseInfo.currentState = stateKey;
if (!getDoubleOrLong(event, matcher, value)) {
VLOG("Failed to get value %d from event %s", i, event.ToString().c_str());
StatsdStats::getInstance().noteBadValueType(mMetricId);
@@ -907,7 +908,6 @@ void ValueMetricProducer::onMatchedLogEventInternalLocked(
interval.hasValue = true;
}
interval.sampleSize += 1;
- baseInfo.currentState = stateKey;
}
// Only trigger the tracker if all intervals are correct
diff --git a/cmds/statsd/src/metrics/ValueMetricProducer.h b/cmds/statsd/src/metrics/ValueMetricProducer.h
index 3de5b99a2b09..b359af745c91 100644
--- a/cmds/statsd/src/metrics/ValueMetricProducer.h
+++ b/cmds/statsd/src/metrics/ValueMetricProducer.h
@@ -75,7 +75,7 @@ public:
if (!mSplitBucketForAppUpgrade) {
return;
}
- if (mIsPulled && mCondition) {
+ if (mIsPulled && mCondition == ConditionState::kTrue) {
pullAndMatchEventsLocked(eventTimeNs);
}
flushCurrentBucketLocked(eventTimeNs, eventTimeNs);
@@ -84,7 +84,7 @@ public:
// ValueMetric needs special logic if it's a pulled atom.
void onStatsdInitCompleted(const int64_t& eventTimeNs) override {
std::lock_guard<std::mutex> lock(mMutex);
- if (mIsPulled && mCondition) {
+ if (mIsPulled && mCondition == ConditionState::kTrue) {
pullAndMatchEventsLocked(eventTimeNs);
}
flushCurrentBucketLocked(eventTimeNs, eventTimeNs);
@@ -313,6 +313,7 @@ private:
FRIEND_TEST(ValueMetricProducerTest, TestSlicedState);
FRIEND_TEST(ValueMetricProducerTest, TestSlicedStateWithMap);
FRIEND_TEST(ValueMetricProducerTest, TestSlicedStateWithPrimaryField_WithDimensions);
+ FRIEND_TEST(ValueMetricProducerTest, TestSlicedStateWithCondition);
FRIEND_TEST(ValueMetricProducerTest, TestTrimUnusedDimensionKey);
FRIEND_TEST(ValueMetricProducerTest, TestUseZeroDefaultBase);
FRIEND_TEST(ValueMetricProducerTest, TestUseZeroDefaultBaseWithPullFailures);
diff --git a/cmds/statsd/src/statsd_config.proto b/cmds/statsd/src/statsd_config.proto
index 72decf2c7bd0..acdffd3d4712 100644
--- a/cmds/statsd/src/statsd_config.proto
+++ b/cmds/statsd/src/statsd_config.proto
@@ -198,6 +198,9 @@ message EventMetric {
optional int64 condition = 3;
repeated MetricConditionLink links = 4;
+
+ reserved 100;
+ reserved 101;
}
message CountMetric {
@@ -218,6 +221,9 @@ message CountMetric {
repeated MetricStateLink state_link = 9;
optional FieldMatcher dimensions_in_condition = 7 [deprecated = true];
+
+ reserved 100;
+ reserved 101;
}
message DurationMetric {
@@ -245,6 +251,9 @@ message DurationMetric {
optional TimeUnit bucket = 7;
optional FieldMatcher dimensions_in_condition = 8 [deprecated = true];
+
+ reserved 100;
+ reserved 101;
}
message GaugeMetric {
@@ -281,6 +290,9 @@ message GaugeMetric {
optional int32 max_pull_delay_sec = 13 [default = 30];
optional bool split_bucket_for_app_upgrade = 14 [default = true];
+
+ reserved 100;
+ reserved 101;
}
message ValueMetric {
@@ -333,6 +345,9 @@ message ValueMetric {
optional bool split_bucket_for_app_upgrade = 17 [default = true];
optional FieldMatcher dimensions_in_condition = 9 [deprecated = true];
+
+ reserved 100;
+ reserved 101;
}
message Alert {
diff --git a/cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp b/cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp
index 1bcc35d99d18..f0419964e892 100644
--- a/cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp
+++ b/cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp
@@ -167,6 +167,32 @@ public:
return valueProducer;
}
+ static sp<ValueMetricProducer> createValueProducerWithConditionAndState(
+ sp<MockStatsPullerManager>& pullerManager, ValueMetric& metric,
+ vector<int32_t> slicedStateAtoms,
+ unordered_map<int, unordered_map<int, int64_t>> stateGroupMap,
+ ConditionState conditionAfterFirstBucketPrepared) {
+ UidMap uidMap;
+ SimpleAtomMatcher atomMatcher;
+ atomMatcher.set_atom_id(tagId);
+ sp<EventMatcherWizard> eventMatcherWizard =
+ new EventMatcherWizard({new SimpleLogMatchingTracker(
+ atomMatcherId, logEventMatcherIndex, atomMatcher, uidMap)});
+ sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
+ EXPECT_CALL(*pullerManager, RegisterReceiver(tagId, kConfigKey, _, _, _))
+ .WillOnce(Return());
+ EXPECT_CALL(*pullerManager, UnRegisterReceiver(tagId, kConfigKey, _))
+ .WillRepeatedly(Return());
+
+ sp<ValueMetricProducer> valueProducer = new ValueMetricProducer(
+ kConfigKey, metric, 0 /* condition tracker index */, {ConditionState::kUnknown},
+ wizard, logEventMatcherIndex, eventMatcherWizard, tagId, bucketStartTimeNs,
+ bucketStartTimeNs, pullerManager, {}, {}, slicedStateAtoms, stateGroupMap);
+ valueProducer->prepareFirstBucket();
+ valueProducer->mCondition = conditionAfterFirstBucketPrepared;
+ return valueProducer;
+ }
+
static ValueMetric createMetric() {
ValueMetric metric;
metric.set_id(metricId);
@@ -188,6 +214,13 @@ public:
metric.add_slice_by_state(StringToId(state));
return metric;
}
+
+ static ValueMetric createMetricWithConditionAndState(string state) {
+ ValueMetric metric = ValueMetricProducerTestHelper::createMetric();
+ metric.set_condition(StringToId("SCREEN_ON"));
+ metric.add_slice_by_state(StringToId(state));
+ return metric;
+ }
};
// Setup for parameterized tests.
@@ -3893,13 +3926,13 @@ TEST(ValueMetricProducerTest, TestSlicedState) {
return true;
}));
+ StateManager::getInstance().clear();
sp<ValueMetricProducer> valueProducer =
ValueMetricProducerTestHelper::createValueProducerWithState(
pullerManager, metric, {util::SCREEN_STATE_CHANGED}, {});
EXPECT_EQ(1, valueProducer->mSlicedStateAtoms.size());
// Set up StateManager and check that StateTrackers are initialized.
- StateManager::getInstance().clear();
StateManager::getInstance().registerListener(SCREEN_STATE_ATOM_ID, valueProducer);
EXPECT_EQ(1, StateManager::getInstance().getStateTrackersCount());
EXPECT_EQ(1, StateManager::getInstance().getListenersCount(SCREEN_STATE_ATOM_ID));
@@ -4105,12 +4138,12 @@ TEST(ValueMetricProducerTest, TestSlicedStateWithMap) {
}
}
+ StateManager::getInstance().clear();
sp<ValueMetricProducer> valueProducer =
ValueMetricProducerTestHelper::createValueProducerWithState(
pullerManager, metric, {util::SCREEN_STATE_CHANGED}, stateGroupMap);
// Set up StateManager and check that StateTrackers are initialized.
- StateManager::getInstance().clear();
StateManager::getInstance().registerListener(SCREEN_STATE_ATOM_ID, valueProducer);
EXPECT_EQ(1, StateManager::getInstance().getStateTrackersCount());
EXPECT_EQ(1, StateManager::getInstance().getListenersCount(SCREEN_STATE_ATOM_ID));
@@ -4357,12 +4390,12 @@ TEST(ValueMetricProducerTest, TestSlicedStateWithPrimaryField_WithDimensions) {
return true;
}));
+ StateManager::getInstance().clear();
sp<ValueMetricProducer> valueProducer =
ValueMetricProducerTestHelper::createValueProducerWithState(
pullerManager, metric, {UID_PROCESS_STATE_ATOM_ID}, {});
// Set up StateManager and check that StateTrackers are initialized.
- StateManager::getInstance().clear();
StateManager::getInstance().registerListener(UID_PROCESS_STATE_ATOM_ID, valueProducer);
EXPECT_EQ(1, StateManager::getInstance().getStateTrackersCount());
EXPECT_EQ(1, StateManager::getInstance().getListenersCount(UID_PROCESS_STATE_ATOM_ID));
@@ -4722,6 +4755,212 @@ TEST(ValueMetricProducerTest, TestSlicedStateWithPrimaryField_WithDimensions) {
EXPECT_EQ(5, report.value_metrics().data(4).bucket_info(1).values(0).value_long());
}
+TEST(ValueMetricProducerTest, TestSlicedStateWithCondition) {
+ // Set up ValueMetricProducer.
+ ValueMetric metric = ValueMetricProducerTestHelper::createMetricWithConditionAndState(
+ "BATTERY_SAVER_MODE_STATE");
+ sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
+ EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, _, _, _))
+ // Condition changed to true.
+ .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
+ vector<std::shared_ptr<LogEvent>>* data, bool) {
+ EXPECT_EQ(eventTimeNs, bucketStartTimeNs + 20 * NS_PER_SEC);
+ data->clear();
+ data->push_back(
+ CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs + 20 * NS_PER_SEC, 3));
+ return true;
+ }))
+ // Battery saver mode state changed to OFF.
+ .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
+ vector<std::shared_ptr<LogEvent>>* data, bool) {
+ EXPECT_EQ(eventTimeNs, bucketStartTimeNs + 30 * NS_PER_SEC);
+ data->clear();
+ data->push_back(
+ CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs + 30 * NS_PER_SEC, 5));
+ return true;
+ }))
+ // Condition changed to false.
+ .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
+ vector<std::shared_ptr<LogEvent>>* data, bool) {
+ EXPECT_EQ(eventTimeNs, bucket2StartTimeNs + 10 * NS_PER_SEC);
+ data->clear();
+ data->push_back(CreateRepeatedValueLogEvent(
+ tagId, bucket2StartTimeNs + 10 * NS_PER_SEC, 15));
+ return true;
+ }));
+
+ StateManager::getInstance().clear();
+ sp<ValueMetricProducer> valueProducer =
+ ValueMetricProducerTestHelper::createValueProducerWithConditionAndState(
+ pullerManager, metric, {util::BATTERY_SAVER_MODE_STATE_CHANGED}, {},
+ ConditionState::kFalse);
+ EXPECT_EQ(1, valueProducer->mSlicedStateAtoms.size());
+
+ // Set up StateManager and check that StateTrackers are initialized.
+ StateManager::getInstance().registerListener(util::BATTERY_SAVER_MODE_STATE_CHANGED,
+ valueProducer);
+ EXPECT_EQ(1, StateManager::getInstance().getStateTrackersCount());
+ EXPECT_EQ(1, StateManager::getInstance().getListenersCount(
+ util::BATTERY_SAVER_MODE_STATE_CHANGED));
+
+ // Bucket status after battery saver mode ON event.
+ // Condition is false so we do nothing.
+ unique_ptr<LogEvent> batterySaverOnEvent =
+ CreateBatterySaverOnEvent(/*timestamp=*/bucketStartTimeNs + 10 * NS_PER_SEC);
+ StateManager::getInstance().onLogEvent(*batterySaverOnEvent);
+ EXPECT_EQ(0UL, valueProducer->mCurrentSlicedBucket.size());
+ EXPECT_EQ(0UL, valueProducer->mCurrentBaseInfo.size());
+
+ // Bucket status after condition change to true.
+ valueProducer->onConditionChanged(true, bucketStartTimeNs + 20 * NS_PER_SEC);
+ // Base for dimension key {}
+ ASSERT_EQ(1UL, valueProducer->mCurrentBaseInfo.size());
+ std::unordered_map<HashableDimensionKey, std::vector<ValueMetricProducer::BaseInfo>>::iterator
+ itBase = valueProducer->mCurrentBaseInfo.find(DEFAULT_DIMENSION_KEY);
+ EXPECT_TRUE(itBase->second[0].hasBase);
+ EXPECT_EQ(3, itBase->second[0].base.long_value);
+ EXPECT_TRUE(itBase->second[0].hasCurrentState);
+ ASSERT_EQ(1, itBase->second[0].currentState.getValues().size());
+ EXPECT_EQ(BatterySaverModeStateChanged::ON,
+ itBase->second[0].currentState.getValues()[0].mValue.int_value);
+ // Value for key {{}, -1}
+ ASSERT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
+ std::unordered_map<MetricDimensionKey, std::vector<ValueMetricProducer::Interval>>::iterator
+ it = valueProducer->mCurrentSlicedBucket.begin();
+ EXPECT_EQ(0, it->first.getDimensionKeyInWhat().getValues().size());
+ ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
+ EXPECT_EQ(-1 /*StateTracker::kUnknown*/,
+ it->first.getStateValuesKey().getValues()[0].mValue.int_value);
+ EXPECT_FALSE(it->second[0].hasValue);
+
+ // Bucket status after battery saver mode OFF event.
+ unique_ptr<LogEvent> batterySaverOffEvent =
+ CreateBatterySaverOffEvent(/*timestamp=*/bucketStartTimeNs + 30 * NS_PER_SEC);
+ StateManager::getInstance().onLogEvent(*batterySaverOffEvent);
+ // Base for dimension key {}
+ ASSERT_EQ(1UL, valueProducer->mCurrentBaseInfo.size());
+ itBase = valueProducer->mCurrentBaseInfo.find(DEFAULT_DIMENSION_KEY);
+ EXPECT_TRUE(itBase->second[0].hasBase);
+ EXPECT_EQ(5, itBase->second[0].base.long_value);
+ EXPECT_TRUE(itBase->second[0].hasCurrentState);
+ ASSERT_EQ(1, itBase->second[0].currentState.getValues().size());
+ EXPECT_EQ(BatterySaverModeStateChanged::OFF,
+ itBase->second[0].currentState.getValues()[0].mValue.int_value);
+ // Value for key {{}, ON}
+ ASSERT_EQ(2UL, valueProducer->mCurrentSlicedBucket.size());
+ it = valueProducer->mCurrentSlicedBucket.begin();
+ EXPECT_EQ(0, it->first.getDimensionKeyInWhat().getValues().size());
+ ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
+ EXPECT_EQ(BatterySaverModeStateChanged::ON,
+ it->first.getStateValuesKey().getValues()[0].mValue.int_value);
+ EXPECT_TRUE(it->second[0].hasValue);
+ EXPECT_EQ(2, it->second[0].value.long_value);
+
+ // Pull at end of first bucket.
+ vector<shared_ptr<LogEvent>> allData;
+ allData.clear();
+ allData.push_back(CreateRepeatedValueLogEvent(tagId, bucket2StartTimeNs, 11));
+ valueProducer->onDataPulled(allData, /** succeed */ true, bucket2StartTimeNs);
+
+ EXPECT_EQ(2UL, valueProducer->mPastBuckets.size());
+ EXPECT_EQ(3UL, valueProducer->mCurrentSlicedBucket.size());
+ // Base for dimension key {}
+ ASSERT_EQ(1UL, valueProducer->mCurrentBaseInfo.size());
+ itBase = valueProducer->mCurrentBaseInfo.find(DEFAULT_DIMENSION_KEY);
+ EXPECT_TRUE(itBase->second[0].hasBase);
+ EXPECT_EQ(11, itBase->second[0].base.long_value);
+ EXPECT_TRUE(itBase->second[0].hasCurrentState);
+ ASSERT_EQ(1, itBase->second[0].currentState.getValues().size());
+ EXPECT_EQ(BatterySaverModeStateChanged::OFF,
+ itBase->second[0].currentState.getValues()[0].mValue.int_value);
+
+ // Bucket 2 status after condition change to false.
+ valueProducer->onConditionChanged(false, bucket2StartTimeNs + 10 * NS_PER_SEC);
+ // Base for dimension key {}
+ ASSERT_EQ(1UL, valueProducer->mCurrentBaseInfo.size());
+ itBase = valueProducer->mCurrentBaseInfo.find(DEFAULT_DIMENSION_KEY);
+ EXPECT_FALSE(itBase->second[0].hasBase);
+ EXPECT_TRUE(itBase->second[0].hasCurrentState);
+ ASSERT_EQ(1, itBase->second[0].currentState.getValues().size());
+ EXPECT_EQ(BatterySaverModeStateChanged::OFF,
+ itBase->second[0].currentState.getValues()[0].mValue.int_value);
+ // Value for key {{}, OFF}
+ ASSERT_EQ(3UL, valueProducer->mCurrentSlicedBucket.size());
+ it = valueProducer->mCurrentSlicedBucket.begin();
+ EXPECT_EQ(0, it->first.getDimensionKeyInWhat().getValues().size());
+ ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
+ EXPECT_EQ(BatterySaverModeStateChanged::OFF,
+ it->first.getStateValuesKey().getValues()[0].mValue.int_value);
+ EXPECT_TRUE(it->second[0].hasValue);
+ EXPECT_EQ(4, it->second[0].value.long_value);
+
+ // Start dump report and check output.
+ ProtoOutputStream output;
+ std::set<string> strSet;
+ valueProducer->onDumpReport(bucket2StartTimeNs + 50 * NS_PER_SEC,
+ true /* include recent buckets */, true, NO_TIME_CONSTRAINTS,
+ &strSet, &output);
+
+ StatsLogReport report = outputStreamToProto(&output);
+ EXPECT_TRUE(report.has_value_metrics());
+ ASSERT_EQ(2, report.value_metrics().data_size());
+
+ ValueMetricData data = report.value_metrics().data(0);
+ EXPECT_EQ(util::BATTERY_SAVER_MODE_STATE_CHANGED, data.slice_by_state(0).atom_id());
+ EXPECT_TRUE(data.slice_by_state(0).has_value());
+ EXPECT_EQ(BatterySaverModeStateChanged::ON, data.slice_by_state(0).value());
+ ASSERT_EQ(1, data.bucket_info_size());
+ EXPECT_EQ(2, data.bucket_info(0).values(0).value_long());
+
+ data = report.value_metrics().data(1);
+ EXPECT_EQ(util::BATTERY_SAVER_MODE_STATE_CHANGED, data.slice_by_state(0).atom_id());
+ EXPECT_TRUE(data.slice_by_state(0).has_value());
+ EXPECT_EQ(BatterySaverModeStateChanged::OFF, data.slice_by_state(0).value());
+ ASSERT_EQ(2, data.bucket_info_size());
+ EXPECT_EQ(6, data.bucket_info(0).values(0).value_long());
+ EXPECT_EQ(4, data.bucket_info(1).values(0).value_long());
+}
+
+/*
+ * Test bucket splits when condition is unknown.
+ */
+TEST(ValueMetricProducerTest, TestForcedBucketSplitWhenConditionUnknownSkipsBucket) {
+ ValueMetric metric = ValueMetricProducerTestHelper::createMetricWithCondition();
+
+ sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
+
+ sp<ValueMetricProducer> valueProducer =
+ ValueMetricProducerTestHelper::createValueProducerWithCondition(
+ pullerManager, metric,
+ ConditionState::kUnknown);
+
+ // App update event.
+ int64_t appUpdateTimeNs = bucketStartTimeNs + 1000;
+ valueProducer->notifyAppUpgrade(appUpdateTimeNs);
+
+ // Check dump report.
+ ProtoOutputStream output;
+ std::set<string> strSet;
+ int64_t dumpReportTimeNs = bucketStartTimeNs + 10000000000; // 10 seconds
+ valueProducer->onDumpReport(dumpReportTimeNs, false /* include current buckets */, true,
+ NO_TIME_CONSTRAINTS /* dumpLatency */, &strSet, &output);
+
+ StatsLogReport report = outputStreamToProto(&output);
+ EXPECT_TRUE(report.has_value_metrics());
+ ASSERT_EQ(0, report.value_metrics().data_size());
+ ASSERT_EQ(1, report.value_metrics().skipped_size());
+
+ EXPECT_EQ(NanoToMillis(bucketStartTimeNs),
+ report.value_metrics().skipped(0).start_bucket_elapsed_millis());
+ EXPECT_EQ(NanoToMillis(appUpdateTimeNs),
+ report.value_metrics().skipped(0).end_bucket_elapsed_millis());
+ ASSERT_EQ(1, report.value_metrics().skipped(0).drop_event_size());
+
+ auto dropEvent = report.value_metrics().skipped(0).drop_event(0);
+ EXPECT_EQ(BucketDropReason::NO_DATA, dropEvent.drop_reason());
+ EXPECT_EQ(NanoToMillis(appUpdateTimeNs), dropEvent.drop_time_millis());
+}
+
} // namespace statsd
} // namespace os
} // namespace android
diff --git a/cmds/statsd/tests/statsd_test_util.cpp b/cmds/statsd/tests/statsd_test_util.cpp
index 06e29d4b5de1..cee83725d075 100644
--- a/cmds/statsd/tests/statsd_test_util.cpp
+++ b/cmds/statsd/tests/statsd_test_util.cpp
@@ -663,6 +663,8 @@ std::unique_ptr<LogEvent> CreateBatterySaverOnEvent(uint64_t timestampNs) {
AStatsEvent_setAtomId(statsEvent, util::BATTERY_SAVER_MODE_STATE_CHANGED);
AStatsEvent_overwriteTimestamp(statsEvent, timestampNs);
AStatsEvent_writeInt32(statsEvent, BatterySaverModeStateChanged::ON);
+ AStatsEvent_addBoolAnnotation(statsEvent, util::ANNOTATION_ID_EXCLUSIVE_STATE, true);
+ AStatsEvent_addBoolAnnotation(statsEvent, util::ANNOTATION_ID_STATE_NESTED, false);
std::unique_ptr<LogEvent> logEvent = std::make_unique<LogEvent>(/*uid=*/0, /*pid=*/0);
parseStatsEventToLogEvent(statsEvent, logEvent.get());
@@ -674,6 +676,8 @@ std::unique_ptr<LogEvent> CreateBatterySaverOffEvent(uint64_t timestampNs) {
AStatsEvent_setAtomId(statsEvent, util::BATTERY_SAVER_MODE_STATE_CHANGED);
AStatsEvent_overwriteTimestamp(statsEvent, timestampNs);
AStatsEvent_writeInt32(statsEvent, BatterySaverModeStateChanged::OFF);
+ AStatsEvent_addBoolAnnotation(statsEvent, util::ANNOTATION_ID_EXCLUSIVE_STATE, true);
+ AStatsEvent_addBoolAnnotation(statsEvent, util::ANNOTATION_ID_STATE_NESTED, false);
std::unique_ptr<LogEvent> logEvent = std::make_unique<LogEvent>(/*uid=*/0, /*pid=*/0);
parseStatsEventToLogEvent(statsEvent, logEvent.get());
diff --git a/core/java/android/accessibilityservice/AccessibilityService.java b/core/java/android/accessibilityservice/AccessibilityService.java
index ed0ea556dc9d..ac00a042b79e 100644
--- a/core/java/android/accessibilityservice/AccessibilityService.java
+++ b/core/java/android/accessibilityservice/AccessibilityService.java
@@ -520,6 +520,12 @@ public abstract class AccessibilityService extends Service {
*/
public static final int GLOBAL_ACTION_ACCESSIBILITY_SHORTCUT = 13;
+ /**
+ * Action to show Launcher's all apps.
+ * @hide
+ */
+ public static final int GLOBAL_ACTION_ACCESSIBILITY_ALL_APPS = 14;
+
private static final String LOG_TAG = "AccessibilityService";
/**
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index 87fc8fe392f0..22a63d9b486b 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -5151,6 +5151,10 @@ public class Activity extends ContextThemeWrapper
* the signature of the app declaring the permissions.
* </p>
* <p>
+ * Call {@link #shouldShowRequestPermissionRationale(String)} before calling this API to
+ * check if the system recommends to show a rationale UI before asking for a permission.
+ * </p>
+ * <p>
* If your app does not have the requested permissions the user will be presented
* with UI for accepting them. After the user has accepted or rejected the
* requested permissions you will receive a callback on {@link
@@ -5240,20 +5244,10 @@ public class Activity extends ContextThemeWrapper
}
/**
- * Gets whether you should show UI with rationale for requesting a permission.
- * You should do this only if you do not have the permission and the context in
- * which the permission is requested does not clearly communicate to the user
- * what would be the benefit from granting this permission.
- * <p>
- * For example, if you write a camera app, requesting the camera permission
- * would be expected by the user and no rationale for why it is requested is
- * needed. If however, the app needs location for tagging photos then a non-tech
- * savvy user may wonder how location is related to taking photos. In this case
- * you may choose to show UI with rationale of requesting this permission.
- * </p>
+ * Gets whether you should show UI with rationale before requesting a permission.
*
* @param permission A permission your app wants to request.
- * @return Whether you can show permission rationale UI.
+ * @return Whether you should show permission rationale UI.
*
* @see #checkSelfPermission(String)
* @see #requestPermissions(String[], int)
@@ -5568,7 +5562,7 @@ public class Activity extends ContextThemeWrapper
options = transferSpringboardActivityOptions(options);
String resolvedType = null;
if (fillInIntent != null) {
- fillInIntent.migrateExtraStreamToClipData();
+ fillInIntent.migrateExtraStreamToClipData(this);
fillInIntent.prepareToLeaveProcess(this);
resolvedType = fillInIntent.resolveTypeIfNeeded(getContentResolver());
}
@@ -5823,7 +5817,7 @@ public class Activity extends ContextThemeWrapper
if (referrer != null) {
intent.putExtra(Intent.EXTRA_REFERRER, referrer);
}
- intent.migrateExtraStreamToClipData();
+ intent.migrateExtraStreamToClipData(this);
intent.prepareToLeaveProcess(this);
result = ActivityTaskManager.getService()
.startActivity(mMainThread.getApplicationThread(), getBasePackageName(),
@@ -5894,7 +5888,7 @@ public class Activity extends ContextThemeWrapper
@Nullable Bundle options) {
if (mParent == null) {
try {
- intent.migrateExtraStreamToClipData();
+ intent.migrateExtraStreamToClipData(this);
intent.prepareToLeaveProcess(this);
return ActivityTaskManager.getService()
.startNextMatchingActivity(mToken, intent, options);
diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java
index 97b704ccc1c9..b608a343fc7d 100644
--- a/core/java/android/app/ActivityManager.java
+++ b/core/java/android/app/ActivityManager.java
@@ -601,20 +601,6 @@ public class ActivityManager {
@TestApi
public static final int PROCESS_CAPABILITY_FOREGROUND_MICROPHONE = 1 << 2;
- // TODO: remove this when development is done.
- // These are debug flags used between OomAdjuster and AppOpsService to detect and report absence
- // of the real flags.
- /** @hide */
- public static final int DEBUG_PROCESS_CAPABILITY_FOREGROUND_MICROPHONE_Q = 1 << 27;
- /** @hide */
- public static final int DEBUG_PROCESS_CAPABILITY_FOREGROUND_CAMERA_Q = 1 << 28;
- /** @hide */
- public static final int DEBUG_PROCESS_CAPABILITY_FOREGROUND_MICROPHONE = 1 << 29;
- /** @hide */
- public static final int DEBUG_PROCESS_CAPABILITY_FOREGROUND_CAMERA = 1 << 30;
- /** @hide */
- public static final int DEBUG_PROCESS_CAPABILITY_FOREGROUND_LOCATION = 1 << 31;
-
/** @hide all capabilities, the ORing of all flags in {@link ProcessCapability}*/
@TestApi
public static final int PROCESS_CAPABILITY_ALL = PROCESS_CAPABILITY_FOREGROUND_LOCATION
@@ -653,29 +639,9 @@ public class ActivityManager {
*/
public static void printCapabilitiesFull(PrintWriter pw, @ProcessCapability int caps) {
printCapabilitiesSummary(pw, caps);
- if ((caps & DEBUG_PROCESS_CAPABILITY_FOREGROUND_LOCATION) != 0) {
- pw.print(" !L");
- }
- if ((caps & DEBUG_PROCESS_CAPABILITY_FOREGROUND_CAMERA) != 0) {
- pw.print(" !C");
- }
- if ((caps & DEBUG_PROCESS_CAPABILITY_FOREGROUND_CAMERA_Q) != 0) {
- pw.print(" !Cq");
- }
- if ((caps & DEBUG_PROCESS_CAPABILITY_FOREGROUND_MICROPHONE) != 0) {
- pw.print(" !M");
- }
- if ((caps & DEBUG_PROCESS_CAPABILITY_FOREGROUND_MICROPHONE_Q) != 0) {
- pw.print(" !Mq");
- }
final int remain = caps & ~(PROCESS_CAPABILITY_FOREGROUND_LOCATION
| PROCESS_CAPABILITY_FOREGROUND_CAMERA
- | PROCESS_CAPABILITY_FOREGROUND_MICROPHONE
- | DEBUG_PROCESS_CAPABILITY_FOREGROUND_LOCATION
- | DEBUG_PROCESS_CAPABILITY_FOREGROUND_CAMERA
- | DEBUG_PROCESS_CAPABILITY_FOREGROUND_CAMERA_Q
- | DEBUG_PROCESS_CAPABILITY_FOREGROUND_MICROPHONE
- | DEBUG_PROCESS_CAPABILITY_FOREGROUND_MICROPHONE_Q);
+ | PROCESS_CAPABILITY_FOREGROUND_MICROPHONE);
if (remain != 0) {
pw.print('+');
pw.print(remain);
diff --git a/core/java/android/app/ActivityManagerInternal.java b/core/java/android/app/ActivityManagerInternal.java
index c491eea7a674..a5965bc7f85f 100644
--- a/core/java/android/app/ActivityManagerInternal.java
+++ b/core/java/android/app/ActivityManagerInternal.java
@@ -398,13 +398,6 @@ public abstract class ActivityManagerInternal {
*/
public abstract boolean isUidCurrentlyInstrumented(int uid);
- /**
- * Show a debug toast, asking user to file a bugreport.
- */
- // TODO: remove this toast after feature development is done
- public abstract void showWhileInUseDebugToast(int uid, int op, int mode);
-
-
/** Is this a device owner app? */
public abstract boolean isDeviceOwner(int uid);
@@ -429,11 +422,17 @@ public abstract class ActivityManagerInternal {
int userId, int[] appIdWhitelist);
/**
- * Add or delete uid from the ActivityManagerService PendingStartActivityUids list.
+ * Add uid to the ActivityManagerService PendingStartActivityUids list.
+ * @param uid uid
+ * @param pid pid of the ProcessRecord that is pending top.
+ */
+ public abstract void addPendingTopUid(int uid, int pid);
+
+ /**
+ * Delete uid from the ActivityManagerService PendingStartActivityUids list.
* @param uid uid
- * @param pending add to the list if true, delete from list if false.
*/
- public abstract void updatePendingTopUid(int uid, boolean pending);
+ public abstract void deletePendingTopUid(int uid);
/**
* Is the uid in ActivityManagerService PendingStartActivityUids list?
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index cffa59c06a53..812ca4aefb9b 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -123,6 +123,7 @@ import android.os.SystemProperties;
import android.os.TelephonyServiceManager;
import android.os.Trace;
import android.os.UserHandle;
+import android.os.UserManager;
import android.permission.IPermissionManager;
import android.provider.BlockedNumberContract;
import android.provider.CalendarContract;
@@ -3252,18 +3253,56 @@ public final class ActivityThread extends ClientTransactionHandler {
@Override
public void handleFixedRotationAdjustments(@NonNull IBinder token,
@Nullable FixedRotationAdjustments fixedRotationAdjustments) {
- final Consumer<DisplayAdjustments> override = fixedRotationAdjustments != null
- ? displayAdjustments -> displayAdjustments.setFixedRotationAdjustments(
- fixedRotationAdjustments)
- : null;
+ handleFixedRotationAdjustments(token, fixedRotationAdjustments, null /* overrideConfig */);
+ }
+
+ /**
+ * Applies the rotation adjustments to override display information in resources belong to the
+ * provided token. If the token is activity token, the adjustments also apply to application
+ * because the appearance of activity is usually more sensitive to the application resources.
+ *
+ * @param token The token to apply the adjustments.
+ * @param fixedRotationAdjustments The information to override the display adjustments of
+ * corresponding resources. If it is null, the exiting override
+ * will be cleared.
+ * @param overrideConfig The override configuration of activity. It is used to override
+ * application configuration. If it is non-null, it means the token is
+ * confirmed as activity token. Especially when launching new activity,
+ * {@link #mActivities} hasn't put the new token.
+ */
+ private void handleFixedRotationAdjustments(@NonNull IBinder token,
+ @Nullable FixedRotationAdjustments fixedRotationAdjustments,
+ @Nullable Configuration overrideConfig) {
+ // The element of application configuration override is set only if the application
+ // adjustments are needed, because activity already has its own override configuration.
+ final Configuration[] appConfigOverride;
+ final Consumer<DisplayAdjustments> override;
+ if (fixedRotationAdjustments != null) {
+ appConfigOverride = new Configuration[1];
+ override = displayAdjustments -> {
+ displayAdjustments.setFixedRotationAdjustments(fixedRotationAdjustments);
+ if (appConfigOverride[0] != null) {
+ displayAdjustments.getConfiguration().updateFrom(appConfigOverride[0]);
+ }
+ };
+ } else {
+ appConfigOverride = null;
+ override = null;
+ }
if (!mResourcesManager.overrideTokenDisplayAdjustments(token, override)) {
// No resources are associated with the token.
return;
}
- if (mActivities.get(token) == null) {
- // Only apply the override to application for activity token because the appearance of
- // activity is usually more sensitive to the application resources.
- return;
+ if (overrideConfig == null) {
+ final ActivityClientRecord r = mActivities.get(token);
+ if (r == null) {
+ // It is not an activity token. Nothing to do for application.
+ return;
+ }
+ overrideConfig = r.overrideConfig;
+ }
+ if (appConfigOverride != null) {
+ appConfigOverride[0] = overrideConfig;
}
// Apply the last override to application resources for compatibility. Because the Resources
@@ -3503,7 +3542,8 @@ public final class ActivityThread extends ClientTransactionHandler {
// The rotation adjustments must be applied before creating the activity, so the activity
// can get the adjusted display info during creation.
if (r.mPendingFixedRotationAdjustments != null) {
- handleFixedRotationAdjustments(r.token, r.mPendingFixedRotationAdjustments);
+ handleFixedRotationAdjustments(r.token, r.mPendingFixedRotationAdjustments,
+ r.overrideConfig);
r.mPendingFixedRotationAdjustments = null;
}
@@ -6777,7 +6817,11 @@ public final class ActivityThread extends ClientTransactionHandler {
throw ex.rethrowFromSystemServer();
}
if (holder == null) {
- Slog.e(TAG, "Failed to find provider info for " + auth);
+ if (UserManager.get(c).isUserUnlocked(userId)) {
+ Slog.e(TAG, "Failed to find provider info for " + auth);
+ } else {
+ Slog.w(TAG, "Failed to find provider info for " + auth + " (user not unlocked)");
+ }
return null;
}
@@ -7388,6 +7432,10 @@ public final class ActivityThread extends ClientTransactionHandler {
}
}
+ public Bundle getCoreSettings() {
+ return mCoreSettings;
+ }
+
public int getIntCoreSetting(String key, int defaultValue) {
synchronized (mResourcesManager) {
if (mCoreSettings != null) {
@@ -7397,6 +7445,18 @@ public final class ActivityThread extends ClientTransactionHandler {
}
}
+ /**
+ * Get the string value of the given key from core settings.
+ */
+ public String getStringCoreSetting(String key, String defaultValue) {
+ synchronized (mResourcesManager) {
+ if (mCoreSettings != null) {
+ return mCoreSettings.getString(key, defaultValue);
+ }
+ return defaultValue;
+ }
+ }
+
float getFloatCoreSetting(String key, float defaultValue) {
synchronized (mResourcesManager) {
if (mCoreSettings != null) {
diff --git a/core/java/android/app/ActivityView.java b/core/java/android/app/ActivityView.java
index 635ed138cc65..d650bbcdfa33 100644
--- a/core/java/android/app/ActivityView.java
+++ b/core/java/android/app/ActivityView.java
@@ -102,6 +102,14 @@ public class ActivityView extends ViewGroup implements android.window.TaskEmbedd
public ActivityView(
@NonNull Context context, @NonNull AttributeSet attrs, int defStyle,
boolean singleTaskInstance, boolean usePublicVirtualDisplay) {
+ this(context, attrs, defStyle, singleTaskInstance, usePublicVirtualDisplay, false);
+ }
+
+ /** @hide */
+ public ActivityView(
+ @NonNull Context context, @NonNull AttributeSet attrs, int defStyle,
+ boolean singleTaskInstance, boolean usePublicVirtualDisplay,
+ boolean disableSurfaceViewBackgroundLayer) {
super(context, attrs, defStyle);
if (useTaskOrganizer()) {
mTaskEmbedder = new TaskOrganizerTaskEmbedder(context, this);
@@ -109,7 +117,7 @@ public class ActivityView extends ViewGroup implements android.window.TaskEmbedd
mTaskEmbedder = new VirtualDisplayTaskEmbedder(context, this, singleTaskInstance,
usePublicVirtualDisplay);
}
- mSurfaceView = new SurfaceView(context);
+ mSurfaceView = new SurfaceView(context, null, 0, 0, disableSurfaceViewBackgroundLayer);
// Since ActivityView#getAlpha has been overridden, we should use parent class's alpha
// as master to synchronize surface view's alpha value.
mSurfaceView.setAlpha(super.getAlpha());
diff --git a/core/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java
index b058dcd714dd..ddc57474a027 100644
--- a/core/java/android/app/AppOpsManager.java
+++ b/core/java/android/app/AppOpsManager.java
@@ -182,6 +182,8 @@ public class AppOpsManager {
@EnabledAfter(targetSdkVersion = Build.VERSION_CODES.Q)
public static final long CALL_BACK_ON_CHANGED_LISTENER_WITH_SWITCHED_OP_CHANGE = 148180766L;
+ private static final int MAX_UNFORWARDED_OPS = 10;
+
final Context mContext;
@UnsupportedAppUsage
@@ -217,6 +219,17 @@ public class AppOpsManager {
private static @Nullable OnOpNotedCallback sOnOpNotedCallback;
/**
+ * Sync note-ops collected from {@link #readAndLogNotedAppops(Parcel)} that have not been
+ * delivered to a callback yet.
+ *
+ * Similar to {@link com.android.server.appop.AppOpsService#mUnforwardedAsyncNotedOps} for
+ * {@link COLLECT_ASYNC}. Used in situation when AppOpsManager asks to collect stacktrace with
+ * {@link #sMessageCollector}, which forces {@link COLLECT_SYNC} mode.
+ */
+ @GuardedBy("sLock")
+ private static ArrayList<SyncNotedAppOp> sUnforwardedOps = new ArrayList<>();
+
+ /**
* Additional collector that collect accesses and forwards a few of them them via
* {@link IAppOpsService#reportRuntimeAppOpAccessMessageAndGetConfig}.
*/
@@ -8163,6 +8176,11 @@ public class AppOpsManager {
code = notedAppOps.nextSetBit(code + 1)) {
if (sOnOpNotedCallback != null) {
sOnOpNotedCallback.onNoted(new SyncNotedAppOp(code, attributionTag));
+ } else {
+ sUnforwardedOps.add(new SyncNotedAppOp(code, attributionTag));
+ if (sUnforwardedOps.size() > MAX_UNFORWARDED_OPS) {
+ sUnforwardedOps.remove(0);
+ }
}
}
}
@@ -8229,6 +8247,17 @@ public class AppOpsManager {
}
}
}
+ synchronized (this) {
+ int numMissedSyncOps = sUnforwardedOps.size();
+ for (int i = 0; i < numMissedSyncOps; i++) {
+ final SyncNotedAppOp syncNotedAppOp = sUnforwardedOps.get(i);
+ if (sOnOpNotedCallback != null) {
+ sOnOpNotedCallback.getAsyncNotedExecutor().execute(
+ () -> sOnOpNotedCallback.onNoted(syncNotedAppOp));
+ }
+ }
+ sUnforwardedOps.clear();
+ }
}
}
}
@@ -8577,6 +8606,25 @@ public class AppOpsManager {
}
/**
+ * Reboots the ops history.
+ *
+ * @param offlineDurationMillis The duration to wait between
+ * tearing down and initializing the history. Must be greater
+ * than or equal to zero.
+ *
+ * @hide
+ */
+ @TestApi
+ @RequiresPermission(Manifest.permission.MANAGE_APPOPS)
+ public void rebootHistory(long offlineDurationMillis) {
+ try {
+ mService.rebootHistory(offlineDurationMillis);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
* Pulls current AppOps access report and picks package and op to watch for next access report
* Returns null if no reports were collected since last call. There is no guarantee of report
* collection, hence this method should be called periodically even if no report was collected
diff --git a/core/java/android/app/ApplicationPackageManager.java b/core/java/android/app/ApplicationPackageManager.java
index 6bd8fd7c6ecf..6f8233d5de9b 100644
--- a/core/java/android/app/ApplicationPackageManager.java
+++ b/core/java/android/app/ApplicationPackageManager.java
@@ -139,6 +139,10 @@ public class ApplicationPackageManager extends PackageManager {
public static final String APP_PERMISSION_BUTTON_ALLOW_ALWAYS =
"app_permission_button_allow_always";
+ // Name of the package which the permission controller's resources are in.
+ public static final String PERMISSION_CONTROLLER_RESOURCE_PACKAGE =
+ "com.android.permissioncontroller";
+
private final Object mLock = new Object();
@GuardedBy("mLock")
@@ -893,8 +897,7 @@ public class ApplicationPackageManager extends PackageManager {
mContext.createPackageContext(permissionController, 0);
int textId = context.getResources().getIdentifier(APP_PERMISSION_BUTTON_ALLOW_ALWAYS,
- "string", "com.android.permissioncontroller");
-// permissionController); STOPSHIP b/147434671
+ "string", PERMISSION_CONTROLLER_RESOURCE_PACKAGE);
if (textId != 0) {
return context.getText(textId);
}
diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java
index 48160e475d50..86a3579effe1 100644
--- a/core/java/android/app/ContextImpl.java
+++ b/core/java/android/app/ContextImpl.java
@@ -1087,7 +1087,7 @@ class ContextImpl extends Context {
try {
String resolvedType = null;
if (fillInIntent != null) {
- fillInIntent.migrateExtraStreamToClipData();
+ fillInIntent.migrateExtraStreamToClipData(this);
fillInIntent.prepareToLeaveProcess(this);
resolvedType = fillInIntent.resolveTypeIfNeeded(getContentResolver());
}
diff --git a/core/java/android/app/Fragment.java b/core/java/android/app/Fragment.java
index c6a0de458df0..e4e5ba37ddbf 100644
--- a/core/java/android/app/Fragment.java
+++ b/core/java/android/app/Fragment.java
@@ -1179,6 +1179,10 @@ public class Fragment implements ComponentCallbacks2, OnCreateContextMenuListene
* the signature of the app declaring the permissions.
* </p>
* <p>
+ * Call {@link #shouldShowRequestPermissionRationale(String)} before calling this API
+ * to check if the system recommends to show a rationale UI before asking for a permission.
+ * </p>
+ * <p>
* If your app does not have the requested permissions the user will be presented
* with UI for accepting them. After the user has accepted or rejected the
* requested permissions you will receive a callback on {@link
@@ -1213,29 +1217,6 @@ public class Fragment implements ComponentCallbacks2, OnCreateContextMenuListene
* <code>true</code> because in this case the activity would not receive
* result callbacks including {@link #onRequestPermissionsResult(int, String[], int[])}.
* </p>
- * <p>
- * A sample permissions request looks like this:
- * </p>
- * <code><pre><p>
- * private void showContacts() {
- * if (getActivity().checkSelfPermission(Manifest.permission.READ_CONTACTS)
- * != PackageManager.PERMISSION_GRANTED) {
- * requestPermissions(new String[]{Manifest.permission.READ_CONTACTS},
- * PERMISSIONS_REQUEST_READ_CONTACTS);
- * } else {
- * doShowContacts();
- * }
- * }
- *
- * {@literal @}Override
- * public void onRequestPermissionsResult(int requestCode, String[] permissions,
- * int[] grantResults) {
- * if (requestCode == PERMISSIONS_REQUEST_READ_CONTACTS
- * && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
- * doShowContacts();
- * }
- * }
- * </code></pre></p>
*
* @param permissions The requested permissions. Must me non-null and not empty.
* @param requestCode Application specific request code to match with a result
@@ -1275,20 +1256,10 @@ public class Fragment implements ComponentCallbacks2, OnCreateContextMenuListene
}
/**
- * Gets whether you should show UI with rationale for requesting a permission.
- * You should do this only if you do not have the permission and the context in
- * which the permission is requested does not clearly communicate to the user
- * what would be the benefit from granting this permission.
- * <p>
- * For example, if you write a camera app, requesting the camera permission
- * would be expected by the user and no rationale for why it is requested is
- * needed. If however, the app needs location for tagging photos then a non-tech
- * savvy user may wonder how location is related to taking photos. In this case
- * you may choose to show UI with rationale of requesting this permission.
- * </p>
+ * Gets whether you should show UI with rationale before requesting a permission.
*
* @param permission A permission your app wants to request.
- * @return Whether you can show permission rationale UI.
+ * @return Whether you should show permission rationale UI.
*
* @see Context#checkSelfPermission(String)
* @see #requestPermissions(String[], int)
diff --git a/core/java/android/app/ITaskStackListener.aidl b/core/java/android/app/ITaskStackListener.aidl
index 2d06ee8d06bc..aec9f3e98960 100644
--- a/core/java/android/app/ITaskStackListener.aidl
+++ b/core/java/android/app/ITaskStackListener.aidl
@@ -216,4 +216,16 @@ oneway interface ITaskStackListener {
* in {@link android.content.pm.ActivityInfo}.
*/
void onTaskRequestedOrientationChanged(int taskId, int requestedOrientation);
+
+ /**
+ * Called when a rotation is about to start on the foreground activity.
+ * This applies for:
+ * * free sensor rotation
+ * * forced rotation
+ * * rotation settings set through adb command line
+ * * rotation that occurs when rotation tile is toggled in quick settings
+ *
+ * @param displayId id of the display where activity will rotate
+ */
+ void onActivityRotation(int displayId);
}
diff --git a/core/java/android/app/Instrumentation.java b/core/java/android/app/Instrumentation.java
index e233adeb3f65..721525d9af9d 100644
--- a/core/java/android/app/Instrumentation.java
+++ b/core/java/android/app/Instrumentation.java
@@ -1718,7 +1718,7 @@ public class Instrumentation {
}
}
try {
- intent.migrateExtraStreamToClipData();
+ intent.migrateExtraStreamToClipData(who);
intent.prepareToLeaveProcess(who);
int result = ActivityTaskManager.getService().startActivity(whoThread,
who.getBasePackageName(), who.getAttributionTag(), intent,
@@ -1788,7 +1788,7 @@ public class Instrumentation {
try {
String[] resolvedTypes = new String[intents.length];
for (int i=0; i<intents.length; i++) {
- intents[i].migrateExtraStreamToClipData();
+ intents[i].migrateExtraStreamToClipData(who);
intents[i].prepareToLeaveProcess(who);
resolvedTypes[i] = intents[i].resolveTypeIfNeeded(who.getContentResolver());
}
@@ -1857,7 +1857,7 @@ public class Instrumentation {
}
}
try {
- intent.migrateExtraStreamToClipData();
+ intent.migrateExtraStreamToClipData(who);
intent.prepareToLeaveProcess(who);
int result = ActivityTaskManager.getService().startActivity(whoThread,
who.getBasePackageName(), who.getAttributionTag(), intent,
@@ -1924,7 +1924,7 @@ public class Instrumentation {
}
}
try {
- intent.migrateExtraStreamToClipData();
+ intent.migrateExtraStreamToClipData(who);
intent.prepareToLeaveProcess(who);
int result = ActivityTaskManager.getService().startActivityAsUser(whoThread,
who.getBasePackageName(), who.getAttributionTag(), intent,
@@ -1970,7 +1970,7 @@ public class Instrumentation {
}
}
try {
- intent.migrateExtraStreamToClipData();
+ intent.migrateExtraStreamToClipData(who);
intent.prepareToLeaveProcess(who);
int result = ActivityTaskManager.getService()
.startActivityAsCaller(whoThread, who.getBasePackageName(), intent,
@@ -2017,7 +2017,7 @@ public class Instrumentation {
}
}
try {
- intent.migrateExtraStreamToClipData();
+ intent.migrateExtraStreamToClipData(who);
intent.prepareToLeaveProcess(who);
int result = appTask.startActivity(whoThread.asBinder(), who.getBasePackageName(),
who.getAttributionTag(), intent,
diff --git a/core/java/android/app/LoadedApk.java b/core/java/android/app/LoadedApk.java
index 10f7835b3d69..f9b48e710148 100644
--- a/core/java/android/app/LoadedApk.java
+++ b/core/java/android/app/LoadedApk.java
@@ -38,6 +38,7 @@ import android.content.res.Resources;
import android.os.Build;
import android.os.Bundle;
import android.os.FileUtils;
+import android.os.GraphicsEnvironment;
import android.os.Handler;
import android.os.IBinder;
import android.os.Process;
@@ -46,6 +47,7 @@ import android.os.StrictMode;
import android.os.SystemProperties;
import android.os.Trace;
import android.os.UserHandle;
+import android.provider.Settings;
import android.security.net.config.NetworkSecurityConfigProvider;
import android.sysprop.VndkProperties;
import android.text.TextUtils;
@@ -824,6 +826,32 @@ public final class LoadedApk {
final String librarySearchPath = TextUtils.join(File.pathSeparator, libPaths);
+ if (mActivityThread != null) {
+ final String gpuDebugApp = mActivityThread.getStringCoreSetting(
+ Settings.Global.GPU_DEBUG_APP, "");
+ if (!gpuDebugApp.isEmpty() && mPackageName.equals(gpuDebugApp)) {
+
+ // The current application is used to debug, attempt to get the debug layers.
+ try {
+ // Get the ApplicationInfo from PackageManager so that metadata fields present.
+ final ApplicationInfo ai = ActivityThread.getPackageManager()
+ .getApplicationInfo(mPackageName, PackageManager.GET_META_DATA,
+ UserHandle.myUserId());
+ final String debugLayerPath = GraphicsEnvironment.getInstance()
+ .getDebugLayerPathsFromSettings(mActivityThread.getCoreSettings(),
+ ActivityThread.getPackageManager(), mPackageName, ai);
+ if (debugLayerPath != null) {
+ libraryPermittedPath += File.pathSeparator + debugLayerPath;
+ }
+ } catch (RemoteException e) {
+ // Unlikely to fail for applications, but in case of failure, something is wrong
+ // inside the system server, hence just skip.
+ Slog.e(ActivityThread.TAG,
+ "RemoteException when fetching debug layer paths for: " + mPackageName);
+ }
+ }
+ }
+
// If we're not asked to include code, we construct a classloader that has
// no code path included. We still need to set up the library search paths
// and permitted path because NativeActivity relies on it (it attempts to
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index e8ce92db62ad..f881616fd35a 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -7625,9 +7625,7 @@ public class Notification implements Parcelable
}
boolean isConversationLayout = mConversationType != CONVERSATION_TYPE_LEGACY;
boolean isImportantConversation = mConversationType == CONVERSATION_TYPE_IMPORTANT;
- Icon largeIcon = isConversationLayout && mShortcutIcon != null
- ? mShortcutIcon
- : mBuilder.mN.mLargeIcon;
+ Icon largeIcon = mBuilder.mN.mLargeIcon;
TemplateBindResult bindResult = new TemplateBindResult();
StandardTemplateParams p = mBuilder.mParams.reset()
.hasProgress(false)
@@ -7671,6 +7669,8 @@ public class Notification implements Parcelable
contentView.setCharSequence(R.id.status_bar_latest_event_content,
"setConversationTitle", conversationTitle);
if (isConversationLayout) {
+ contentView.setIcon(R.id.status_bar_latest_event_content,
+ "setShortcutIcon", mShortcutIcon);
contentView.setBoolean(R.id.status_bar_latest_event_content,
"setIsImportantConversation", isImportantConversation);
}
diff --git a/core/java/android/app/PendingIntent.java b/core/java/android/app/PendingIntent.java
index 792f840638a9..cd352e141994 100644
--- a/core/java/android/app/PendingIntent.java
+++ b/core/java/android/app/PendingIntent.java
@@ -351,7 +351,7 @@ public final class PendingIntent implements Parcelable {
String resolvedType = intent != null ? intent.resolveTypeIfNeeded(
context.getContentResolver()) : null;
try {
- intent.migrateExtraStreamToClipData();
+ intent.migrateExtraStreamToClipData(context);
intent.prepareToLeaveProcess(context);
IIntentSender target =
ActivityManager.getService().getIntentSenderWithFeature(
@@ -377,7 +377,7 @@ public final class PendingIntent implements Parcelable {
String resolvedType = intent != null ? intent.resolveTypeIfNeeded(
context.getContentResolver()) : null;
try {
- intent.migrateExtraStreamToClipData();
+ intent.migrateExtraStreamToClipData(context);
intent.prepareToLeaveProcess(context);
IIntentSender target =
ActivityManager.getService().getIntentSenderWithFeature(
@@ -491,7 +491,7 @@ public final class PendingIntent implements Parcelable {
String packageName = context.getPackageName();
String[] resolvedTypes = new String[intents.length];
for (int i=0; i<intents.length; i++) {
- intents[i].migrateExtraStreamToClipData();
+ intents[i].migrateExtraStreamToClipData(context);
intents[i].prepareToLeaveProcess(context);
resolvedTypes[i] = intents[i].resolveTypeIfNeeded(context.getContentResolver());
}
@@ -517,7 +517,7 @@ public final class PendingIntent implements Parcelable {
String packageName = context.getPackageName();
String[] resolvedTypes = new String[intents.length];
for (int i=0; i<intents.length; i++) {
- intents[i].migrateExtraStreamToClipData();
+ intents[i].migrateExtraStreamToClipData(context);
intents[i].prepareToLeaveProcess(context);
resolvedTypes[i] = intents[i].resolveTypeIfNeeded(context.getContentResolver());
}
diff --git a/core/java/android/app/ResourcesManager.java b/core/java/android/app/ResourcesManager.java
index 1aae04db32d0..4cba6ea74955 100644
--- a/core/java/android/app/ResourcesManager.java
+++ b/core/java/android/app/ResourcesManager.java
@@ -52,10 +52,13 @@ import com.android.internal.util.IndentingPrintWriter;
import java.io.IOException;
import java.io.PrintWriter;
+import java.lang.ref.Reference;
+import java.lang.ref.ReferenceQueue;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
+import java.util.HashSet;
import java.util.List;
import java.util.Objects;
import java.util.WeakHashMap;
@@ -70,12 +73,6 @@ public class ResourcesManager {
private static ResourcesManager sResourcesManager;
/**
- * Predicate that returns true if a WeakReference is gc'ed.
- */
- private static final Predicate<WeakReference<Resources>> sEmptyReferencePredicate =
- weakRef -> weakRef == null || weakRef.get() == null;
-
- /**
* The global compatibility settings.
*/
private CompatibilityInfo mResCompatibilityInfo;
@@ -100,6 +97,7 @@ public class ResourcesManager {
*/
@UnsupportedAppUsage
private final ArrayList<WeakReference<Resources>> mResourceReferences = new ArrayList<>();
+ private final ReferenceQueue<Resources> mResourcesReferencesQueue = new ReferenceQueue<>();
private static class ApkKey {
public final String path;
@@ -155,6 +153,7 @@ public class ResourcesManager {
}
public final Configuration overrideConfig = new Configuration();
public final ArrayList<WeakReference<Resources>> activityResources = new ArrayList<>();
+ final ReferenceQueue<Resources> activityResourcesQueue = new ReferenceQueue<>();
}
/**
@@ -667,12 +666,15 @@ public class ResourcesManager {
@NonNull CompatibilityInfo compatInfo) {
final ActivityResources activityResources = getOrCreateActivityResourcesStructLocked(
activityToken);
+ cleanupReferences(activityResources.activityResources,
+ activityResources.activityResourcesQueue);
Resources resources = compatInfo.needsCompatResources() ? new CompatResources(classLoader)
: new Resources(classLoader);
resources.setImpl(impl);
resources.setCallbacks(mUpdateCallbacks);
- activityResources.activityResources.add(new WeakReference<>(resources));
+ activityResources.activityResources.add(
+ new WeakReference<>(resources, activityResources.activityResourcesQueue));
if (DEBUG) {
Slog.d(TAG, "- creating new ref=" + resources);
Slog.d(TAG, "- setting ref=" + resources + " with impl=" + impl);
@@ -682,11 +684,13 @@ public class ResourcesManager {
private @NonNull Resources createResourcesLocked(@NonNull ClassLoader classLoader,
@NonNull ResourcesImpl impl, @NonNull CompatibilityInfo compatInfo) {
+ cleanupReferences(mResourceReferences, mResourcesReferencesQueue);
+
Resources resources = compatInfo.needsCompatResources() ? new CompatResources(classLoader)
: new Resources(classLoader);
resources.setImpl(impl);
resources.setCallbacks(mUpdateCallbacks);
- mResourceReferences.add(new WeakReference<>(resources));
+ mResourceReferences.add(new WeakReference<>(resources, mResourcesReferencesQueue));
if (DEBUG) {
Slog.d(TAG, "- creating new ref=" + resources);
Slog.d(TAG, "- setting ref=" + resources + " with impl=" + impl);
@@ -752,7 +756,6 @@ public class ResourcesManager {
updateResourcesForActivity(token, overrideConfig, displayId,
false /* movedToDifferentDisplay */);
- cleanupReferences(token);
rebaseKeyForActivity(token, key);
synchronized (this) {
@@ -778,10 +781,6 @@ public class ResourcesManager {
final ActivityResources activityResources =
getOrCreateActivityResourcesStructLocked(activityToken);
- // Clean up any dead references so they don't pile up.
- ArrayUtils.unstableRemoveIf(activityResources.activityResources,
- sEmptyReferencePredicate);
-
// Rebase the key's override config on top of the Activity's base override.
if (key.hasOverrideConfiguration()
&& !activityResources.overrideConfig.equals(Configuration.EMPTY)) {
@@ -794,21 +793,21 @@ public class ResourcesManager {
/**
* Check WeakReferences and remove any dead references so they don't pile up.
- * @param activityToken optional token to clean up Activity resources
*/
- private void cleanupReferences(IBinder activityToken) {
- synchronized (this) {
- if (activityToken != null) {
- ActivityResources activityResources = mActivityResourceReferences.get(
- activityToken);
- if (activityResources != null) {
- ArrayUtils.unstableRemoveIf(activityResources.activityResources,
- sEmptyReferencePredicate);
- }
- } else {
- ArrayUtils.unstableRemoveIf(mResourceReferences, sEmptyReferencePredicate);
- }
+ private static <T> void cleanupReferences(ArrayList<WeakReference<T>> references,
+ ReferenceQueue<T> referenceQueue) {
+ Reference<? extends T> enduedRef = referenceQueue.poll();
+ if (enduedRef == null) {
+ return;
}
+
+ final HashSet<Reference<? extends T>> deadReferences = new HashSet<>();
+ for (; enduedRef != null; enduedRef = referenceQueue.poll()) {
+ deadReferences.add(enduedRef);
+ }
+
+ ArrayUtils.unstableRemoveIf(references,
+ (ref) -> ref == null || deadReferences.contains(ref));
}
/**
@@ -896,8 +895,6 @@ public class ResourcesManager {
loaders == null ? null : loaders.toArray(new ResourcesLoader[0]));
classLoader = classLoader != null ? classLoader : ClassLoader.getSystemClassLoader();
- cleanupReferences(activityToken);
-
if (activityToken != null) {
rebaseKeyForActivity(activityToken, key);
}
diff --git a/core/java/android/app/TaskStackListener.java b/core/java/android/app/TaskStackListener.java
index 5d8daf88a8de..f137d6858a68 100644
--- a/core/java/android/app/TaskStackListener.java
+++ b/core/java/android/app/TaskStackListener.java
@@ -199,4 +199,8 @@ public abstract class TaskStackListener extends ITaskStackListener.Stub {
@Override
public void onTaskRequestedOrientationChanged(int taskId, int requestedOrientation) {
}
+
+ @Override
+ public void onActivityRotation(int displayId) {
+ }
}
diff --git a/core/java/android/app/contentsuggestions/ContentSuggestionsManager.java b/core/java/android/app/contentsuggestions/ContentSuggestionsManager.java
index bea1bd6e70d6..b3f9e31abaa4 100644
--- a/core/java/android/app/contentsuggestions/ContentSuggestionsManager.java
+++ b/core/java/android/app/contentsuggestions/ContentSuggestionsManager.java
@@ -95,7 +95,7 @@ public final class ContentSuggestionsManager {
try {
mService.provideContextBitmap(mUser, bitmap, imageContextRequestExtras);
} catch (RemoteException e) {
- e.rethrowFromSystemServer();
+ throw e.rethrowFromSystemServer();
}
}
@@ -117,7 +117,7 @@ public final class ContentSuggestionsManager {
try {
mService.provideContextImage(mUser, taskId, imageContextRequestExtras);
} catch (RemoteException e) {
- e.rethrowFromSystemServer();
+ throw e.rethrowFromSystemServer();
}
}
@@ -146,7 +146,7 @@ public final class ContentSuggestionsManager {
mService.suggestContentSelections(
mUser, request, new SelectionsCallbackWrapper(callback, callbackExecutor));
} catch (RemoteException e) {
- e.rethrowFromSystemServer();
+ throw e.rethrowFromSystemServer();
}
}
@@ -173,7 +173,7 @@ public final class ContentSuggestionsManager {
mService.classifyContentSelections(
mUser, request, new ClassificationsCallbackWrapper(callback, callbackExecutor));
} catch (RemoteException e) {
- e.rethrowFromSystemServer();
+ throw e.rethrowFromSystemServer();
}
}
@@ -193,7 +193,7 @@ public final class ContentSuggestionsManager {
try {
mService.notifyInteraction(mUser, requestId, interaction);
} catch (RemoteException e) {
- e.rethrowFromSystemServer();
+ throw e.rethrowFromSystemServer();
}
}
@@ -213,9 +213,10 @@ public final class ContentSuggestionsManager {
mService.isEnabled(mUser, receiver);
return receiver.getIntResult() != 0;
} catch (RemoteException e) {
- e.rethrowFromSystemServer();
+ throw e.rethrowFromSystemServer();
+ } catch (SyncResultReceiver.TimeoutException e) {
+ throw new RuntimeException("Fail to get the enable status.");
}
- return false;
}
/**
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index baaf8f76797a..be3cfeff729e 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -1884,6 +1884,9 @@ public class Intent implements Parcelable, Cloneable {
/**
* Activity action: Launch UI to manage auto-revoke state.
+ *
+ * This is equivalent to Intent#ACTION_APPLICATION_DETAILS_SETTINGS
+ *
* <p>
* Input: {@link Intent#setData data} should be a {@code package}-scheme {@link Uri} with
* a package name, whose auto-revoke state will be reviewed (mandatory).
@@ -11272,6 +11275,19 @@ public class Intent implements Parcelable, Cloneable {
* @hide
*/
public boolean migrateExtraStreamToClipData() {
+ return migrateExtraStreamToClipData(AppGlobals.getInitialApplication());
+ }
+
+ /**
+ * Migrate any {@link #EXTRA_STREAM} in {@link #ACTION_SEND} and
+ * {@link #ACTION_SEND_MULTIPLE} to {@link ClipData}. Also inspects nested
+ * intents in {@link #ACTION_CHOOSER}.
+ *
+ * @param context app context
+ * @return Whether any contents were migrated.
+ * @hide
+ */
+ public boolean migrateExtraStreamToClipData(Context context) {
// Refuse to touch if extras already parcelled
if (mExtras != null && mExtras.isParcelled()) return false;
@@ -11289,7 +11305,7 @@ public class Intent implements Parcelable, Cloneable {
try {
final Intent intent = getParcelableExtra(EXTRA_INTENT);
if (intent != null) {
- migrated |= intent.migrateExtraStreamToClipData();
+ migrated |= intent.migrateExtraStreamToClipData(context);
}
} catch (ClassCastException e) {
}
@@ -11299,7 +11315,7 @@ public class Intent implements Parcelable, Cloneable {
for (int i = 0; i < intents.length; i++) {
final Intent intent = (Intent) intents[i];
if (intent != null) {
- migrated |= intent.migrateExtraStreamToClipData();
+ migrated |= intent.migrateExtraStreamToClipData(context);
}
}
}
@@ -11362,13 +11378,17 @@ public class Intent implements Parcelable, Cloneable {
} catch (ClassCastException e) {
}
} else if (isImageCaptureIntent()) {
- final Uri output;
+ Uri output;
try {
output = getParcelableExtra(MediaStore.EXTRA_OUTPUT);
} catch (ClassCastException e) {
return false;
}
+
if (output != null) {
+ output = maybeConvertFileToContentUri(context, output);
+ putExtra(MediaStore.EXTRA_OUTPUT, output);
+
setClipData(ClipData.newRawUri("", output));
addFlags(FLAG_GRANT_WRITE_URI_PERMISSION|FLAG_GRANT_READ_URI_PERMISSION);
return true;
@@ -11378,6 +11398,23 @@ public class Intent implements Parcelable, Cloneable {
return false;
}
+ private Uri maybeConvertFileToContentUri(Context context, Uri uri) {
+ if (ContentResolver.SCHEME_FILE.equals(uri.getScheme())
+ && context.getApplicationInfo().targetSdkVersion < Build.VERSION_CODES.R) {
+ File file = new File(uri.getPath());
+ try {
+ if (!file.exists()) file.createNewFile();
+ uri = MediaStore.scanFile(context.getContentResolver(), new File(uri.getPath()));
+ if (uri != null) {
+ return uri;
+ }
+ } catch (IOException e) {
+ Log.e(TAG, "Ignoring failure to create file " + file, e);
+ }
+ }
+ return uri;
+ }
+
/**
* Convert the dock state to a human readable format.
* @hide
diff --git a/core/java/android/content/pm/PackageInstaller.java b/core/java/android/content/pm/PackageInstaller.java
index ed75504529b9..fc4ccd072e75 100644
--- a/core/java/android/content/pm/PackageInstaller.java
+++ b/core/java/android/content/pm/PackageInstaller.java
@@ -1449,6 +1449,13 @@ public class PackageInstaller {
/** {@hide} */
public static final int UID_UNKNOWN = -1;
+ /**
+ * This value is derived from the maximum file name length. No package above this limit
+ * can ever be successfully installed on the device.
+ * @hide
+ */
+ public static final int MAX_PACKAGE_NAME_LENGTH = 255;
+
/** {@hide} */
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
public int mode = MODE_INVALID;
@@ -1642,6 +1649,8 @@ public class PackageInstaller {
/**
* Optionally set a label representing the app being installed.
+ *
+ * This value will be trimmed to the first 1000 characters.
*/
public void setAppLabel(@Nullable CharSequence appLabel) {
this.appLabel = (appLabel != null) ? appLabel.toString() : null;
@@ -1711,7 +1720,8 @@ public class PackageInstaller {
*
* <p>Initially, all restricted permissions are whitelisted but you can change
* which ones are whitelisted by calling this method or the corresponding ones
- * on the {@link PackageManager}.
+ * on the {@link PackageManager}. Only soft or hard restricted permissions on the current
+ * Android version are supported and any invalid entries will be removed.
*
* @see PackageManager#addWhitelistedRestrictedPermission(String, String, int)
* @see PackageManager#removeWhitelistedRestrictedPermission(String, String, int)
diff --git a/core/java/android/content/pm/PackageItemInfo.java b/core/java/android/content/pm/PackageItemInfo.java
index f354bdb5a08b..65ce1e7ef079 100644
--- a/core/java/android/content/pm/PackageItemInfo.java
+++ b/core/java/android/content/pm/PackageItemInfo.java
@@ -49,8 +49,16 @@ import java.util.Objects;
* in the implementation of Parcelable in subclasses.
*/
public class PackageItemInfo {
- /** The maximum length of a safe label, in characters */
- private static final int MAX_SAFE_LABEL_LENGTH = 50000;
+
+ /**
+ * The maximum length of a safe label, in characters
+ *
+ * TODO(b/157997155): It may make sense to expose this publicly so that apps can check for the
+ * value and truncate the strings/use a different label, without having to hardcode and make
+ * assumptions about the value.
+ * @hide
+ */
+ public static final int MAX_SAFE_LABEL_LENGTH = 1000;
/** @hide */
public static final float DEFAULT_MAX_LABEL_SIZE_PX = 500f;
diff --git a/core/java/android/content/pm/PackagePartitions.java b/core/java/android/content/pm/PackagePartitions.java
index 653b9ec9e8f2..98a20f73a120 100644
--- a/core/java/android/content/pm/PackagePartitions.java
+++ b/core/java/android/content/pm/PackagePartitions.java
@@ -183,17 +183,20 @@ public class PackagePartitions {
/** Returns whether the partition contains the specified file in its priv-app folder. */
public boolean containsPrivApp(@NonNull File scanFile) {
- return FileUtils.contains(mPrivAppFolder.getFile(), canonicalize(scanFile));
+ return mPrivAppFolder != null
+ && FileUtils.contains(mPrivAppFolder.getFile(), canonicalize(scanFile));
}
/** Returns whether the partition contains the specified file in its app folder. */
public boolean containsApp(@NonNull File scanFile) {
- return FileUtils.contains(mAppFolder.getFile(), canonicalize(scanFile));
+ return mAppFolder != null
+ && FileUtils.contains(mAppFolder.getFile(), canonicalize(scanFile));
}
/** Returns whether the partition contains the specified file in its overlay folder. */
public boolean containsOverlay(@NonNull File scanFile) {
- return FileUtils.contains(mOverlayFolder.getFile(), canonicalize(scanFile));
+ return mOverlayFolder != null
+ && FileUtils.contains(mOverlayFolder.getFile(), canonicalize(scanFile));
}
}
diff --git a/core/java/android/content/pm/parsing/component/ParsedActivityUtils.java b/core/java/android/content/pm/parsing/component/ParsedActivityUtils.java
index f64560a14832..fb8fd74545c7 100644
--- a/core/java/android/content/pm/parsing/component/ParsedActivityUtils.java
+++ b/core/java/android/content/pm/parsing/component/ParsedActivityUtils.java
@@ -302,7 +302,14 @@ public class ParsedActivityUtils {
}
String permission = array.getNonConfigurationString(permissionAttr, 0);
- activity.setPermission(permission != null ? permission : pkg.getPermission());
+ if (isAlias) {
+ // An alias will override permissions to allow referencing an Activity through its alias
+ // without needing the original permission. If an alias needs the same permission,
+ // it must be re-declared.
+ activity.setPermission(permission);
+ } else {
+ activity.setPermission(permission != null ? permission : pkg.getPermission());
+ }
final boolean setExported = array.hasValue(exportedAttr);
if (setExported) {
diff --git a/core/java/android/content/pm/parsing/component/ParsedComponentUtils.java b/core/java/android/content/pm/parsing/component/ParsedComponentUtils.java
index b37b61757053..6811e06fbe7e 100644
--- a/core/java/android/content/pm/parsing/component/ParsedComponentUtils.java
+++ b/core/java/android/content/pm/parsing/component/ParsedComponentUtils.java
@@ -20,7 +20,10 @@ import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.pm.PackageManager;
import android.content.pm.parsing.ParsingPackage;
+import android.content.pm.parsing.ParsingPackageUtils;
import android.content.pm.parsing.ParsingUtils;
+import android.content.pm.parsing.result.ParseInput;
+import android.content.pm.parsing.result.ParseResult;
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.content.res.XmlResourceParser;
@@ -29,9 +32,6 @@ import android.text.TextUtils;
import android.util.TypedValue;
import com.android.internal.annotations.VisibleForTesting;
-import android.content.pm.parsing.ParsingPackageUtils;
-import android.content.pm.parsing.result.ParseInput;
-import android.content.pm.parsing.result.ParseResult;
/** @hide */
class ParsedComponentUtils {
@@ -60,16 +60,27 @@ class ParsedComponentUtils {
component.setName(className);
component.setPackageName(packageName);
- if (useRoundIcon) {
- component.icon = array.getResourceId(roundIconAttr, 0);
+ int roundIconVal = useRoundIcon ? array.getResourceId(roundIconAttr, 0) : 0;
+ if (roundIconVal != 0) {
+ component.icon = roundIconVal;
+ component.nonLocalizedLabel = null;
+ } else {
+ int iconVal = array.getResourceId(iconAttr, 0);
+ if (iconVal != 0) {
+ component.icon = iconVal;
+ component.nonLocalizedLabel = null;
+ }
}
- if (component.icon == 0) {
- component.icon = array.getResourceId(iconAttr, 0);
+ int logoVal = array.getResourceId(logoAttr, 0);
+ if (logoVal != 0) {
+ component.logo = logoVal;
}
- component.logo = array.getResourceId(logoAttr, 0);
- component.banner = array.getResourceId(bannerAttr, 0);
+ int bannerVal = array.getResourceId(bannerAttr, 0);
+ if (bannerVal != 0) {
+ component.banner = bannerVal;
+ }
if (descriptionAttr != null) {
component.descriptionRes = array.getResourceId(descriptionAttr, 0);
diff --git a/core/java/android/hardware/biometrics/BiometricManager.java b/core/java/android/hardware/biometrics/BiometricManager.java
index 8d472da1fb7c..570cc2c11738 100644
--- a/core/java/android/hardware/biometrics/BiometricManager.java
+++ b/core/java/android/hardware/biometrics/BiometricManager.java
@@ -116,22 +116,25 @@ public class BiometricManager {
/**
* Any biometric (e.g. fingerprint, iris, or face) on the device that meets or exceeds the
- * requirements for <strong>Strong</strong>, as defined by the Android CDD.
+ * requirements for <strong>Tier 3</strong> (formerly <strong>Strong</strong>), as defined
+ * by the Android CDD.
*/
int BIOMETRIC_STRONG = 0x000F;
/**
* Any biometric (e.g. fingerprint, iris, or face) on the device that meets or exceeds the
- * requirements for <strong>Weak</strong>, as defined by the Android CDD.
+ * requirements for <strong>Tier 2</strong> (formerly <strong>Weak</strong>), as defined by
+ * the Android CDD.
*
* <p>Note that this is a superset of {@link #BIOMETRIC_STRONG} and is defined such that
- * <code>BIOMETRIC_STRONG | BIOMETRIC_WEAK == BIOMETRIC_WEAK</code>.
+ * {@code BIOMETRIC_STRONG | BIOMETRIC_WEAK == BIOMETRIC_WEAK}.
*/
int BIOMETRIC_WEAK = 0x00FF;
/**
* Any biometric (e.g. fingerprint, iris, or face) on the device that meets or exceeds the
- * requirements for <strong>Convenience</strong>, as defined by the Android CDD.
+ * requirements for <strong>Tier 1</strong> (formerly <strong>Convenience</strong>), as
+ * defined by the Android CDD.
*
* <p>This constant is intended for use by {@link android.provider.DeviceConfig} to adjust
* the reported strength of a biometric sensor. It is not a valid parameter for any of the
diff --git a/core/java/android/hardware/camera2/CameraManager.java b/core/java/android/hardware/camera2/CameraManager.java
index 6bbc37a90fae..7f834afd7b30 100644
--- a/core/java/android/hardware/camera2/CameraManager.java
+++ b/core/java/android/hardware/camera2/CameraManager.java
@@ -586,13 +586,27 @@ public final class CameraManager {
* priority when accessing the camera, and this method will succeed even if the camera device is
* in use by another camera API client. Any lower-priority application that loses control of the
* camera in this way will receive an
- * {@link android.hardware.camera2.CameraDevice.StateCallback#onDisconnected} callback.</p>
+ * {@link android.hardware.camera2.CameraDevice.StateCallback#onDisconnected} callback.
+ * Opening the same camera ID twice in the same application will similarly cause the
+ * {@link android.hardware.camera2.CameraDevice.StateCallback#onDisconnected} callback
+ * being fired for the {@link CameraDevice} from the first open call and all ongoing tasks
+ * being droppped.</p>
*
* <p>Once the camera is successfully opened, {@link CameraDevice.StateCallback#onOpened} will
* be invoked with the newly opened {@link CameraDevice}. The camera device can then be set up
* for operation by calling {@link CameraDevice#createCaptureSession} and
* {@link CameraDevice#createCaptureRequest}</p>
*
+ * <p>Before API level 30, when the application tries to open multiple {@link CameraDevice} of
+ * different IDs and the device does not support opening such combination, either the
+ * {@link #openCamera} will fail and throw a {@link CameraAccessException} or one or more of
+ * already opened {@link CameraDevice} will be disconnected and receive
+ * {@link android.hardware.camera2.CameraDevice.StateCallback#onDisconnected} callback. Which
+ * behavior will happen depends on the device implementation and can vary on different devices.
+ * Starting in API level 30, if the device does not support the combination of cameras being
+ * opened, it is guaranteed the {@link #openCamera} call will fail and none of existing
+ * {@link CameraDevice} will be disconnected.</p>
+ *
* <!--
* <p>Since the camera device will be opened asynchronously, any asynchronous operations done
* on the returned CameraDevice instance will be queued up until the device startup has
@@ -618,7 +632,8 @@ public final class CameraManager {
* {@code null} to use the current thread's {@link android.os.Looper looper}.
*
* @throws CameraAccessException if the camera is disabled by device policy,
- * has been disconnected, or is being used by a higher-priority camera API client.
+ * has been disconnected, is being used by a higher-priority camera API client, or the device
+ * has reached its maximal resource and cannot open this camera device.
*
* @throws IllegalArgumentException if cameraId or the callback was null,
* or the cameraId does not match any currently or previously available
diff --git a/core/java/android/hardware/hdmi/HdmiClient.java b/core/java/android/hardware/hdmi/HdmiClient.java
index bff8c39e8c56..a921215c6133 100644
--- a/core/java/android/hardware/hdmi/HdmiClient.java
+++ b/core/java/android/hardware/hdmi/HdmiClient.java
@@ -1,6 +1,7 @@
package android.hardware.hdmi;
import android.annotation.NonNull;
+import android.annotation.SuppressLint;
import android.annotation.SystemApi;
import android.hardware.hdmi.HdmiControlManager.VendorCommandListener;
import android.os.RemoteException;
@@ -84,7 +85,8 @@ public abstract class HdmiClient {
* @param hasVendorId {@code true} if the command type will be &lt;Vendor Command With ID&gt;.
* {@code false} if the command will be &lt;Vendor Command&gt;
*/
- public void sendVendorCommand(int targetAddress, byte[] params, boolean hasVendorId) {
+ public void sendVendorCommand(int targetAddress,
+ @SuppressLint("MissingNullability") byte[] params, boolean hasVendorId) {
try {
mService.sendVendorCommand(getDeviceType(), targetAddress, params, hasVendorId);
} catch (RemoteException e) {
diff --git a/core/java/android/hardware/hdmi/HdmiControlManager.java b/core/java/android/hardware/hdmi/HdmiControlManager.java
index 6bc962b67576..1ce9b9c71c0e 100644
--- a/core/java/android/hardware/hdmi/HdmiControlManager.java
+++ b/core/java/android/hardware/hdmi/HdmiControlManager.java
@@ -18,6 +18,7 @@ package android.hardware.hdmi;
import static com.android.internal.os.RoSystemProperties.PROPERTY_HDMI_IS_DEVICE_HDMI_CEC_SWITCH;
+import android.annotation.CallbackExecutor;
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -28,8 +29,10 @@ import android.annotation.SdkConstant.SdkConstantType;
import android.annotation.SuppressLint;
import android.annotation.SystemApi;
import android.annotation.SystemService;
+import android.annotation.TestApi;
import android.content.Context;
import android.content.pm.PackageManager;
+import android.os.Binder;
import android.os.RemoteException;
import android.os.SystemProperties;
import android.util.ArrayMap;
@@ -40,6 +43,7 @@ import com.android.internal.annotations.GuardedBy;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
+import java.util.concurrent.Executor;
/**
* The {@link HdmiControlManager} class is used to send HDMI control messages
@@ -54,6 +58,7 @@ import java.util.Objects;
* @hide
*/
@SystemApi
+@TestApi
@SystemService(Context.HDMI_CONTROL_SERVICE)
@RequiresFeature(PackageManager.FEATURE_HDMI_CEC)
public final class HdmiControlManager {
@@ -136,6 +141,8 @@ public final class HdmiControlManager {
public static final int POWER_STATUS_TRANSIENT_TO_ON = 2;
public static final int POWER_STATUS_TRANSIENT_TO_STANDBY = 3;
+ /** @hide */
+ @SystemApi
@IntDef ({
RESULT_SUCCESS,
RESULT_TIMEOUT,
@@ -397,8 +404,11 @@ public final class HdmiControlManager {
* See {@link HdmiDeviceInfo#DEVICE_PLAYBACK}
* See {@link HdmiDeviceInfo#DEVICE_TV}
* See {@link HdmiDeviceInfo#DEVICE_AUDIO_SYSTEM}
+ *
+ * @hide
*/
@Nullable
+ @SystemApi
@SuppressLint("Doclava125")
public HdmiClient getClient(int type) {
if (mService == null) {
@@ -427,8 +437,11 @@ public final class HdmiControlManager {
* system if the system is configured to host more than one type of HDMI-CEC logical devices.
*
* @return {@link HdmiPlaybackClient} instance. {@code null} on failure.
+ *
+ * @hide
*/
@Nullable
+ @SystemApi
@SuppressLint("Doclava125")
public HdmiPlaybackClient getPlaybackClient() {
return (HdmiPlaybackClient) getClient(HdmiDeviceInfo.DEVICE_PLAYBACK);
@@ -442,8 +455,11 @@ public final class HdmiControlManager {
* system if the system is configured to host more than one type of HDMI-CEC logical devices.
*
* @return {@link HdmiTvClient} instance. {@code null} on failure.
+ *
+ * @hide
*/
@Nullable
+ @SystemApi
@SuppressLint("Doclava125")
public HdmiTvClient getTvClient() {
return (HdmiTvClient) getClient(HdmiDeviceInfo.DEVICE_TV);
@@ -475,10 +491,8 @@ public final class HdmiControlManager {
* system if the system is configured to host more than one type of HDMI-CEC logical device.
*
* @return {@link HdmiSwitchClient} instance. {@code null} on failure.
- * @hide
*/
@Nullable
- @SystemApi
@SuppressLint("Doclava125")
public HdmiSwitchClient getSwitchClient() {
return (HdmiSwitchClient) getClient(HdmiDeviceInfo.DEVICE_PURE_CEC_SWITCH);
@@ -787,7 +801,10 @@ public final class HdmiControlManager {
/**
* Listener used to get hotplug event from HDMI port.
+ *
+ * @hide
*/
+ @SystemApi
public interface HotplugEventListener {
void onReceived(HdmiHotplugEvent event);
}
@@ -818,8 +835,29 @@ public final class HdmiControlManager {
mHdmiControlStatusChangeListeners = new ArrayMap<>();
/**
+ * Listener used to get the status of the HDMI CEC volume control feature (enabled/disabled).
+ * @hide
+ */
+ public interface HdmiCecVolumeControlFeatureListener {
+ /**
+ * Called when the HDMI Control (CEC) volume control feature is enabled/disabled.
+ *
+ * @param enabled status of HDMI CEC volume control feature
+ * @see {@link HdmiControlManager#setHdmiCecVolumeControlEnabled(boolean)} ()}
+ **/
+ void onHdmiCecVolumeControlFeature(boolean enabled);
+ }
+
+ private final ArrayMap<HdmiCecVolumeControlFeatureListener,
+ IHdmiCecVolumeControlFeatureListener>
+ mHdmiCecVolumeControlFeatureListeners = new ArrayMap<>();
+
+ /**
* Listener used to get vendor-specific commands.
+ *
+ * @hide
*/
+ @SystemApi
public interface VendorCommandListener {
/**
* Called when a vendor command is received.
@@ -858,7 +896,10 @@ public final class HdmiControlManager {
*
* @param listener {@link HotplugEventListener} instance
* @see HdmiControlManager#removeHotplugEventListener(HotplugEventListener)
+ *
+ * @hide
*/
+ @SystemApi
@RequiresPermission(android.Manifest.permission.HDMI_CEC)
public void addHotplugEventListener(HotplugEventListener listener) {
if (mService == null) {
@@ -882,7 +923,10 @@ public final class HdmiControlManager {
* Removes a listener to stop getting informed of {@link HdmiHotplugEvent}.
*
* @param listener {@link HotplugEventListener} instance to be removed
+ *
+ * @hide
*/
+ @SystemApi
@RequiresPermission(android.Manifest.permission.HDMI_CEC)
public void removeHotplugEventListener(HotplugEventListener listener) {
if (mService == null) {
@@ -979,4 +1023,76 @@ public final class HdmiControlManager {
};
}
+ /**
+ * Adds a listener to get informed of changes to the state of the HDMI CEC volume control
+ * feature.
+ *
+ * Upon adding a listener, the current state of the HDMI CEC volume control feature will be
+ * sent immediately.
+ *
+ * <p>To stop getting the notification,
+ * use {@link #removeHdmiCecVolumeControlFeatureListener(HdmiCecVolumeControlFeatureListener)}.
+ *
+ * @param listener {@link HdmiCecVolumeControlFeatureListener} instance
+ * @hide
+ * @see #removeHdmiCecVolumeControlFeatureListener(HdmiCecVolumeControlFeatureListener)
+ */
+ @RequiresPermission(android.Manifest.permission.HDMI_CEC)
+ public void addHdmiCecVolumeControlFeatureListener(@NonNull @CallbackExecutor Executor executor,
+ @NonNull HdmiCecVolumeControlFeatureListener listener) {
+ if (mService == null) {
+ Log.e(TAG, "HdmiControlService is not available");
+ return;
+ }
+ if (mHdmiCecVolumeControlFeatureListeners.containsKey(listener)) {
+ Log.e(TAG, "listener is already registered");
+ return;
+ }
+ IHdmiCecVolumeControlFeatureListener wrappedListener =
+ createHdmiCecVolumeControlFeatureListenerWrapper(executor, listener);
+ mHdmiCecVolumeControlFeatureListeners.put(listener, wrappedListener);
+ try {
+ mService.addHdmiCecVolumeControlFeatureListener(wrappedListener);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Removes a listener to stop getting informed of changes to the state of the HDMI CEC volume
+ * control feature.
+ *
+ * @param listener {@link HdmiCecVolumeControlFeatureListener} instance to be removed
+ * @hide
+ */
+ @RequiresPermission(android.Manifest.permission.HDMI_CEC)
+ public void removeHdmiCecVolumeControlFeatureListener(
+ HdmiCecVolumeControlFeatureListener listener) {
+ if (mService == null) {
+ Log.e(TAG, "HdmiControlService is not available");
+ return;
+ }
+ IHdmiCecVolumeControlFeatureListener wrappedListener =
+ mHdmiCecVolumeControlFeatureListeners.remove(listener);
+ if (wrappedListener == null) {
+ Log.e(TAG, "tried to remove not-registered listener");
+ return;
+ }
+ try {
+ mService.removeHdmiCecVolumeControlFeatureListener(wrappedListener);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ private IHdmiCecVolumeControlFeatureListener createHdmiCecVolumeControlFeatureListenerWrapper(
+ Executor executor, final HdmiCecVolumeControlFeatureListener listener) {
+ return new android.hardware.hdmi.IHdmiCecVolumeControlFeatureListener.Stub() {
+ @Override
+ public void onHdmiCecVolumeControlFeature(boolean enabled) {
+ Binder.clearCallingIdentity();
+ executor.execute(() -> listener.onHdmiCecVolumeControlFeature(enabled));
+ }
+ };
+ }
}
diff --git a/core/java/android/hardware/hdmi/HdmiControlServiceWrapper.java b/core/java/android/hardware/hdmi/HdmiControlServiceWrapper.java
new file mode 100644
index 000000000000..02896351ea3a
--- /dev/null
+++ b/core/java/android/hardware/hdmi/HdmiControlServiceWrapper.java
@@ -0,0 +1,469 @@
+/*
+ * Copyright 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 android.hardware.hdmi;
+
+import android.annotation.BinderThread;
+import android.annotation.NonNull;
+import android.annotation.TestApi;
+
+import java.util.List;
+
+/**
+ * A wrapper of the Binder interface that clients running in the application process
+ * will use to perform HDMI-CEC features by communicating with other devices
+ * on the bus.
+ *
+ * @hide
+ */
+@TestApi
+public final class HdmiControlServiceWrapper {
+
+ /** Pure CEC switch device type. */
+ public static final int DEVICE_PURE_CEC_SWITCH = HdmiDeviceInfo.DEVICE_PURE_CEC_SWITCH;
+
+ private List<HdmiPortInfo> mInfoList = null;
+ private int[] mTypes = null;
+
+ /**
+ * Create a new HdmiControlManager with the current HdmiControlService wrapper
+ *
+ * @return the created HdmiControlManager
+ */
+ @NonNull
+ public HdmiControlManager createHdmiControlManager() {
+ return new HdmiControlManager(mInterface);
+ }
+
+ private final IHdmiControlService mInterface = new IHdmiControlService.Stub() {
+
+ @Override
+ public int[] getSupportedTypes() {
+ return HdmiControlServiceWrapper.this.getSupportedTypes();
+ }
+
+ @Override
+ public HdmiDeviceInfo getActiveSource() {
+ return HdmiControlServiceWrapper.this.getActiveSource();
+ }
+
+ @Override
+ public void oneTouchPlay(IHdmiControlCallback callback) {
+ HdmiControlServiceWrapper.this.oneTouchPlay(callback);
+ }
+
+ @Override
+ public void queryDisplayStatus(IHdmiControlCallback callback) {
+ HdmiControlServiceWrapper.this.queryDisplayStatus(callback);
+ }
+
+ @Override
+ public void addHdmiControlStatusChangeListener(IHdmiControlStatusChangeListener listener) {
+ HdmiControlServiceWrapper.this.addHdmiControlStatusChangeListener(listener);
+ }
+
+ @Override
+ public void removeHdmiControlStatusChangeListener(
+ IHdmiControlStatusChangeListener listener) {
+ HdmiControlServiceWrapper.this.removeHdmiControlStatusChangeListener(listener);
+ }
+
+ @Override
+ public void addHotplugEventListener(IHdmiHotplugEventListener listener) {
+ HdmiControlServiceWrapper.this.addHotplugEventListener(listener);
+ }
+
+ @Override
+ public void removeHotplugEventListener(IHdmiHotplugEventListener listener) {
+ HdmiControlServiceWrapper.this.removeHotplugEventListener(listener);
+ }
+
+ @Override
+ public void addDeviceEventListener(IHdmiDeviceEventListener listener) {
+ HdmiControlServiceWrapper.this.addDeviceEventListener(listener);
+ }
+
+ @Override
+ public void deviceSelect(int deviceId, IHdmiControlCallback callback) {
+ HdmiControlServiceWrapper.this.deviceSelect(deviceId, callback);
+ }
+
+ @Override
+ public void portSelect(int portId, IHdmiControlCallback callback) {
+ HdmiControlServiceWrapper.this.portSelect(portId, callback);
+ }
+
+ @Override
+ public void sendKeyEvent(int deviceType, int keyCode, boolean isPressed) {
+ HdmiControlServiceWrapper.this.sendKeyEvent(deviceType, keyCode, isPressed);
+ }
+
+ @Override
+ public void sendVolumeKeyEvent(int deviceType, int keyCode, boolean isPressed) {
+ HdmiControlServiceWrapper.this.sendVolumeKeyEvent(deviceType, keyCode, isPressed);
+ }
+
+ @Override
+ public List<HdmiPortInfo> getPortInfo() {
+ return HdmiControlServiceWrapper.this.getPortInfo();
+ }
+
+ @Override
+ public boolean canChangeSystemAudioMode() {
+ return HdmiControlServiceWrapper.this.canChangeSystemAudioMode();
+ }
+
+ @Override
+ public boolean getSystemAudioMode() {
+ return HdmiControlServiceWrapper.this.getSystemAudioMode();
+ }
+
+ @Override
+ public int getPhysicalAddress() {
+ return HdmiControlServiceWrapper.this.getPhysicalAddress();
+ }
+
+ @Override
+ public void setSystemAudioMode(boolean enabled, IHdmiControlCallback callback) {
+ HdmiControlServiceWrapper.this.setSystemAudioMode(enabled, callback);
+ }
+
+ @Override
+ public void addSystemAudioModeChangeListener(IHdmiSystemAudioModeChangeListener listener) {
+ HdmiControlServiceWrapper.this.addSystemAudioModeChangeListener(listener);
+ }
+
+ @Override
+ public void removeSystemAudioModeChangeListener(
+ IHdmiSystemAudioModeChangeListener listener) {
+ HdmiControlServiceWrapper.this.removeSystemAudioModeChangeListener(listener);
+ }
+
+ @Override
+ public void setArcMode(boolean enabled) {
+ HdmiControlServiceWrapper.this.setArcMode(enabled);
+ }
+
+ @Override
+ public void setProhibitMode(boolean enabled) {
+ HdmiControlServiceWrapper.this.setProhibitMode(enabled);
+ }
+
+ @Override
+ public void setSystemAudioVolume(int oldIndex, int newIndex, int maxIndex) {
+ HdmiControlServiceWrapper.this.setSystemAudioVolume(oldIndex, newIndex, maxIndex);
+ }
+
+ @Override
+ public void setSystemAudioMute(boolean mute) {
+ HdmiControlServiceWrapper.this.setSystemAudioMute(mute);
+ }
+
+ @Override
+ public void setInputChangeListener(IHdmiInputChangeListener listener) {
+ HdmiControlServiceWrapper.this.setInputChangeListener(listener);
+ }
+
+ @Override
+ public List<HdmiDeviceInfo> getInputDevices() {
+ return HdmiControlServiceWrapper.this.getInputDevices();
+ }
+
+ @Override
+ public List<HdmiDeviceInfo> getDeviceList() {
+ return HdmiControlServiceWrapper.this.getDeviceList();
+ }
+
+ @Override
+ public void powerOffRemoteDevice(int logicalAddress, int powerStatus) {
+ HdmiControlServiceWrapper.this.powerOffRemoteDevice(logicalAddress, powerStatus);
+ }
+
+ @Override
+ public void powerOnRemoteDevice(int logicalAddress, int powerStatus) {
+ HdmiControlServiceWrapper.this.powerOnRemoteDevice(logicalAddress, powerStatus);
+ }
+
+ @Override
+ public void askRemoteDeviceToBecomeActiveSource(int physicalAddress) {
+ HdmiControlServiceWrapper.this.askRemoteDeviceToBecomeActiveSource(physicalAddress);
+ }
+
+ @Override
+ public void sendVendorCommand(int deviceType, int targetAddress, byte[] params,
+ boolean hasVendorId) {
+ HdmiControlServiceWrapper.this.sendVendorCommand(
+ deviceType, targetAddress, params, hasVendorId);
+ }
+
+ @Override
+ public void addVendorCommandListener(IHdmiVendorCommandListener listener, int deviceType) {
+ HdmiControlServiceWrapper.this.addVendorCommandListener(listener, deviceType);
+ }
+
+ @Override
+ public void sendStandby(int deviceType, int deviceId) {
+ HdmiControlServiceWrapper.this.sendStandby(deviceType, deviceId);
+ }
+
+ @Override
+ public void setHdmiRecordListener(IHdmiRecordListener callback) {
+ HdmiControlServiceWrapper.this.setHdmiRecordListener(callback);
+ }
+
+ @Override
+ public void startOneTouchRecord(int recorderAddress, byte[] recordSource) {
+ HdmiControlServiceWrapper.this.startOneTouchRecord(recorderAddress, recordSource);
+ }
+
+ @Override
+ public void stopOneTouchRecord(int recorderAddress) {
+ HdmiControlServiceWrapper.this.stopOneTouchRecord(recorderAddress);
+ }
+
+ @Override
+ public void startTimerRecording(int recorderAddress, int sourceType, byte[] recordSource) {
+ HdmiControlServiceWrapper.this.startTimerRecording(
+ recorderAddress, sourceType, recordSource);
+ }
+
+ @Override
+ public void clearTimerRecording(int recorderAddress, int sourceType, byte[] recordSource) {
+ HdmiControlServiceWrapper.this.clearTimerRecording(
+ recorderAddress, sourceType, recordSource);
+ }
+
+ @Override
+ public void sendMhlVendorCommand(int portId, int offset, int length, byte[] data) {
+ HdmiControlServiceWrapper.this.sendMhlVendorCommand(portId, offset, length, data);
+ }
+
+ @Override
+ public void addHdmiMhlVendorCommandListener(IHdmiMhlVendorCommandListener listener) {
+ HdmiControlServiceWrapper.this.addHdmiMhlVendorCommandListener(listener);
+ }
+
+ @Override
+ public void setStandbyMode(boolean isStandbyModeOn) {
+ HdmiControlServiceWrapper.this.setStandbyMode(isStandbyModeOn);
+ }
+
+ @Override
+ public void setHdmiCecVolumeControlEnabled(boolean isHdmiCecVolumeControlEnabled) {
+ HdmiControlServiceWrapper.this.setHdmiCecVolumeControlEnabled(
+ isHdmiCecVolumeControlEnabled);
+ }
+
+ @Override
+ public boolean isHdmiCecVolumeControlEnabled() {
+ return HdmiControlServiceWrapper.this.isHdmiCecVolumeControlEnabled();
+ }
+
+ @Override
+ public void reportAudioStatus(int deviceType, int volume, int maxVolume, boolean isMute) {
+ HdmiControlServiceWrapper.this.reportAudioStatus(deviceType, volume, maxVolume, isMute);
+ }
+
+ @Override
+ public void setSystemAudioModeOnForAudioOnlySource() {
+ HdmiControlServiceWrapper.this.setSystemAudioModeOnForAudioOnlySource();
+ }
+
+ @Override
+ public void addHdmiCecVolumeControlFeatureListener(
+ IHdmiCecVolumeControlFeatureListener listener) {
+ HdmiControlServiceWrapper.this.addHdmiCecVolumeControlFeatureListener(listener);
+ }
+
+ @Override
+ public void removeHdmiCecVolumeControlFeatureListener(
+ IHdmiCecVolumeControlFeatureListener listener) {
+ HdmiControlServiceWrapper.this.removeHdmiCecVolumeControlFeatureListener(listener);
+ }
+ };
+
+ @BinderThread
+ public void setPortInfo(@NonNull List<HdmiPortInfo> infoList) {
+ mInfoList = infoList;
+ }
+
+ @BinderThread
+ public void setDeviceTypes(@NonNull int[] types) {
+ mTypes = types;
+ }
+
+ /** @hide */
+ public List<HdmiPortInfo> getPortInfo() {
+ return mInfoList;
+ }
+
+ /** @hide */
+ public int[] getSupportedTypes() {
+ return mTypes;
+ }
+
+ /** @hide */
+ public HdmiDeviceInfo getActiveSource() {
+ return null;
+ }
+
+ /** @hide */
+ public void oneTouchPlay(IHdmiControlCallback callback) {}
+
+ /** @hide */
+ public void queryDisplayStatus(IHdmiControlCallback callback) {}
+
+ /** @hide */
+ public void addHdmiControlStatusChangeListener(IHdmiControlStatusChangeListener listener) {}
+
+ /** @hide */
+ public void removeHdmiControlStatusChangeListener(IHdmiControlStatusChangeListener listener) {}
+
+ /** @hide */
+ public void addHotplugEventListener(IHdmiHotplugEventListener listener) {}
+
+ /** @hide */
+ public void removeHotplugEventListener(IHdmiHotplugEventListener listener) {}
+
+ /** @hide */
+ public void addDeviceEventListener(IHdmiDeviceEventListener listener) {}
+
+ /** @hide */
+ public void deviceSelect(int deviceId, IHdmiControlCallback callback) {}
+
+ /** @hide */
+ public void portSelect(int portId, IHdmiControlCallback callback) {}
+
+ /** @hide */
+ public void sendKeyEvent(int deviceType, int keyCode, boolean isPressed) {}
+
+ /** @hide */
+ public void sendVolumeKeyEvent(int deviceType, int keyCode, boolean isPressed) {}
+
+ /** @hide */
+ public boolean canChangeSystemAudioMode() {
+ return true;
+ }
+
+ /** @hide */
+ public boolean getSystemAudioMode() {
+ return true;
+ }
+
+ /** @hide */
+ public int getPhysicalAddress() {
+ return 0xffff;
+ }
+
+ /** @hide */
+ public void setSystemAudioMode(boolean enabled, IHdmiControlCallback callback) {}
+
+ /** @hide */
+ public void addSystemAudioModeChangeListener(IHdmiSystemAudioModeChangeListener listener) {}
+
+ /** @hide */
+ public void removeSystemAudioModeChangeListener(IHdmiSystemAudioModeChangeListener listener) {}
+
+ /** @hide */
+ public void setArcMode(boolean enabled) {}
+
+ /** @hide */
+ public void setProhibitMode(boolean enabled) {}
+
+ /** @hide */
+ public void setSystemAudioVolume(int oldIndex, int newIndex, int maxIndex) {}
+
+ /** @hide */
+ public void setSystemAudioMute(boolean mute) {}
+
+ /** @hide */
+ public void setInputChangeListener(IHdmiInputChangeListener listener) {}
+
+ /** @hide */
+ public List<HdmiDeviceInfo> getInputDevices() {
+ return null;
+ }
+
+ /** @hide */
+ public List<HdmiDeviceInfo> getDeviceList() {
+ return null;
+ }
+
+ /** @hide */
+ public void powerOffRemoteDevice(int logicalAddress, int powerStatus) {}
+
+ /** @hide */
+ public void powerOnRemoteDevice(int logicalAddress, int powerStatus) {}
+
+ /** @hide */
+ public void askRemoteDeviceToBecomeActiveSource(int physicalAddress) {}
+
+ /** @hide */
+ public void sendVendorCommand(int deviceType, int targetAddress, byte[] params,
+ boolean hasVendorId) {}
+
+ /** @hide */
+ public void addVendorCommandListener(IHdmiVendorCommandListener listener, int deviceType) {}
+
+ /** @hide */
+ public void sendStandby(int deviceType, int deviceId) {}
+
+ /** @hide */
+ public void setHdmiRecordListener(IHdmiRecordListener callback) {}
+
+ /** @hide */
+ public void startOneTouchRecord(int recorderAddress, byte[] recordSource) {}
+
+ /** @hide */
+ public void stopOneTouchRecord(int recorderAddress) {}
+
+ /** @hide */
+ public void startTimerRecording(int recorderAddress, int sourceType, byte[] recordSource) {}
+
+ /** @hide */
+ public void clearTimerRecording(int recorderAddress, int sourceType, byte[] recordSource) {}
+
+ /** @hide */
+ public void sendMhlVendorCommand(int portId, int offset, int length, byte[] data) {}
+
+ /** @hide */
+ public void addHdmiMhlVendorCommandListener(IHdmiMhlVendorCommandListener listener) {}
+
+ /** @hide */
+ public void setStandbyMode(boolean isStandbyModeOn) {}
+
+ /** @hide */
+ public void setHdmiCecVolumeControlEnabled(boolean isHdmiCecVolumeControlEnabled) {}
+
+ /** @hide */
+ public boolean isHdmiCecVolumeControlEnabled() {
+ return true;
+ }
+
+ /** @hide */
+ public void reportAudioStatus(int deviceType, int volume, int maxVolume, boolean isMute) {}
+
+ /** @hide */
+ public void setSystemAudioModeOnForAudioOnlySource() {}
+
+ /** @hide */
+ public void addHdmiCecVolumeControlFeatureListener(
+ IHdmiCecVolumeControlFeatureListener listener) {}
+
+ /** @hide */
+ public void removeHdmiCecVolumeControlFeatureListener(
+ IHdmiCecVolumeControlFeatureListener listener) {}
+}
diff --git a/core/java/android/hardware/hdmi/HdmiPortInfo.java b/core/java/android/hardware/hdmi/HdmiPortInfo.java
index 2623458aff5b..52c3628f358b 100644
--- a/core/java/android/hardware/hdmi/HdmiPortInfo.java
+++ b/core/java/android/hardware/hdmi/HdmiPortInfo.java
@@ -18,6 +18,7 @@ package android.hardware.hdmi;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.SystemApi;
+import android.annotation.TestApi;
import android.os.Parcel;
import android.os.Parcelable;
@@ -28,6 +29,7 @@ import android.os.Parcelable;
* @hide
*/
@SystemApi
+@TestApi
public final class HdmiPortInfo implements Parcelable {
/** HDMI port type: Input */
public static final int PORT_INPUT = 0;
@@ -153,7 +155,9 @@ public final class HdmiPortInfo implements Parcelable {
* @param dest The Parcel in which the object should be written.
* @param flags Additional flags about how the object should be written.
* May be 0 or {@link Parcelable#PARCELABLE_WRITE_RETURN_VALUE}.
+ * @hide
*/
+ @SystemApi
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeInt(mId);
@@ -187,4 +191,9 @@ public final class HdmiPortInfo implements Parcelable {
&& mCecSupported == other.mCecSupported && mArcSupported == other.mArcSupported
&& mMhlSupported == other.mMhlSupported;
}
+
+ @Override
+ public int hashCode() {
+ return mId;
+ }
}
diff --git a/core/java/android/hardware/hdmi/HdmiSwitchClient.java b/core/java/android/hardware/hdmi/HdmiSwitchClient.java
index 7833653e41b0..913edfd0ebf4 100644
--- a/core/java/android/hardware/hdmi/HdmiSwitchClient.java
+++ b/core/java/android/hardware/hdmi/HdmiSwitchClient.java
@@ -18,6 +18,7 @@ package android.hardware.hdmi;
import android.annotation.CallbackExecutor;
import android.annotation.NonNull;
import android.annotation.SystemApi;
+import android.annotation.TestApi;
import android.hardware.hdmi.HdmiControlManager.ControlCallbackResult;
import android.os.Binder;
import android.os.RemoteException;
@@ -38,6 +39,7 @@ import java.util.concurrent.Executor;
* @hide
*/
@SystemApi
+@TestApi
public class HdmiSwitchClient extends HdmiClient {
private static final String TAG = "HdmiSwitchClient";
@@ -187,11 +189,8 @@ public class HdmiSwitchClient extends HdmiClient {
* <p>This returns an empty list when the current device does not have HDMI input.
*
* @return a list of {@link HdmiPortInfo}
- *
- * @hide
*/
@NonNull
- @SystemApi
public List<HdmiPortInfo> getPortInfo() {
try {
return mService.getPortInfo();
diff --git a/core/java/android/hardware/hdmi/IHdmiCecVolumeControlFeatureListener.aidl b/core/java/android/hardware/hdmi/IHdmiCecVolumeControlFeatureListener.aidl
new file mode 100644
index 000000000000..873438bb1d20
--- /dev/null
+++ b/core/java/android/hardware/hdmi/IHdmiCecVolumeControlFeatureListener.aidl
@@ -0,0 +1,32 @@
+/*
+ * 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 android.hardware.hdmi;
+
+/**
+ * Listener used to get the status of the HDMI CEC volume control feature (enabled/disabled).
+ * @hide
+ */
+oneway interface IHdmiCecVolumeControlFeatureListener {
+
+ /**
+ * Called when the HDMI Control (CEC) volume control feature is enabled/disabled.
+ *
+ * @param enabled status of HDMI CEC volume control feature
+ * @see {@link HdmiControlManager#setHdmiCecVolumeControlEnabled(boolean)} ()}
+ **/
+ void onHdmiCecVolumeControlFeature(boolean enabled);
+}
diff --git a/core/java/android/hardware/hdmi/IHdmiControlService.aidl b/core/java/android/hardware/hdmi/IHdmiControlService.aidl
index 3582a927ff46..4c724ef62ea9 100644
--- a/core/java/android/hardware/hdmi/IHdmiControlService.aidl
+++ b/core/java/android/hardware/hdmi/IHdmiControlService.aidl
@@ -18,6 +18,7 @@ package android.hardware.hdmi;
import android.hardware.hdmi.HdmiDeviceInfo;
import android.hardware.hdmi.HdmiPortInfo;
+import android.hardware.hdmi.IHdmiCecVolumeControlFeatureListener;
import android.hardware.hdmi.IHdmiControlCallback;
import android.hardware.hdmi.IHdmiControlStatusChangeListener;
import android.hardware.hdmi.IHdmiDeviceEventListener;
@@ -44,6 +45,8 @@ interface IHdmiControlService {
void queryDisplayStatus(IHdmiControlCallback callback);
void addHdmiControlStatusChangeListener(IHdmiControlStatusChangeListener listener);
void removeHdmiControlStatusChangeListener(IHdmiControlStatusChangeListener listener);
+ void addHdmiCecVolumeControlFeatureListener(IHdmiCecVolumeControlFeatureListener listener);
+ void removeHdmiCecVolumeControlFeatureListener(IHdmiCecVolumeControlFeatureListener listener);
void addHotplugEventListener(IHdmiHotplugEventListener listener);
void removeHotplugEventListener(IHdmiHotplugEventListener listener);
void addDeviceEventListener(IHdmiDeviceEventListener listener);
diff --git a/core/java/android/hardware/soundtrigger/ConversionUtil.java b/core/java/android/hardware/soundtrigger/ConversionUtil.java
index 425218a63cf7..c4d123ca4382 100644
--- a/core/java/android/hardware/soundtrigger/ConversionUtil.java
+++ b/core/java/android/hardware/soundtrigger/ConversionUtil.java
@@ -195,11 +195,14 @@ class ConversionUtil {
public static SoundTrigger.RecognitionEvent aidl2apiRecognitionEvent(
int modelHandle, RecognitionEvent aidlEvent) {
+ // The API recognition event doesn't allow for a null audio format, even though it doesn't
+ // always make sense. We thus replace it with a default.
+ AudioFormat audioFormat = aidl2apiAudioFormatWithDefault(aidlEvent.audioConfig);
return new SoundTrigger.GenericRecognitionEvent(
aidlEvent.status,
modelHandle, aidlEvent.captureAvailable, aidlEvent.captureSession,
aidlEvent.captureDelayMs, aidlEvent.capturePreambleMs, aidlEvent.triggerInData,
- aidl2apiAudioFormat(aidlEvent.audioConfig), aidlEvent.data);
+ audioFormat, aidlEvent.data);
}
public static SoundTrigger.RecognitionEvent aidl2apiPhraseRecognitionEvent(
@@ -210,11 +213,14 @@ class ConversionUtil {
for (int i = 0; i < aidlEvent.phraseExtras.length; ++i) {
apiExtras[i] = aidl2apiPhraseRecognitionExtra(aidlEvent.phraseExtras[i]);
}
+ // The API recognition event doesn't allow for a null audio format, even though it doesn't
+ // always make sense. We thus replace it with a default.
+ AudioFormat audioFormat = aidl2apiAudioFormatWithDefault(aidlEvent.common.audioConfig);
return new SoundTrigger.KeyphraseRecognitionEvent(aidlEvent.common.status, modelHandle,
aidlEvent.common.captureAvailable,
aidlEvent.common.captureSession, aidlEvent.common.captureDelayMs,
aidlEvent.common.capturePreambleMs, aidlEvent.common.triggerInData,
- aidl2apiAudioFormat(aidlEvent.common.audioConfig), aidlEvent.common.data,
+ audioFormat, aidlEvent.common.data,
apiExtras);
}
@@ -226,6 +232,14 @@ class ConversionUtil {
return apiBuilder.build();
}
+ // Same as above, but in case of a null input returns a non-null valid output.
+ public static AudioFormat aidl2apiAudioFormatWithDefault(@Nullable AudioConfig audioConfig) {
+ if (audioConfig != null) {
+ return aidl2apiAudioFormat(audioConfig);
+ }
+ return new AudioFormat.Builder().build();
+ }
+
public static int aidl2apiEncoding(int aidlFormat) {
switch (aidlFormat) {
case android.media.audio.common.AudioFormat.PCM
diff --git a/core/java/android/hardware/soundtrigger/SoundTriggerModule.java b/core/java/android/hardware/soundtrigger/SoundTriggerModule.java
index c1df5b6d2e7e..a2a15b30d578 100644
--- a/core/java/android/hardware/soundtrigger/SoundTriggerModule.java
+++ b/core/java/android/hardware/soundtrigger/SoundTriggerModule.java
@@ -303,7 +303,7 @@ public class SoundTriggerModule {
(SoundTrigger.RecognitionEvent) msg.obj);
break;
case EVENT_SERVICE_STATE_CHANGE:
- listener.onServiceStateChange(msg.arg1);
+ listener.onServiceStateChange((int) msg.obj);
break;
case EVENT_SERVICE_DIED:
listener.onServiceDied();
diff --git a/core/java/android/inputmethodservice/AbstractInputMethodService.java b/core/java/android/inputmethodservice/AbstractInputMethodService.java
index b0fca006d1e2..d7ca63a54987 100644
--- a/core/java/android/inputmethodservice/AbstractInputMethodService.java
+++ b/core/java/android/inputmethodservice/AbstractInputMethodService.java
@@ -260,4 +260,10 @@ public abstract class AbstractInputMethodService extends Service
*/
public void notifyUserActionIfNecessary() {
}
+
+ /** @hide */
+ @Override
+ public final boolean isUiContext() {
+ return true;
+ }
}
diff --git a/core/java/android/net/NetworkAgent.java b/core/java/android/net/NetworkAgent.java
index 65e772cb5ebb..482d2d2192b8 100644
--- a/core/java/android/net/NetworkAgent.java
+++ b/core/java/android/net/NetworkAgent.java
@@ -357,6 +357,7 @@ public abstract class NetworkAgent {
final NetworkInfo ni = new NetworkInfo(config.legacyType, config.legacyType,
config.legacyTypeName, "");
ni.setIsAvailable(true);
+ ni.setExtraInfo(config.getLegacyExtraInfo());
return ni;
}
diff --git a/core/java/android/net/NetworkAgentConfig.java b/core/java/android/net/NetworkAgentConfig.java
index fee868a93be4..fe1268d79b89 100644
--- a/core/java/android/net/NetworkAgentConfig.java
+++ b/core/java/android/net/NetworkAgentConfig.java
@@ -185,6 +185,26 @@ public final class NetworkAgentConfig implements Parcelable {
return legacyTypeName;
}
+ /**
+ * The legacy extra info of the agent. The extra info should only be :
+ * <ul>
+ * <li>For cellular agents, the APN name.</li>
+ * <li>For ethernet agents, the interface name.</li>
+ * </ul>
+ * @hide
+ */
+ @NonNull
+ private String mLegacyExtraInfo = "";
+
+ /**
+ * The legacy extra info of the agent.
+ * @hide
+ */
+ @NonNull
+ public String getLegacyExtraInfo() {
+ return mLegacyExtraInfo;
+ }
+
/** @hide */
public NetworkAgentConfig() {
}
@@ -201,6 +221,7 @@ public final class NetworkAgentConfig implements Parcelable {
skip464xlat = nac.skip464xlat;
legacyType = nac.legacyType;
legacyTypeName = nac.legacyTypeName;
+ mLegacyExtraInfo = nac.mLegacyExtraInfo;
}
}
@@ -309,6 +330,18 @@ public final class NetworkAgentConfig implements Parcelable {
}
/**
+ * Sets the legacy extra info of the agent.
+ * @param legacyExtraInfo the legacy extra info.
+ * @return this builder, to facilitate chaining.
+ * @hide
+ */
+ @NonNull
+ public Builder setLegacyExtraInfo(@NonNull String legacyExtraInfo) {
+ mConfig.mLegacyExtraInfo = legacyExtraInfo;
+ return this;
+ }
+
+ /**
* Returns the constructed {@link NetworkAgentConfig} object.
*/
@NonNull
@@ -330,14 +363,15 @@ public final class NetworkAgentConfig implements Parcelable {
&& skip464xlat == that.skip464xlat
&& legacyType == that.legacyType
&& Objects.equals(subscriberId, that.subscriberId)
- && Objects.equals(legacyTypeName, that.legacyTypeName);
+ && Objects.equals(legacyTypeName, that.legacyTypeName)
+ && Objects.equals(mLegacyExtraInfo, that.mLegacyExtraInfo);
}
@Override
public int hashCode() {
return Objects.hash(allowBypass, explicitlySelected, acceptUnvalidated,
acceptPartialConnectivity, provisioningNotificationDisabled, subscriberId,
- skip464xlat, legacyType, legacyTypeName);
+ skip464xlat, legacyType, legacyTypeName, mLegacyExtraInfo);
}
@Override
@@ -353,6 +387,7 @@ public final class NetworkAgentConfig implements Parcelable {
+ ", legacyType = " + legacyType
+ ", hasShownBroken = " + hasShownBroken
+ ", legacyTypeName = '" + legacyTypeName + '\''
+ + ", legacyExtraInfo = '" + mLegacyExtraInfo + '\''
+ "}";
}
@@ -372,6 +407,7 @@ public final class NetworkAgentConfig implements Parcelable {
out.writeInt(skip464xlat ? 1 : 0);
out.writeInt(legacyType);
out.writeString(legacyTypeName);
+ out.writeString(mLegacyExtraInfo);
}
public static final @NonNull Creator<NetworkAgentConfig> CREATOR =
@@ -388,6 +424,7 @@ public final class NetworkAgentConfig implements Parcelable {
networkAgentConfig.skip464xlat = in.readInt() != 0;
networkAgentConfig.legacyType = in.readInt();
networkAgentConfig.legacyTypeName = in.readString();
+ networkAgentConfig.mLegacyExtraInfo = in.readString();
return networkAgentConfig;
}
diff --git a/core/java/android/net/NetworkCapabilities.java b/core/java/android/net/NetworkCapabilities.java
index 9ded22fb70c6..a3fd60e9d3b0 100644
--- a/core/java/android/net/NetworkCapabilities.java
+++ b/core/java/android/net/NetworkCapabilities.java
@@ -679,13 +679,14 @@ public final class NetworkCapabilities implements Parcelable {
*/
public void restrictCapabilitesForTestNetwork(int creatorUid) {
final long originalCapabilities = mNetworkCapabilities;
+ final long originalTransportTypes = mTransportTypes;
final NetworkSpecifier originalSpecifier = mNetworkSpecifier;
final int originalSignalStrength = mSignalStrength;
final int originalOwnerUid = getOwnerUid();
final int[] originalAdministratorUids = getAdministratorUids();
clearAll();
- // Reset the transports to only contain TRANSPORT_TEST.
- mTransportTypes = (1 << TRANSPORT_TEST);
+ mTransportTypes = (originalTransportTypes & TEST_NETWORKS_ALLOWED_TRANSPORTS)
+ | (1 << TRANSPORT_TEST);
mNetworkCapabilities = originalCapabilities & TEST_NETWORKS_ALLOWED_CAPABILITIES;
mNetworkSpecifier = originalSpecifier;
mSignalStrength = originalSignalStrength;
@@ -787,6 +788,13 @@ public final class NetworkCapabilities implements Parcelable {
};
/**
+ * Allowed transports on a test network, in addition to TRANSPORT_TEST.
+ */
+ private static final int TEST_NETWORKS_ALLOWED_TRANSPORTS = 1 << TRANSPORT_TEST
+ // Test ethernet networks can be created with EthernetManager#setIncludeTestInterfaces
+ | 1 << TRANSPORT_ETHERNET;
+
+ /**
* Adds the given transport type to this {@code NetworkCapability} instance.
* Multiple transports may be applied. Note that when searching
* for a network to satisfy a request, any listed in the request will satisfy the request.
diff --git a/core/java/android/net/NetworkRequest.java b/core/java/android/net/NetworkRequest.java
index a6bd74a5870d..473e6c5a7287 100644
--- a/core/java/android/net/NetworkRequest.java
+++ b/core/java/android/net/NetworkRequest.java
@@ -468,8 +468,8 @@ public class NetworkRequest implements Parcelable {
}
/**
- * Returns true iff. the capabilities requested in this NetworkRequest are satisfied by the
- * provided {@link NetworkCapabilities}.
+ * Returns true if and only if the capabilities requested in this NetworkRequest are satisfied
+ * by the provided {@link NetworkCapabilities}.
*
* @param nc Capabilities that should satisfy this NetworkRequest. null capabilities do not
* satisfy any request.
diff --git a/core/java/android/os/AppZygote.java b/core/java/android/os/AppZygote.java
index 92574968e965..74b814ea4159 100644
--- a/core/java/android/os/AppZygote.java
+++ b/core/java/android/os/AppZygote.java
@@ -92,10 +92,9 @@ public class AppZygote {
@GuardedBy("mLock")
private void stopZygoteLocked() {
if (mZygote != null) {
- // Close the connection and kill the zygote process. This will not cause
- // child processes to be killed by itself.
mZygote.close();
- Process.killProcess(mZygote.getPid());
+ // use killProcessGroup() here, so we kill all untracked children as well.
+ Process.killProcessGroup(mZygoteUid, mZygote.getPid());
mZygote = null;
}
}
diff --git a/core/java/android/os/GraphicsEnvironment.java b/core/java/android/os/GraphicsEnvironment.java
index 034e6a7a06c4..df58a6c636f5 100644
--- a/core/java/android/os/GraphicsEnvironment.java
+++ b/core/java/android/os/GraphicsEnvironment.java
@@ -22,6 +22,7 @@ import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
import android.content.pm.ApplicationInfo;
+import android.content.pm.IPackageManager;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
@@ -93,8 +94,8 @@ public class GraphicsEnvironment {
private static final int GAME_DRIVER_GLOBAL_OPT_IN_OFF = 3;
private ClassLoader mClassLoader;
- private String mLayerPath;
- private String mDebugLayerPath;
+ private String mLibrarySearchPaths;
+ private String mLibraryPermittedPaths;
/**
* Set up GraphicsEnvironment
@@ -185,118 +186,131 @@ public class GraphicsEnvironment {
}
/**
- * Store the layer paths available to the loader.
+ * Store the class loader for namespace lookup later.
*/
public void setLayerPaths(ClassLoader classLoader,
- String layerPath,
- String debugLayerPath) {
+ String searchPaths,
+ String permittedPaths) {
// We have to store these in the class because they are set up before we
// have access to the Context to properly set up GraphicsEnvironment
mClassLoader = classLoader;
- mLayerPath = layerPath;
- mDebugLayerPath = debugLayerPath;
+ mLibrarySearchPaths = searchPaths;
+ mLibraryPermittedPaths = permittedPaths;
+ }
+
+ /**
+ * Returns the debug layer paths from settings.
+ * Returns null if:
+ * 1) The application process is not debuggable or layer injection metadata flag is not
+ * true; Or
+ * 2) ENABLE_GPU_DEBUG_LAYERS is not true; Or
+ * 3) Package name is not equal to GPU_DEBUG_APP.
+ */
+ public String getDebugLayerPathsFromSettings(
+ Bundle coreSettings, IPackageManager pm, String packageName,
+ ApplicationInfo ai) {
+ if (!debugLayerEnabled(coreSettings, packageName, ai)) {
+ return null;
+ }
+ Log.i(TAG, "GPU debug layers enabled for " + packageName);
+ String debugLayerPaths = "";
+
+ // Grab all debug layer apps and add to paths.
+ final String gpuDebugLayerApps =
+ coreSettings.getString(Settings.Global.GPU_DEBUG_LAYER_APP, "");
+ if (!gpuDebugLayerApps.isEmpty()) {
+ Log.i(TAG, "GPU debug layer apps: " + gpuDebugLayerApps);
+ // If a colon is present, treat this as multiple apps, so Vulkan and GLES
+ // layer apps can be provided at the same time.
+ final String[] layerApps = gpuDebugLayerApps.split(":");
+ for (int i = 0; i < layerApps.length; i++) {
+ String paths = getDebugLayerAppPaths(pm, layerApps[i]);
+ if (!paths.isEmpty()) {
+ // Append the path so files placed in the app's base directory will
+ // override the external path
+ debugLayerPaths += paths + File.pathSeparator;
+ }
+ }
+ }
+ return debugLayerPaths;
}
/**
* Return the debug layer app's on-disk and in-APK lib directories
*/
- private static String getDebugLayerAppPaths(PackageManager pm, String app) {
+ private static String getDebugLayerAppPaths(IPackageManager pm, String packageName) {
final ApplicationInfo appInfo;
try {
- appInfo = pm.getApplicationInfo(app, PackageManager.MATCH_ALL);
- } catch (PackageManager.NameNotFoundException e) {
- Log.w(TAG, "Debug layer app '" + app + "' not installed");
-
- return null;
+ appInfo = pm.getApplicationInfo(packageName, PackageManager.MATCH_ALL,
+ UserHandle.myUserId());
+ } catch (RemoteException e) {
+ return "";
+ }
+ if (appInfo == null) {
+ Log.w(TAG, "Debug layer app '" + packageName + "' not installed");
}
final String abi = chooseAbi(appInfo);
-
final StringBuilder sb = new StringBuilder();
sb.append(appInfo.nativeLibraryDir)
- .append(File.pathSeparator);
- sb.append(appInfo.sourceDir)
+ .append(File.pathSeparator)
+ .append(appInfo.sourceDir)
.append("!/lib/")
.append(abi);
final String paths = sb.toString();
-
if (DEBUG) Log.v(TAG, "Debug layer app libs: " + paths);
return paths;
}
+ private boolean debugLayerEnabled(Bundle coreSettings, String packageName, ApplicationInfo ai) {
+ // Only enable additional debug functionality if the following conditions are met:
+ // 1. App is debuggable or device is rooted or layer injection metadata flag is true
+ // 2. ENABLE_GPU_DEBUG_LAYERS is true
+ // 3. Package name is equal to GPU_DEBUG_APP
+ if (!isDebuggable() && !canInjectLayers(ai)) {
+ return false;
+ }
+ final int enable = coreSettings.getInt(Settings.Global.ENABLE_GPU_DEBUG_LAYERS, 0);
+ if (enable == 0) {
+ return false;
+ }
+ final String gpuDebugApp = coreSettings.getString(Settings.Global.GPU_DEBUG_APP, "");
+ if (packageName == null
+ || (gpuDebugApp.isEmpty() || packageName.isEmpty())
+ || !gpuDebugApp.equals(packageName)) {
+ return false;
+ }
+ return true;
+ }
+
/**
* Set up layer search paths for all apps
- * If debuggable, check for additional debug settings
*/
private void setupGpuLayers(
Context context, Bundle coreSettings, PackageManager pm, String packageName,
ApplicationInfo ai) {
+ final boolean enabled = debugLayerEnabled(coreSettings, packageName, ai);
String layerPaths = "";
+ if (enabled) {
+ layerPaths = mLibraryPermittedPaths;
- // Only enable additional debug functionality if the following conditions are met:
- // 1. App is debuggable or device is rooted or layer injection metadata flag is true
- // 2. ENABLE_GPU_DEBUG_LAYERS is true
- // 3. Package name is equal to GPU_DEBUG_APP
+ final String layers = coreSettings.getString(Settings.Global.GPU_DEBUG_LAYERS);
+ Log.i(TAG, "Vulkan debug layer list: " + layers);
+ if (layers != null && !layers.isEmpty()) {
+ setDebugLayers(layers);
+ }
- if (isDebuggable() || canInjectLayers(ai)) {
-
- final int enable = coreSettings.getInt(Settings.Global.ENABLE_GPU_DEBUG_LAYERS, 0);
-
- if (enable != 0) {
-
- final String gpuDebugApp = coreSettings.getString(Settings.Global.GPU_DEBUG_APP);
-
- if ((gpuDebugApp != null && packageName != null)
- && (!gpuDebugApp.isEmpty() && !packageName.isEmpty())
- && gpuDebugApp.equals(packageName)) {
- Log.i(TAG, "GPU debug layers enabled for " + packageName);
-
- // Prepend the debug layer path as a searchable path.
- // This will ensure debug layers added will take precedence over
- // the layers specified by the app.
- layerPaths = mDebugLayerPath + ":";
-
- // If there is a debug layer app specified, add its path.
- final String gpuDebugLayerApp =
- coreSettings.getString(Settings.Global.GPU_DEBUG_LAYER_APP);
-
- if (gpuDebugLayerApp != null && !gpuDebugLayerApp.isEmpty()) {
- Log.i(TAG, "GPU debug layer app: " + gpuDebugLayerApp);
- // If a colon is present, treat this as multiple apps, so Vulkan and GLES
- // layer apps can be provided at the same time.
- String[] layerApps = gpuDebugLayerApp.split(":");
- for (int i = 0; i < layerApps.length; i++) {
- String paths = getDebugLayerAppPaths(pm, layerApps[i]);
- if (paths != null) {
- // Append the path so files placed in the app's base directory will
- // override the external path
- layerPaths += paths + ":";
- }
- }
- }
-
- final String layers = coreSettings.getString(Settings.Global.GPU_DEBUG_LAYERS);
-
- Log.i(TAG, "Vulkan debug layer list: " + layers);
- if (layers != null && !layers.isEmpty()) {
- setDebugLayers(layers);
- }
-
- final String layersGLES =
- coreSettings.getString(Settings.Global.GPU_DEBUG_LAYERS_GLES);
-
- Log.i(TAG, "GLES debug layer list: " + layersGLES);
- if (layersGLES != null && !layersGLES.isEmpty()) {
- setDebugLayersGLES(layersGLES);
- }
- }
+ final String layersGLES =
+ coreSettings.getString(Settings.Global.GPU_DEBUG_LAYERS_GLES);
+ Log.i(TAG, "GLES debug layer list: " + layersGLES);
+ if (layersGLES != null && !layersGLES.isEmpty()) {
+ setDebugLayersGLES(layersGLES);
}
}
// Include the app's lib directory in all cases
- layerPaths += mLayerPath;
-
+ layerPaths += mLibrarySearchPaths;
setLayerPaths(mClassLoader, layerPaths);
}
diff --git a/core/java/android/os/StrictMode.java b/core/java/android/os/StrictMode.java
index 02b822a99f2a..772845d4e683 100644
--- a/core/java/android/os/StrictMode.java
+++ b/core/java/android/os/StrictMode.java
@@ -817,6 +817,9 @@ public final class StrictMode {
/** @hide */
public @NonNull Builder permitActivityLeaks() {
+ synchronized (StrictMode.class) {
+ sExpectedActivityInstanceCount.clear();
+ }
return disable(DETECT_VM_ACTIVITY_LEAKS);
}
@@ -2586,8 +2589,10 @@ public final class StrictMode {
return;
}
+ // Use the instance count from InstanceTracker as initial value.
Integer expected = sExpectedActivityInstanceCount.get(klass);
- Integer newExpected = expected == null ? 1 : expected + 1;
+ Integer newExpected =
+ expected == null ? InstanceTracker.getInstanceCount(klass) + 1 : expected + 1;
sExpectedActivityInstanceCount.put(klass, newExpected);
}
}
diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java
index 7845200f4bf7..a8391c2b5461 100644
--- a/core/java/android/os/UserManager.java
+++ b/core/java/android/os/UserManager.java
@@ -4090,13 +4090,6 @@ public class UserManager {
public static int getMaxSupportedUsers() {
// Don't allow multiple users on certain builds
if (android.os.Build.ID.startsWith("JVP")) return 1;
- if (ActivityManager.isLowRamDeviceStatic()) {
- // Low-ram devices are Svelte. Most of the time they don't get multi-user.
- if ((Resources.getSystem().getConfiguration().uiMode & Configuration.UI_MODE_TYPE_MASK)
- != Configuration.UI_MODE_TYPE_TELEVISION) {
- return 1;
- }
- }
return SystemProperties.getInt("fw.max_users",
Resources.getSystem().getInteger(R.integer.config_multiuserMaximumUsers));
}
diff --git a/core/java/android/os/ZygoteProcess.java b/core/java/android/os/ZygoteProcess.java
index a4c99c006d80..39038f555044 100644
--- a/core/java/android/os/ZygoteProcess.java
+++ b/core/java/android/os/ZygoteProcess.java
@@ -1318,15 +1318,15 @@ public class ZygoteProcess {
Process.ProcessStartResult result;
try {
- // As app zygote is for generating isolated process, at the end it can't access
- // apps data, so doesn't need to its data info.
+ // We will bind mount app data dirs so app zygote can't access /data/data, while
+ // we don't need to bind mount storage dirs as /storage won't be mounted.
result = startViaZygote(processClass, niceName, uid, gid,
gids, runtimeFlags, 0 /* mountExternal */, 0 /* targetSdkVersion */, seInfo,
abi, instructionSet, null /* appDataDir */, null /* invokeWith */,
true /* startChildZygote */, null /* packageName */,
ZYGOTE_POLICY_FLAG_SYSTEM_PROCESS /* zygotePolicyFlags */, false /* isTopApp */,
null /* disabledCompatChanges */, null /* pkgDataInfoMap */,
- null /* whitelistedDataInfoMap */, false /* bindMountAppsData*/,
+ null /* whitelistedDataInfoMap */, true /* bindMountAppsData*/,
/* bindMountAppStorageDirs */ false, extraArgs);
} catch (ZygoteStartFailedEx ex) {
diff --git a/core/java/android/os/storage/StorageManager.java b/core/java/android/os/storage/StorageManager.java
index 4ca48cb3e57c..e8806a03d00e 100644
--- a/core/java/android/os/storage/StorageManager.java
+++ b/core/java/android/os/storage/StorageManager.java
@@ -1365,6 +1365,7 @@ public class StorageManager {
String[] packageNames = ActivityThread.getPackageManager().getPackagesForUid(
android.os.Process.myUid());
if (packageNames == null || packageNames.length <= 0) {
+ Log.w(TAG, "Missing package names; no storage volumes available");
return new StorageVolume[0];
}
packageName = packageNames[0];
@@ -1372,6 +1373,7 @@ public class StorageManager {
final int uid = ActivityThread.getPackageManager().getPackageUid(packageName,
PackageManager.MATCH_DEBUG_TRIAGED_MISSING, userId);
if (uid <= 0) {
+ Log.w(TAG, "Missing UID; no storage volumes available");
return new StorageVolume[0];
}
return storageManager.getVolumeList(uid, packageName, flags);
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 1b19e1290121..e10fceaa5bc7 100755
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -1778,6 +1778,15 @@ public final class Settings {
= "android.settings.NOTIFICATION_SETTINGS";
/**
+ * Activity Action: Show conversation settings.
+ *
+ * @hide
+ */
+ @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
+ public static final String ACTION_CONVERSATION_SETTINGS
+ = "android.settings.CONVERSATION_SETTINGS";
+
+ /**
* Activity Action: Show notification history screen.
*
* @hide
@@ -14245,15 +14254,6 @@ public final class Settings {
public static final String KERNEL_CPU_THREAD_READER = "kernel_cpu_thread_reader";
/**
- * Persistent user id that is last logged in to.
- *
- * They map to user ids, for example, 10, 11, 12.
- *
- * @hide
- */
- public static final String LAST_ACTIVE_USER_ID = "last_active_persistent_user_id";
-
- /**
* Whether we've enabled native flags health check on this device. Takes effect on
* reboot. The value "1" enables native flags health check; otherwise it's disabled.
* @hide
diff --git a/core/java/android/provider/Telephony.java b/core/java/android/provider/Telephony.java
index b34268d04238..a2489b9b68d9 100644
--- a/core/java/android/provider/Telephony.java
+++ b/core/java/android/provider/Telephony.java
@@ -4325,6 +4325,15 @@ public final class Telephony {
public static final String ETWS_WARNING_TYPE = "etws_warning_type";
/**
+ * ETWS (Earthquake and Tsunami Warning System) primary message or not (ETWS alerts only).
+ * <p>See {@link android.telephony.SmsCbEtwsInfo}</p>
+ * <P>Type: BOOLEAN</P>
+ *
+ * @hide // TODO: Unhide this for S.
+ */
+ public static final String ETWS_IS_PRIMARY = "etws_is_primary";
+
+ /**
* CMAS (Commercial Mobile Alert System) message class (CMAS alerts only).
* <p>See {@link android.telephony.SmsCbCmasInfo}</p>
* <P>Type: INTEGER</P>
@@ -4464,37 +4473,6 @@ public final class Telephony {
CMAS_URGENCY,
CMAS_CERTAINTY
};
-
- /**
- * Query columns for instantiating {@link android.telephony.SmsCbMessage} objects.
- * @hide
- */
- public static final String[] QUERY_COLUMNS_FWK = {
- _ID,
- SLOT_INDEX,
- SUBSCRIPTION_ID,
- GEOGRAPHICAL_SCOPE,
- PLMN,
- LAC,
- CID,
- SERIAL_NUMBER,
- SERVICE_CATEGORY,
- LANGUAGE_CODE,
- MESSAGE_BODY,
- MESSAGE_FORMAT,
- MESSAGE_PRIORITY,
- ETWS_WARNING_TYPE,
- CMAS_MESSAGE_CLASS,
- CMAS_CATEGORY,
- CMAS_RESPONSE_TYPE,
- CMAS_SEVERITY,
- CMAS_URGENCY,
- CMAS_CERTAINTY,
- RECEIVED_TIME,
- MESSAGE_BROADCASTED,
- GEOMETRIES,
- MAXIMUM_WAIT_TIME
- };
}
/**
diff --git a/core/java/android/service/autofill/InlineSuggestionRoot.java b/core/java/android/service/autofill/InlineSuggestionRoot.java
index c879653859d8..16c3f1d4e476 100644
--- a/core/java/android/service/autofill/InlineSuggestionRoot.java
+++ b/core/java/android/service/autofill/InlineSuggestionRoot.java
@@ -58,7 +58,9 @@ public class InlineSuggestionRoot extends FrameLayout {
case MotionEvent.ACTION_DOWN: {
mDownX = event.getX();
mDownY = event.getY();
- } break;
+ }
+ // Intentionally fall through to the next case so that when the window is obscured
+ // we transfer the touch to the remote IME window and don't handle it locally.
case MotionEvent.ACTION_MOVE: {
final float distance = MathUtils.dist(mDownX, mDownY,
diff --git a/core/java/android/service/autofill/augmented/FillCallback.java b/core/java/android/service/autofill/augmented/FillCallback.java
index 21738d80f2d3..8ba5c173890c 100644
--- a/core/java/android/service/autofill/augmented/FillCallback.java
+++ b/core/java/android/service/autofill/augmented/FillCallback.java
@@ -62,9 +62,10 @@ public final class FillCallback {
List<Dataset> inlineSuggestions = response.getInlineSuggestions();
Bundle clientState = response.getClientState();
+ // We need to report result regardless of whether inline suggestions are returned or not.
+ mProxy.reportResult(inlineSuggestions, clientState);
if (inlineSuggestions != null && !inlineSuggestions.isEmpty()) {
mProxy.logEvent(AutofillProxy.REPORT_EVENT_INLINE_RESPONSE);
- mProxy.reportResult(inlineSuggestions, clientState);
return;
}
diff --git a/core/java/android/service/controls/Control.java b/core/java/android/service/controls/Control.java
index d01bc2524332..8383072a48e3 100644
--- a/core/java/android/service/controls/Control.java
+++ b/core/java/android/service/controls/Control.java
@@ -73,25 +73,37 @@ public final class Control implements Parcelable {
})
public @interface Status {};
+ /**
+ * Reserved for use with the {@link StatelessBuilder}, and while loading. When state is
+ * requested via {@link ControlsProviderService#createPublisherFor}, use other status codes
+ * to indicate the proper device state.
+ */
public static final int STATUS_UNKNOWN = 0;
/**
- * The device corresponding to the {@link Control} is responding correctly.
+ * Used to indicate that the state of the device was successfully retrieved. This includes
+ * all scenarios where the device may have a warning for the user, such as "Lock jammed",
+ * or "Vacuum stuck". Any information for the user should be set through
+ * {@link StatefulBuilder#setStatusText}.
*/
public static final int STATUS_OK = 1;
/**
- * The device corresponding to the {@link Control} cannot be found or was removed.
+ * The device corresponding to the {@link Control} cannot be found or was removed. The user
+ * will be alerted and directed to the application to resolve.
*/
public static final int STATUS_NOT_FOUND = 2;
/**
- * The device corresponding to the {@link Control} is in an error state.
+ * Used to indicate that there was a temporary error while loading the device state. A default
+ * error message will be displayed in place of any custom text that was set through
+ * {@link StatefulBuilder#setStatusText}.
*/
public static final int STATUS_ERROR = 3;
/**
- * The {@link Control} is currently disabled.
+ * The {@link Control} is currently disabled. A default error message will be displayed in
+ * place of any custom text that was set through {@link StatefulBuilder#setStatusText}.
*/
public static final int STATUS_DISABLED = 4;
diff --git a/core/java/android/service/notification/ZenModeConfig.java b/core/java/android/service/notification/ZenModeConfig.java
index 1f6555c85a66..0827fef60252 100644
--- a/core/java/android/service/notification/ZenModeConfig.java
+++ b/core/java/android/service/notification/ZenModeConfig.java
@@ -78,6 +78,7 @@ public class ZenModeConfig implements Parcelable {
private static final int DEFAULT_SOURCE = SOURCE_CONTACT;
private static final int DEFAULT_CALLS_SOURCE = SOURCE_STAR;
+ public static final String MANUAL_RULE_ID = "MANUAL_RULE";
public static final String EVENTS_DEFAULT_RULE_ID = "EVENTS_DEFAULT_RULE";
public static final String EVERY_NIGHT_DEFAULT_RULE_ID = "EVERY_NIGHT_DEFAULT_RULE";
public static final List<String> DEFAULT_RULE_IDS = Arrays.asList(EVERY_NIGHT_DEFAULT_RULE_ID,
@@ -959,6 +960,48 @@ public class ZenModeConfig implements Parcelable {
};
/**
+ * Converts a ZenModeConfig to a ZenPolicy
+ */
+ public ZenPolicy toZenPolicy() {
+ ZenPolicy.Builder builder = new ZenPolicy.Builder()
+ .allowCalls(allowCalls
+ ? ZenModeConfig.getZenPolicySenders(allowCallsFrom)
+ : ZenPolicy.PEOPLE_TYPE_NONE)
+ .allowRepeatCallers(allowRepeatCallers)
+ .allowMessages(allowMessages
+ ? ZenModeConfig.getZenPolicySenders(allowMessagesFrom)
+ : ZenPolicy.PEOPLE_TYPE_NONE)
+ .allowReminders(allowReminders)
+ .allowEvents(allowEvents)
+ .allowAlarms(allowAlarms)
+ .allowMedia(allowMedia)
+ .allowSystem(allowSystem)
+ .allowConversations(allowConversations
+ ? ZenModeConfig.getZenPolicySenders(allowConversationsFrom)
+ : ZenPolicy.PEOPLE_TYPE_NONE);
+ if (suppressedVisualEffects == 0) {
+ builder.showAllVisualEffects();
+ } else {
+ // configs don't have an unset state: wither true or false.
+ builder.showFullScreenIntent(
+ (suppressedVisualEffects & Policy.SUPPRESSED_EFFECT_FULL_SCREEN_INTENT) == 0);
+ builder.showLights(
+ (suppressedVisualEffects & SUPPRESSED_EFFECT_LIGHTS) == 0);
+ builder.showPeeking(
+ (suppressedVisualEffects & SUPPRESSED_EFFECT_PEEK) == 0);
+ builder.showStatusBarIcons(
+ (suppressedVisualEffects & Policy.SUPPRESSED_EFFECT_STATUS_BAR) == 0);
+ builder.showBadges(
+ (suppressedVisualEffects & Policy.SUPPRESSED_EFFECT_BADGE) == 0);
+ builder.showInAmbientDisplay(
+ (suppressedVisualEffects & Policy.SUPPRESSED_EFFECT_AMBIENT) == 0);
+ builder.showInNotificationList(
+ (suppressedVisualEffects & Policy.SUPPRESSED_EFFECT_NOTIFICATION_LIST) == 0);
+ }
+ return builder.build();
+ }
+
+ /**
* Converts a zenPolicy to a notificationPolicy using this ZenModeConfig's values as its
* defaults for all unset values in zenPolicy
*/
diff --git a/core/java/android/service/notification/ZenPolicy.java b/core/java/android/service/notification/ZenPolicy.java
index 87295e1c95b9..6d0bcffe148e 100644
--- a/core/java/android/service/notification/ZenPolicy.java
+++ b/core/java/android/service/notification/ZenPolicy.java
@@ -24,6 +24,7 @@ import android.os.Parcel;
import android.os.Parcelable;
import android.util.proto.ProtoOutputStream;
+import java.io.ByteArrayOutputStream;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
@@ -1111,6 +1112,40 @@ public final class ZenPolicy implements Parcelable {
}
/**
+ * Converts a policy to a statsd proto.
+ * @hides
+ */
+ public byte[] toProto() {
+ ByteArrayOutputStream bytes = new ByteArrayOutputStream();
+ ProtoOutputStream proto = new ProtoOutputStream(bytes);
+
+ proto.write(DNDPolicyProto.CALLS, getPriorityCategoryCalls());
+ proto.write(DNDPolicyProto.REPEAT_CALLERS, getPriorityCategoryRepeatCallers());
+ proto.write(DNDPolicyProto.MESSAGES, getPriorityCategoryMessages());
+ proto.write(DNDPolicyProto.CONVERSATIONS, getPriorityCategoryConversations());
+ proto.write(DNDPolicyProto.REMINDERS, getPriorityCategoryReminders());
+ proto.write(DNDPolicyProto.EVENTS, getPriorityCategoryEvents());
+ proto.write(DNDPolicyProto.ALARMS, getPriorityCategoryAlarms());
+ proto.write(DNDPolicyProto.MEDIA, getPriorityCategoryMedia());
+ proto.write(DNDPolicyProto.SYSTEM, getPriorityCategorySystem());
+
+ proto.write(DNDPolicyProto.FULLSCREEN, getVisualEffectFullScreenIntent());
+ proto.write(DNDPolicyProto.LIGHTS, getVisualEffectLights());
+ proto.write(DNDPolicyProto.PEEK, getVisualEffectPeek());
+ proto.write(DNDPolicyProto.STATUS_BAR, getVisualEffectStatusBar());
+ proto.write(DNDPolicyProto.BADGE, getVisualEffectBadge());
+ proto.write(DNDPolicyProto.AMBIENT, getVisualEffectAmbient());
+ proto.write(DNDPolicyProto.NOTIFICATION_LIST, getVisualEffectNotificationList());
+
+ proto.write(DNDPolicyProto.ALLOW_CALLS_FROM, getPriorityCallSenders());
+ proto.write(DNDPolicyProto.ALLOW_MESSAGES_FROM, getPriorityMessageSenders());
+ proto.write(DNDPolicyProto.ALLOW_CONVERSATIONS_FROM, getPriorityConversationSenders());
+
+ proto.flush();
+ return bytes.toByteArray();
+ }
+
+ /**
* Makes deep copy of this ZenPolicy.
* @hide
*/
diff --git a/core/java/android/service/voice/VoiceInteractionSession.java b/core/java/android/service/voice/VoiceInteractionSession.java
index 4a0dd870f797..0341b6d96b29 100644
--- a/core/java/android/service/voice/VoiceInteractionSession.java
+++ b/core/java/android/service/voice/VoiceInteractionSession.java
@@ -1311,7 +1311,7 @@ public class VoiceInteractionSession implements KeyEvent.Callback, ComponentCall
throw new IllegalStateException("Can't call before onCreate()");
}
try {
- intent.migrateExtraStreamToClipData();
+ intent.migrateExtraStreamToClipData(mContext);
intent.prepareToLeaveProcess(mContext);
int res = mSystemService.startVoiceActivity(mToken, intent,
intent.resolveType(mContext.getContentResolver()),
@@ -1340,7 +1340,7 @@ public class VoiceInteractionSession implements KeyEvent.Callback, ComponentCall
throw new IllegalStateException("Can't call before onCreate()");
}
try {
- intent.migrateExtraStreamToClipData();
+ intent.migrateExtraStreamToClipData(mContext);
intent.prepareToLeaveProcess(mContext);
int res = mSystemService.startAssistantActivity(mToken, intent,
intent.resolveType(mContext.getContentResolver()),
diff --git a/core/java/android/telephony/PhoneStateListener.java b/core/java/android/telephony/PhoneStateListener.java
index e4fbf9f0e187..ef21900dc3e3 100644
--- a/core/java/android/telephony/PhoneStateListener.java
+++ b/core/java/android/telephony/PhoneStateListener.java
@@ -157,8 +157,8 @@ public class PhoneStateListener {
* Listen for changes to the device's cell location. Note that
* this will result in frequent callbacks to the listener.
* {@more}
- * Requires Permission: {@link android.Manifest.permission#ACCESS_COARSE_LOCATION
- * ACCESS_COARSE_LOCATION}
+ * Requires Permission: {@link android.Manifest.permission#ACCESS_FINE_LOCATION
+ * ACCESS_FINE_LOCATION}
* <p>
* If you need regular location updates but want more control over
* the update interval or location precision, you can set up a listener
@@ -340,6 +340,10 @@ public class PhoneStateListener {
/**
* Listen for display info changed event.
*
+ * Requires Permission: {@link android.Manifest.permission#READ_PHONE_STATE
+ * READ_PHONE_STATE} or that the calling app has carrier privileges (see
+ * {@link TelephonyManager#hasCarrierPrivileges}).
+ *
* @see #onDisplayInfoChanged
*/
public static final int LISTEN_DISPLAY_INFO_CHANGED = 0x00100000;
diff --git a/core/java/android/view/GestureDetector.java b/core/java/android/view/GestureDetector.java
index f6c72c4eefbc..55c527ba6fa6 100644
--- a/core/java/android/view/GestureDetector.java
+++ b/core/java/android/view/GestureDetector.java
@@ -16,6 +16,8 @@
package android.view;
+import static android.os.StrictMode.vmIncorrectContextUseEnabled;
+
import static com.android.internal.util.FrameworkStatsLog.TOUCH_GESTURE_CLASSIFIED__CLASSIFICATION__DEEP_PRESS;
import static com.android.internal.util.FrameworkStatsLog.TOUCH_GESTURE_CLASSIFIED__CLASSIFICATION__DOUBLE_TAP;
import static com.android.internal.util.FrameworkStatsLog.TOUCH_GESTURE_CLASSIFIED__CLASSIFICATION__LONG_PRESS;
@@ -26,9 +28,12 @@ import static com.android.internal.util.FrameworkStatsLog.TOUCH_GESTURE_CLASSIFI
import android.compat.annotation.UnsupportedAppUsage;
import android.content.Context;
import android.os.Build;
+import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
+import android.os.StrictMode;
import android.os.SystemClock;
+import android.util.Log;
import com.android.internal.util.FrameworkStatsLog;
@@ -228,6 +233,7 @@ public class GestureDetector {
}
}
+ private static final String TAG = GestureDetector.class.getSimpleName();
@UnsupportedAppUsage
private int mTouchSlopSquare;
private int mDoubleTapTouchSlopSquare;
@@ -378,7 +384,8 @@ public class GestureDetector {
* You may only use this constructor from a {@link android.os.Looper} thread.
* @see android.os.Handler#Handler()
*
- * @param context the application's context
+ * @param context An {@link android.app.Activity} or a {@link Context} created from
+ * {@link Context#createWindowContext(int, Bundle)}
* @param listener the listener invoked for all the callbacks, this must
* not be null. If the listener implements the {@link OnDoubleTapListener} or
* {@link OnContextClickListener} then it will also be set as the listener for
@@ -395,7 +402,8 @@ public class GestureDetector {
* thread associated with the supplied {@link android.os.Handler}.
* @see android.os.Handler#Handler()
*
- * @param context the application's context
+ * @param context An {@link android.app.Activity} or a {@link Context} created from
+ * {@link Context#createWindowContext(int, Bundle)}
* @param listener the listener invoked for all the callbacks, this must
* not be null. If the listener implements the {@link OnDoubleTapListener} or
* {@link OnContextClickListener} then it will also be set as the listener for
@@ -425,7 +433,8 @@ public class GestureDetector {
* thread associated with the supplied {@link android.os.Handler}.
* @see android.os.Handler#Handler()
*
- * @param context the application's context
+ * @param context An {@link android.app.Activity} or a {@link Context} created from
+ * {@link Context#createWindowContext(int, Bundle)}
* @param listener the listener invoked for all the callbacks, this must
* not be null.
* @param handler the handler to use for running deferred listener events.
@@ -456,6 +465,17 @@ public class GestureDetector {
mMaximumFlingVelocity = ViewConfiguration.getMaximumFlingVelocity();
mAmbiguousGestureMultiplier = ViewConfiguration.getAmbiguousGestureMultiplier();
} else {
+ if (!context.isUiContext() && vmIncorrectContextUseEnabled()) {
+ final String errorMessage =
+ "Tried to access UI constants from a non-visual Context.";
+ final String message = "GestureDetector must be accessed from Activity or other "
+ + "visual Context. Use an Activity or a Context created with "
+ + "Context#createWindowContext(int, Bundle), which are adjusted to the "
+ + "configuration and visual bounds of an area on screen.";
+ final Exception exception = new IllegalArgumentException(errorMessage);
+ StrictMode.onIncorrectContextUsed(message, exception);
+ Log.e(TAG, errorMessage + message, exception);
+ }
final ViewConfiguration configuration = ViewConfiguration.get(context);
touchSlop = configuration.getScaledTouchSlop();
doubleTapTouchSlop = configuration.getScaledDoubleTapTouchSlop();
diff --git a/core/java/android/view/ImeFocusController.java b/core/java/android/view/ImeFocusController.java
index a4800726bbe8..825077ffd57a 100644
--- a/core/java/android/view/ImeFocusController.java
+++ b/core/java/android/view/ImeFocusController.java
@@ -125,6 +125,13 @@ public final class ImeFocusController {
final View viewForWindowFocus = focusedView != null ? focusedView : mViewRootImpl.mView;
onViewFocusChanged(viewForWindowFocus, true);
+ // Skip starting input when the next focused view is same as served view and the served
+ // input connection still exists.
+ final boolean nextFocusIsServedView = mServedView != null && mServedView == focusedView;
+ if (nextFocusIsServedView && immDelegate.isAcceptingText()) {
+ forceFocus = false;
+ }
+
immDelegate.startInputAsyncOnWindowFocusGain(viewForWindowFocus,
windowAttribute.softInputMode, windowAttribute.flags, forceFocus);
}
@@ -247,6 +254,7 @@ public final class ImeFocusController {
void setCurrentRootView(ViewRootImpl rootView);
boolean isCurrentRootView(ViewRootImpl rootView);
boolean isRestartOnNextWindowFocus(boolean reset);
+ boolean isAcceptingText();
}
public View getServedView() {
diff --git a/core/java/android/view/InsetsController.java b/core/java/android/view/InsetsController.java
index ef9edc6c0741..e4d53c64a063 100644
--- a/core/java/android/view/InsetsController.java
+++ b/core/java/android/view/InsetsController.java
@@ -791,7 +791,7 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation
WindowInsetsAnimationControlListener listener,
boolean fromIme, long durationMs, @Nullable Interpolator interpolator,
@AnimationType int animationType) {
- if (!checkDisplayFramesForControlling()) {
+ if ((mState.calculateUncontrollableInsetsFromFrame(mFrame) & types) != 0) {
listener.onCancelled(null);
return;
}
@@ -801,13 +801,6 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation
false /* useInsetsAnimationThread */);
}
- private boolean checkDisplayFramesForControlling() {
-
- // If the frame of our window doesn't span the entire display, the control API makes very
- // little sense, as we don't deal with negative insets. So just cancel immediately.
- return mState.getDisplayFrame().equals(mFrame);
- }
-
private void controlAnimationUnchecked(@InsetsType int types,
@Nullable CancellationSignal cancellationSignal,
WindowInsetsAnimationControlListener listener, Rect frame, boolean fromIme,
@@ -1285,9 +1278,6 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation
}
private @InsetsType int calculateControllableTypes() {
- if (!checkDisplayFramesForControlling()) {
- return 0;
- }
@InsetsType int result = 0;
for (int i = mSourceConsumers.size() - 1; i >= 0; i--) {
InsetsSourceConsumer consumer = mSourceConsumers.valueAt(i);
@@ -1295,7 +1285,7 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation
result |= toPublicType(consumer.mType);
}
}
- return result;
+ return result & ~mState.calculateUncontrollableInsetsFromFrame(mFrame);
}
/**
diff --git a/core/java/android/view/InsetsSourceConsumer.java b/core/java/android/view/InsetsSourceConsumer.java
index 3869484468ae..ae70a4971776 100644
--- a/core/java/android/view/InsetsSourceConsumer.java
+++ b/core/java/android/view/InsetsSourceConsumer.java
@@ -22,6 +22,8 @@ import static android.view.InsetsState.getDefaultVisibility;
import static android.view.InsetsController.DEBUG;
import static android.view.InsetsState.toPublicType;
+import static com.android.internal.annotations.VisibleForTesting.Visibility.PACKAGE;
+
import android.annotation.IntDef;
import android.annotation.Nullable;
import android.graphics.Rect;
@@ -271,10 +273,13 @@ public class InsetsSourceConsumer {
// no-op for types that always return ShowResult#SHOW_IMMEDIATELY.
}
- void updateSource(InsetsSource newSource) {
+ @VisibleForTesting(visibility = PACKAGE)
+ public void updateSource(InsetsSource newSource) {
InsetsSource source = mState.peekSource(mType);
if (source == null || mController.getAnimationType(mType) == ANIMATION_TYPE_NONE
|| source.getFrame().equals(newSource.getFrame())) {
+ mPendingFrame = null;
+ mPendingVisibleFrame = null;
mState.addSource(newSource);
return;
}
@@ -292,7 +297,8 @@ public class InsetsSourceConsumer {
if (DEBUG) Log.d(TAG, "updateSource: " + newSource);
}
- boolean notifyAnimationFinished() {
+ @VisibleForTesting(visibility = PACKAGE)
+ public boolean notifyAnimationFinished() {
if (mPendingFrame != null) {
InsetsSource source = mState.getSource(mType);
source.setFrame(mPendingFrame);
diff --git a/core/java/android/view/InsetsState.java b/core/java/android/view/InsetsState.java
index 3822ee59b4aa..f0bca260be38 100644
--- a/core/java/android/view/InsetsState.java
+++ b/core/java/android/view/InsetsState.java
@@ -245,6 +245,44 @@ public class InsetsState implements Parcelable {
return insets.toRect();
}
+ /**
+ * Calculate which insets *cannot* be controlled, because the frame does not cover the
+ * respective side of the inset.
+ *
+ * If the frame of our window doesn't cover the entire inset, the control API makes very
+ * little sense, as we don't deal with negative insets.
+ */
+ @InsetsType
+ public int calculateUncontrollableInsetsFromFrame(Rect frame) {
+ int blocked = 0;
+ for (int type = FIRST_TYPE; type <= LAST_TYPE; type++) {
+ InsetsSource source = mSources.get(type);
+ if (source == null) {
+ continue;
+ }
+ if (!canControlSide(frame, getInsetSide(
+ source.calculateInsets(frame, true /* ignoreVisibility */)))) {
+ blocked |= toPublicType(type);
+ }
+ }
+ return blocked;
+ }
+
+ private boolean canControlSide(Rect frame, int side) {
+ switch (side) {
+ case ISIDE_LEFT:
+ case ISIDE_RIGHT:
+ return frame.left == mDisplayFrame.left && frame.right == mDisplayFrame.right;
+ case ISIDE_TOP:
+ case ISIDE_BOTTOM:
+ return frame.top == mDisplayFrame.top && frame.bottom == mDisplayFrame.bottom;
+ case ISIDE_FLOATING:
+ return true;
+ default:
+ return false;
+ }
+ }
+
private void processSource(InsetsSource source, Rect relativeFrame, boolean ignoreVisibility,
Insets[] typeInsetsMap, @Nullable @InternalInsetsSide SparseIntArray typeSideMap,
@Nullable boolean[] typeVisibilityMap) {
diff --git a/core/java/android/view/SurfaceControl.java b/core/java/android/view/SurfaceControl.java
index 9109f50247e0..6f73e8985a8a 100644
--- a/core/java/android/view/SurfaceControl.java
+++ b/core/java/android/view/SurfaceControl.java
@@ -323,6 +323,14 @@ public final class SurfaceControl implements Parcelable {
public static final int CURSOR_WINDOW = 0x00002000;
/**
+ * Surface creation flag: Indicates the effect layer will not have a color fill on
+ * creation.
+ *
+ * @hide
+ */
+ public static final int NO_COLOR_FILL = 0x00004000;
+
+ /**
* Surface creation flag: Creates a normal surface.
* This is the default.
*
@@ -577,7 +585,7 @@ public final class SurfaceControl implements Parcelable {
throw new IllegalStateException(
"width and height must be positive or unset");
}
- if ((mWidth > 0 || mHeight > 0) && (isColorLayerSet() || isContainerLayerSet())) {
+ if ((mWidth > 0 || mHeight > 0) && (isEffectLayer() || isContainerLayer())) {
throw new IllegalStateException(
"Only buffer layers can set a valid buffer size.");
}
@@ -749,10 +757,27 @@ public final class SurfaceControl implements Parcelable {
}
/**
- * Indicate whether a 'ColorLayer' is to be constructed.
+ * Indicate whether an 'EffectLayer' is to be constructed.
+ *
+ * An effect layer behaves like a container layer by default but it can support
+ * color fill, shadows and/or blur. These layers will not have an associated buffer.
+ * When created, this layer has no effects set and will be transparent but the caller
+ * can render an effect by calling:
+ * - {@link Transaction#setColor(SurfaceControl, float[])}
+ * - {@link Transaction#setBackgroundBlurRadius(SurfaceControl, int)}
+ * - {@link Transaction#setShadowRadius(SurfaceControl, float)}
*
- * Color layers will not have an associated BufferQueue and will instead always render a
- * solid color (that is, solid before plane alpha). Currently that color is black.
+ * @hide
+ */
+ public Builder setEffectLayer() {
+ mFlags |= NO_COLOR_FILL;
+ unsetBufferSize();
+ return setFlags(FX_SURFACE_EFFECT, FX_SURFACE_MASK);
+ }
+
+ /**
+ * A convenience function to create an effect layer with a default color fill
+ * applied to it. Currently that color is black.
*
* @hide
*/
@@ -761,7 +786,7 @@ public final class SurfaceControl implements Parcelable {
return setFlags(FX_SURFACE_EFFECT, FX_SURFACE_MASK);
}
- private boolean isColorLayerSet() {
+ private boolean isEffectLayer() {
return (mFlags & FX_SURFACE_EFFECT) == FX_SURFACE_EFFECT;
}
@@ -786,7 +811,7 @@ public final class SurfaceControl implements Parcelable {
return setFlags(FX_SURFACE_CONTAINER, FX_SURFACE_MASK);
}
- private boolean isContainerLayerSet() {
+ private boolean isContainerLayer() {
return (mFlags & FX_SURFACE_CONTAINER) == FX_SURFACE_CONTAINER;
}
diff --git a/core/java/android/view/SurfaceView.java b/core/java/android/view/SurfaceView.java
index bd811fc1f052..57f91ed3c0ae 100644
--- a/core/java/android/view/SurfaceView.java
+++ b/core/java/android/view/SurfaceView.java
@@ -134,6 +134,7 @@ public class SurfaceView extends View implements ViewRootImpl.SurfaceChangedCall
// we need to preserve the old one until the new one has drawn.
SurfaceControl mDeferredDestroySurfaceControl;
SurfaceControl mBackgroundControl;
+ private boolean mDisableBackgroundLayer = false;
/**
* We use this lock in SOME cases when reading or writing SurfaceControl,
@@ -245,10 +246,17 @@ public class SurfaceView extends View implements ViewRootImpl.SurfaceChangedCall
}
public SurfaceView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
+ this(context, attrs, defStyleAttr, defStyleRes, false);
+ }
+
+ /** @hide */
+ public SurfaceView(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr,
+ int defStyleRes, boolean disableBackgroundLayer) {
super(context, attrs, defStyleAttr, defStyleRes);
mRenderNode.addPositionUpdateListener(mPositionListener);
setWillNotDraw(true);
+ mDisableBackgroundLayer = disableBackgroundLayer;
}
/**
@@ -839,7 +847,8 @@ public class SurfaceView extends View implements ViewRootImpl.SurfaceChangedCall
if (mBackgroundControl == null) {
return;
}
- if ((mSubLayer < 0) && ((mSurfaceFlags & SurfaceControl.OPAQUE) != 0)) {
+ if ((mSubLayer < 0) && ((mSurfaceFlags & SurfaceControl.OPAQUE) != 0)
+ && !mDisableBackgroundLayer) {
t.show(mBackgroundControl);
} else {
t.hide(mBackgroundControl);
@@ -1200,8 +1209,10 @@ public class SurfaceView extends View implements ViewRootImpl.SurfaceChangedCall
}
if (mDeferredDestroySurfaceControl != null) {
- mTmpTransaction.remove(mDeferredDestroySurfaceControl).apply();
- mDeferredDestroySurfaceControl = null;
+ synchronized (mSurfaceControlLock) {
+ mTmpTransaction.remove(mDeferredDestroySurfaceControl).apply();
+ mDeferredDestroySurfaceControl = null;
+ }
}
runOnUiThread(this::performDrawFinished);
diff --git a/core/java/android/view/WindowlessWindowManager.java b/core/java/android/view/WindowlessWindowManager.java
index 9b5b8824b0e6..a5ec4e900641 100644
--- a/core/java/android/view/WindowlessWindowManager.java
+++ b/core/java/android/view/WindowlessWindowManager.java
@@ -209,7 +209,11 @@ public class WindowlessWindowManager implements IWindowSession {
/** @hide */
protected SurfaceControl getSurfaceControl(View rootView) {
- final State s = mStateForWindow.get(rootView.getViewRootImpl().mWindow.asBinder());
+ final ViewRootImpl root = rootView.getViewRootImpl();
+ if (root == null) {
+ return null;
+ }
+ final State s = mStateForWindow.get(root.mWindow.asBinder());
if (s == null) {
return null;
}
diff --git a/core/java/android/view/accessibility/AccessibilityNodeInfo.java b/core/java/android/view/accessibility/AccessibilityNodeInfo.java
index eaaaa80f65ed..214da380ccda 100644
--- a/core/java/android/view/accessibility/AccessibilityNodeInfo.java
+++ b/core/java/android/view/accessibility/AccessibilityNodeInfo.java
@@ -635,7 +635,7 @@ public class AccessibilityNodeInfo implements Parcelable {
"android.view.accessibility.extra.DATA_TEXT_CHARACTER_LOCATION_ARG_LENGTH";
/**
- * Key used to request extra data for accessibility scanning tool's purposes.
+ * Key used to request extra data for the rendering information.
* The key requests that a {@link AccessibilityNodeInfo.ExtraRenderingInfo} be added to this
* info. This request is made with {@link #refreshWithExtraData(String, Bundle)} without
* argument.
@@ -5847,12 +5847,15 @@ public class AccessibilityNodeInfo implements Parcelable {
}
/**
- * Gets the size object containing the height and the width of layout params if the node is
- * a {@link ViewGroup} or a {@link TextView}, or null otherwise. Useful for accessibility
- * scanning tool to understand whether the text is scalable and fits the view or not.
+ * Gets the size object containing the height and the width of
+ * {@link android.view.ViewGroup.LayoutParams} if the node is a {@link ViewGroup} or
+ * a {@link TextView}, or null otherwise. Useful for some accessibility services to
+ * understand whether the text is scalable and fits the view or not.
*
- * @return a {@link Size} stores layout height and layout width of the view,
- * or null otherwise.
+ * @return a {@link Size} stores layout height and layout width of the view, or null
+ * otherwise. And the size value may be in pixels,
+ * {@link android.view.ViewGroup.LayoutParams#MATCH_PARENT},
+ * or {@link android.view.ViewGroup.LayoutParams#WRAP_CONTENT}
*/
public @Nullable Size getLayoutSize() {
return mLayoutSize;
@@ -5870,9 +5873,9 @@ public class AccessibilityNodeInfo implements Parcelable {
}
/**
- * Gets the text size if the node is a {@link TextView}, or -1 otherwise. Useful for
- * accessibility scanning tool to understand whether the text is scalable and fits the view
- * or not.
+ * Gets the text size if the node is a {@link TextView}, or -1 otherwise. Useful for some
+ * accessibility services to understand whether the text is scalable and fits the view or
+ * not.
*
* @return the text size of a {@code TextView}, or -1 otherwise.
*/
@@ -5893,7 +5896,7 @@ public class AccessibilityNodeInfo implements Parcelable {
/**
* Gets the text size unit if the node is a {@link TextView}, or -1 otherwise.
* Text size returned from {@link #getTextSizeInPx} in raw pixels may scale by factors and
- * convert from other units. Useful for accessibility scanning tool to understand whether
+ * convert from other units. Useful for some accessibility services to understand whether
* the text is scalable and fits the view or not.
*
* @return the text size unit which type is {@link TypedValue#TYPE_DIMENSION} of a
diff --git a/core/java/android/view/autofill/AutofillId.java b/core/java/android/view/autofill/AutofillId.java
index b387a68dd8a3..68943bf2a83a 100644
--- a/core/java/android/view/autofill/AutofillId.java
+++ b/core/java/android/view/autofill/AutofillId.java
@@ -75,7 +75,10 @@ public final class AutofillId implements Parcelable {
/** @hide */
public static AutofillId withoutSession(@NonNull AutofillId id) {
final int flags = id.mFlags & ~FLAG_HAS_SESSION;
- return new AutofillId(flags, id.mViewId, id.mVirtualLongId, NO_SESSION);
+ final long virtualChildId =
+ ((id.mFlags & FLAG_IS_VIRTUAL_LONG) != 0) ? id.mVirtualLongId
+ : id.mVirtualIntId;
+ return new AutofillId(flags, id.mViewId, virtualChildId, NO_SESSION);
}
/** @hide */
diff --git a/core/java/android/view/autofill/AutofillManager.java b/core/java/android/view/autofill/AutofillManager.java
index 3112039c36d8..fbfeda6f0bcc 100644
--- a/core/java/android/view/autofill/AutofillManager.java
+++ b/core/java/android/view/autofill/AutofillManager.java
@@ -751,6 +751,8 @@ public final class AutofillManager {
}
} catch (RemoteException e) {
Log.e(TAG, "Could not figure out if there was an autofill session", e);
+ } catch (SyncResultReceiver.TimeoutException e) {
+ Log.e(TAG, "Fail to get session restore status: " + e);
}
}
}
@@ -864,7 +866,9 @@ public final class AutofillManager {
mService.getFillEventHistory(receiver);
return receiver.getParcelableResult();
} catch (RemoteException e) {
- e.rethrowFromSystemServer();
+ throw e.rethrowFromSystemServer();
+ } catch (SyncResultReceiver.TimeoutException e) {
+ Log.e(TAG, "Fail to get fill event history: " + e);
return null;
}
}
@@ -1477,10 +1481,13 @@ public final class AutofillManager {
final SyncResultReceiver receiver = new SyncResultReceiver(SYNC_CALLS_TIMEOUT_MS);
try {
- mService.isServiceEnabled(mContext.getUserId(), mContext.getPackageName(), receiver);
+ mService.isServiceEnabled(mContext.getUserId(), mContext.getPackageName(),
+ receiver);
return receiver.getIntResult() == 1;
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
+ } catch (SyncResultReceiver.TimeoutException e) {
+ throw new RuntimeException("Fail to get enabled autofill services status.");
}
}
@@ -1498,6 +1505,8 @@ public final class AutofillManager {
return receiver.getParcelableResult();
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
+ } catch (SyncResultReceiver.TimeoutException e) {
+ throw new RuntimeException("Fail to get autofill services component name.");
}
}
@@ -1522,8 +1531,9 @@ public final class AutofillManager {
mService.getUserDataId(receiver);
return receiver.getStringResult();
} catch (RemoteException e) {
- e.rethrowFromSystemServer();
- return null;
+ throw e.rethrowFromSystemServer();
+ } catch (SyncResultReceiver.TimeoutException e) {
+ throw new RuntimeException("Fail to get user data id for field classification.");
}
}
@@ -1544,8 +1554,9 @@ public final class AutofillManager {
mService.getUserData(receiver);
return receiver.getParcelableResult();
} catch (RemoteException e) {
- e.rethrowFromSystemServer();
- return null;
+ throw e.rethrowFromSystemServer();
+ } catch (SyncResultReceiver.TimeoutException e) {
+ throw new RuntimeException("Fail to get user data for field classification.");
}
}
@@ -1561,7 +1572,7 @@ public final class AutofillManager {
try {
mService.setUserData(userData);
} catch (RemoteException e) {
- e.rethrowFromSystemServer();
+ throw e.rethrowFromSystemServer();
}
}
@@ -1583,8 +1594,9 @@ public final class AutofillManager {
mService.isFieldClassificationEnabled(receiver);
return receiver.getIntResult() == 1;
} catch (RemoteException e) {
- e.rethrowFromSystemServer();
- return false;
+ throw e.rethrowFromSystemServer();
+ } catch (SyncResultReceiver.TimeoutException e) {
+ throw new RuntimeException("Fail to get field classification enabled status.");
}
}
@@ -1606,8 +1618,9 @@ public final class AutofillManager {
mService.getDefaultFieldClassificationAlgorithm(receiver);
return receiver.getStringResult();
} catch (RemoteException e) {
- e.rethrowFromSystemServer();
- return null;
+ throw e.rethrowFromSystemServer();
+ } catch (SyncResultReceiver.TimeoutException e) {
+ throw new RuntimeException("Fail to get default field classification algorithm.");
}
}
@@ -1627,8 +1640,9 @@ public final class AutofillManager {
final String[] algorithms = receiver.getStringArrayResult();
return algorithms != null ? Arrays.asList(algorithms) : Collections.emptyList();
} catch (RemoteException e) {
- e.rethrowFromSystemServer();
- return null;
+ throw e.rethrowFromSystemServer();
+ } catch (SyncResultReceiver.TimeoutException e) {
+ throw new RuntimeException("Fail to get available field classification algorithms.");
}
}
@@ -1651,6 +1665,8 @@ public final class AutofillManager {
return receiver.getIntResult() == 1;
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
+ } catch (SyncResultReceiver.TimeoutException e) {
+ throw new RuntimeException("Fail to get autofill supported status.");
}
}
@@ -2040,13 +2056,16 @@ public final class AutofillManager {
}
final SyncResultReceiver resultReceiver = new SyncResultReceiver(SYNC_CALLS_TIMEOUT_MS);
- final int resultCode;
+ int resultCode;
try {
mService.setAugmentedAutofillWhitelist(toList(packages), toList(activities),
resultReceiver);
resultCode = resultReceiver.getIntResult();
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
+ } catch (SyncResultReceiver.TimeoutException e) {
+ Log.e(TAG, "Fail to get the result of set AugmentedAutofill whitelist. " + e);
+ return;
}
switch (resultCode) {
case RESULT_OK:
@@ -2283,7 +2302,7 @@ public final class AutofillManager {
// In theory, we could ignore this error since it's not a big deal, but
// in reality, we rather crash the app anyways, as the failure could be
// a consequence of something going wrong on the server side...
- e.rethrowFromSystemServer();
+ throw e.rethrowFromSystemServer();
}
}
@@ -2661,7 +2680,7 @@ public final class AutofillManager {
try {
mService.onPendingSaveUi(operation, token);
} catch (RemoteException e) {
- e.rethrowFromSystemServer();
+ Log.e(TAG, "Error in onPendingSaveUi: ", e);
}
}
}
diff --git a/core/java/android/view/contentcapture/ContentCaptureManager.java b/core/java/android/view/contentcapture/ContentCaptureManager.java
index 756ff78e5906..484b1c10423c 100644
--- a/core/java/android/view/contentcapture/ContentCaptureManager.java
+++ b/core/java/android/view/contentcapture/ContentCaptureManager.java
@@ -487,6 +487,8 @@ public final class ContentCaptureManager {
return resultReceiver.getParcelableResult();
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
+ } catch (SyncResultReceiver.TimeoutException e) {
+ throw new RuntimeException("Fail to get service componentName.");
}
}
@@ -516,6 +518,9 @@ public final class ContentCaptureManager {
return resultReceiver.getParcelableResult();
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
+ } catch (SyncResultReceiver.TimeoutException e) {
+ Log.e(TAG, "Fail to get service settings componentName: " + e);
+ return null;
}
}
@@ -567,9 +572,13 @@ public final class ContentCaptureManager {
final SyncResultReceiver resultReceiver = syncRun(
(r) -> mService.getContentCaptureConditions(mContext.getPackageName(), r));
- final ArrayList<ContentCaptureCondition> result = resultReceiver
- .getParcelableListResult();
- return toSet(result);
+ try {
+ final ArrayList<ContentCaptureCondition> result = resultReceiver
+ .getParcelableListResult();
+ return toSet(result);
+ } catch (SyncResultReceiver.TimeoutException e) {
+ throw new RuntimeException("Fail to get content capture conditions.");
+ }
}
/**
@@ -639,15 +648,21 @@ public final class ContentCaptureManager {
public boolean isContentCaptureFeatureEnabled() {
final SyncResultReceiver resultReceiver = syncRun(
(r) -> mService.isContentCaptureFeatureEnabled(r));
- final int resultCode = resultReceiver.getIntResult();
- switch (resultCode) {
- case RESULT_CODE_TRUE:
- return true;
- case RESULT_CODE_FALSE:
- return false;
- default:
- Log.wtf(TAG, "received invalid result: " + resultCode);
- return false;
+
+ try {
+ final int resultCode = resultReceiver.getIntResult();
+ switch (resultCode) {
+ case RESULT_CODE_TRUE:
+ return true;
+ case RESULT_CODE_FALSE:
+ return false;
+ default:
+ Log.wtf(TAG, "received invalid result: " + resultCode);
+ return false;
+ }
+ } catch (SyncResultReceiver.TimeoutException e) {
+ Log.e(TAG, "Fail to get content capture feature enable status: " + e);
+ return false;
}
}
@@ -663,7 +678,7 @@ public final class ContentCaptureManager {
try {
mService.removeData(request);
} catch (RemoteException e) {
- e.rethrowFromSystemServer();
+ throw e.rethrowFromSystemServer();
}
}
@@ -691,7 +706,7 @@ public final class ContentCaptureManager {
new DataShareAdapterDelegate(executor, dataShareWriteAdapter,
mDataShareAdapterResourceManager));
} catch (RemoteException e) {
- e.rethrowFromSystemServer();
+ throw e.rethrowFromSystemServer();
}
}
@@ -709,10 +724,12 @@ public final class ContentCaptureManager {
if (resultCode == RESULT_CODE_SECURITY_EXCEPTION) {
throw new SecurityException(resultReceiver.getStringResult());
}
- return resultReceiver;
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
+ } catch (SyncResultReceiver.TimeoutException e) {
+ throw new RuntimeException("Fail to get syn run result from SyncResultReceiver.");
}
+ return resultReceiver;
}
/** @hide */
diff --git a/core/java/android/view/inputmethod/InlineSuggestion.java b/core/java/android/view/inputmethod/InlineSuggestion.java
index e4ac5889a3c0..b8893cee834d 100644
--- a/core/java/android/view/inputmethod/InlineSuggestion.java
+++ b/core/java/android/view/inputmethod/InlineSuggestion.java
@@ -317,8 +317,24 @@ public final class InlineSuggestion implements Parcelable {
*/
@MainThread
private void handleOnSurfacePackage(SurfaceControlViewHost.SurfacePackage surfacePackage) {
+ if (surfacePackage == null) {
+ return;
+ }
+ if (mSurfacePackage != null || mSurfacePackageConsumer == null) {
+ // The surface package is not consumed, release it immediately.
+ surfacePackage.release();
+ try {
+ mInlineContentProvider.onSurfacePackageReleased();
+ } catch (RemoteException e) {
+ Slog.w(TAG, "Error calling onSurfacePackageReleased(): " + e);
+ }
+ return;
+ }
mSurfacePackage = surfacePackage;
- if (mSurfacePackage != null && mSurfacePackageConsumer != null) {
+ if (mSurfacePackage == null) {
+ return;
+ }
+ if (mSurfacePackageConsumer != null) {
mSurfacePackageConsumer.accept(mSurfacePackage);
mSurfacePackageConsumer = null;
}
@@ -334,6 +350,10 @@ public final class InlineSuggestion implements Parcelable {
}
mSurfacePackage = null;
}
+ // Clear the pending surface package consumer, if any. This can happen if the IME
+ // attaches the view to window and then quickly detaches it from the window, before
+ // the surface package requested upon attaching to window was returned.
+ mSurfacePackageConsumer = null;
}
@MainThread
diff --git a/core/java/android/view/inputmethod/InputMethodManager.java b/core/java/android/view/inputmethod/InputMethodManager.java
index 71dd6653f6a6..477dd1d13295 100644
--- a/core/java/android/view/inputmethod/InputMethodManager.java
+++ b/core/java/android/view/inputmethod/InputMethodManager.java
@@ -616,12 +616,19 @@ public final class InputMethodManager {
// For some reason we didn't do a startInput + windowFocusGain, so
// we'll just do a window focus gain and call it a day.
try {
- if (DEBUG) Log.v(TAG, "Reporting focus gain, without startInput");
+ View servedView = controller.getServedView();
+ boolean nextFocusIsServedView = servedView != null && servedView == focusedView;
+ if (DEBUG) {
+ Log.v(TAG, "Reporting focus gain, without startInput"
+ + ", nextFocusIsServedView=" + nextFocusIsServedView);
+ }
mService.startInputOrWindowGainedFocus(
StartInputReason.WINDOW_FOCUS_GAIN_REPORT_ONLY, mClient,
focusedView.getWindowToken(), startInputFlags, softInputMode,
windowFlags,
- null, null, 0 /* missingMethodFlags */,
+ nextFocusIsServedView ? mCurrentTextBoxAttribute : null,
+ nextFocusIsServedView ? mServedInputConnectionWrapper : null,
+ 0 /* missingMethodFlags */,
mCurRootView.mContext.getApplicationInfo().targetSdkVersion);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
@@ -646,8 +653,7 @@ public final class InputMethodManager {
public void setCurrentRootView(ViewRootImpl rootView) {
synchronized (mH) {
if (mCurRootView != null) {
- // Reset the last served view and restart window focus state of the root view.
- mCurRootView.getImeFocusController().setServedView(null);
+ // Restart the input when the next window focus state of the root view changed.
mRestartOnNextWindowFocus = true;
}
mCurRootView = rootView;
@@ -677,6 +683,18 @@ public final class InputMethodManager {
}
return result;
}
+
+ /**
+ * For {@link ImeFocusController} to check if the currently served view is accepting full
+ * text edits.
+ */
+ @Override
+ public boolean isAcceptingText() {
+ synchronized (mH) {
+ return mServedInputConnectionWrapper != null
+ && mServedInputConnectionWrapper.getInputConnection() != null;
+ }
+ }
}
/** @hide */
diff --git a/core/java/android/view/textclassifier/TEST_MAPPING b/core/java/android/view/textclassifier/TEST_MAPPING
index 01a6edecf21e..2f9e737dc213 100644
--- a/core/java/android/view/textclassifier/TEST_MAPPING
+++ b/core/java/android/view/textclassifier/TEST_MAPPING
@@ -10,6 +10,22 @@
"exclude-annotation": "androidx.test.filters.FlakyTest"
}
]
+ },
+ {
+ "name": "CtsTextClassifierTestCases",
+ "options": [
+ {
+ "exclude-annotation": "androidx.test.filters.FlakyTest"
+ }
+ ]
+ },
+ {
+ "name": "TextClassifierServiceTest",
+ "options": [
+ {
+ "exclude-annotation": "androidx.test.filters.FlakyTest"
+ }
+ ]
}
]
}
diff --git a/core/java/android/webkit/WebChromeClient.java b/core/java/android/webkit/WebChromeClient.java
index 7042f29fc4e4..4a6551176198 100644
--- a/core/java/android/webkit/WebChromeClient.java
+++ b/core/java/android/webkit/WebChromeClient.java
@@ -205,6 +205,8 @@ public class WebChromeClient {
* <p>Note that if the {@link WebChromeClient} is set to be {@code null},
* or if {@link WebChromeClient} is not set at all, the default dialog will
* be suppressed and Javascript execution will continue immediately.
+ * <p>Note that the default dialog does not inherit the {@link
+ * android.view.Display#FLAG_SECURE} flag from the parent window.
*
* @param view The WebView that initiated the callback.
* @param url The url of the page requesting the dialog.
@@ -240,6 +242,8 @@ public class WebChromeClient {
* or if {@link WebChromeClient} is not set at all, the default dialog will
* be suppressed and the default value of {@code false} will be returned to
* the JavaScript code immediately.
+ * <p>Note that the default dialog does not inherit the {@link
+ * android.view.Display#FLAG_SECURE} flag from the parent window.
*
* @param view The WebView that initiated the callback.
* @param url The url of the page requesting the dialog.
@@ -274,6 +278,8 @@ public class WebChromeClient {
* or if {@link WebChromeClient} is not set at all, the default dialog will
* be suppressed and {@code null} will be returned to the JavaScript code
* immediately.
+ * <p>Note that the default dialog does not inherit the {@link
+ * android.view.Display#FLAG_SECURE} flag from the parent window.
*
* @param view The WebView that initiated the callback.
* @param url The url of the page requesting the dialog.
@@ -308,6 +314,8 @@ public class WebChromeClient {
* <p>Note that if the {@link WebChromeClient} is set to be {@code null},
* or if {@link WebChromeClient} is not set at all, the default dialog will
* be suppressed and the navigation will be resumed immediately.
+ * <p>Note that the default dialog does not inherit the {@link
+ * android.view.Display#FLAG_SECURE} flag from the parent window.
*
* @param view The WebView that initiated the callback.
* @param url The url of the page requesting the dialog.
diff --git a/core/java/android/widget/inline/InlineContentView.java b/core/java/android/widget/inline/InlineContentView.java
index 8657e828a3f6..6a85de5ca757 100644
--- a/core/java/android/widget/inline/InlineContentView.java
+++ b/core/java/android/widget/inline/InlineContentView.java
@@ -197,7 +197,9 @@ public class InlineContentView extends ViewGroup {
mSurfacePackageUpdater.getSurfacePackage(
sp -> {
if (DEBUG) Log.v(TAG, "Received new SurfacePackage");
- mSurfaceView.setChildSurfacePackage(sp);
+ if (getViewRootImpl() != null) {
+ mSurfaceView.setChildSurfacePackage(sp);
+ }
});
}
}
diff --git a/core/java/android/window/VirtualDisplayTaskEmbedder.java b/core/java/android/window/VirtualDisplayTaskEmbedder.java
index d2614da31ff9..9ccb4c172158 100644
--- a/core/java/android/window/VirtualDisplayTaskEmbedder.java
+++ b/core/java/android/window/VirtualDisplayTaskEmbedder.java
@@ -365,8 +365,8 @@ public class VirtualDisplayTaskEmbedder extends TaskEmbedder {
// Found the topmost stack on target display. Now check if the topmost task's
// description changed.
if (taskInfo.taskId == stackInfo.taskIds[stackInfo.taskIds.length - 1]) {
- mHost.onTaskBackgroundColorChanged(VirtualDisplayTaskEmbedder.this,
- taskInfo.taskDescription.getBackgroundColor());
+ mHost.post(()-> mHost.onTaskBackgroundColorChanged(VirtualDisplayTaskEmbedder.this,
+ taskInfo.taskDescription.getBackgroundColor()));
}
}
diff --git a/core/java/android/window/WindowContainerTransaction.java b/core/java/android/window/WindowContainerTransaction.java
index 9a732455113c..8be37e9e492d 100644
--- a/core/java/android/window/WindowContainerTransaction.java
+++ b/core/java/android/window/WindowContainerTransaction.java
@@ -264,6 +264,29 @@ public final class WindowContainerTransaction implements Parcelable {
return this;
}
+ /**
+ * Merges another WCT into this one.
+ * @param transfer When true, this will transfer everything from other potentially leaving
+ * other in an unusable state. When false, other is left alone, but
+ * SurfaceFlinger Transactions will not be merged.
+ * @hide
+ */
+ public void merge(WindowContainerTransaction other, boolean transfer) {
+ for (int i = 0, n = other.mChanges.size(); i < n; ++i) {
+ final IBinder key = other.mChanges.keyAt(i);
+ Change existing = mChanges.get(key);
+ if (existing == null) {
+ existing = new Change();
+ mChanges.put(key, existing);
+ }
+ existing.merge(other.mChanges.valueAt(i), transfer);
+ }
+ for (int i = 0, n = other.mHierarchyOps.size(); i < n; ++i) {
+ mHierarchyOps.add(transfer ? other.mHierarchyOps.get(i)
+ : new HierarchyOp(other.mHierarchyOps.get(i)));
+ }
+ }
+
/** @hide */
public Map<IBinder, Change> getChanges() {
return mChanges;
@@ -359,6 +382,41 @@ public final class WindowContainerTransaction implements Parcelable {
mActivityWindowingMode = in.readInt();
}
+ /**
+ * @param transfer When true, this will transfer other into this leaving other in an
+ * undefined state. Use this if you don't intend to use other. When false,
+ * SurfaceFlinger Transactions will not merge.
+ */
+ public void merge(Change other, boolean transfer) {
+ mConfiguration.setTo(other.mConfiguration, other.mConfigSetMask, other.mWindowSetMask);
+ mConfigSetMask |= other.mConfigSetMask;
+ mWindowSetMask |= other.mWindowSetMask;
+ if ((other.mChangeMask & CHANGE_FOCUSABLE) != 0) {
+ mFocusable = other.mFocusable;
+ }
+ if (transfer && (other.mChangeMask & CHANGE_BOUNDS_TRANSACTION) != 0) {
+ mBoundsChangeTransaction = other.mBoundsChangeTransaction;
+ other.mBoundsChangeTransaction = null;
+ }
+ if ((other.mChangeMask & CHANGE_PIP_CALLBACK) != 0) {
+ mPinnedBounds = transfer ? other.mPinnedBounds : new Rect(other.mPinnedBounds);
+ }
+ if ((other.mChangeMask & CHANGE_HIDDEN) != 0) {
+ mHidden = other.mHidden;
+ }
+ mChangeMask |= other.mChangeMask;
+ if (other.mActivityWindowingMode >= 0) {
+ mActivityWindowingMode = other.mActivityWindowingMode;
+ }
+ if (other.mWindowingMode >= 0) {
+ mWindowingMode = other.mWindowingMode;
+ }
+ if (other.mBoundsChangeSurfaceBounds != null) {
+ mBoundsChangeSurfaceBounds = transfer ? other.mBoundsChangeSurfaceBounds
+ : new Rect(other.mBoundsChangeSurfaceBounds);
+ }
+ }
+
public int getWindowingMode() {
return mWindowingMode;
}
@@ -522,6 +580,12 @@ public final class WindowContainerTransaction implements Parcelable {
mToTop = toTop;
}
+ public HierarchyOp(@NonNull HierarchyOp copy) {
+ mContainer = copy.mContainer;
+ mReparent = copy.mReparent;
+ mToTop = copy.mToTop;
+ }
+
protected HierarchyOp(Parcel in) {
mContainer = in.readStrongBinder();
mReparent = in.readStrongBinder();
diff --git a/core/java/com/android/internal/accessibility/dialog/AccessibilityShortcutChooserActivity.java b/core/java/com/android/internal/accessibility/dialog/AccessibilityShortcutChooserActivity.java
index 1b7517840650..508deacb49d7 100644
--- a/core/java/com/android/internal/accessibility/dialog/AccessibilityShortcutChooserActivity.java
+++ b/core/java/com/android/internal/accessibility/dialog/AccessibilityShortcutChooserActivity.java
@@ -23,6 +23,7 @@ import static com.android.internal.accessibility.common.ShortcutConstants.Shortc
import static com.android.internal.accessibility.dialog.AccessibilityTargetHelper.createEnableDialogContentView;
import static com.android.internal.accessibility.dialog.AccessibilityTargetHelper.getInstalledTargets;
import static com.android.internal.accessibility.dialog.AccessibilityTargetHelper.getTargets;
+import static com.android.internal.accessibility.util.AccessibilityUtils.isUserSetupCompleted;
import android.annotation.Nullable;
import android.app.Activity;
@@ -61,18 +62,8 @@ public class AccessibilityShortcutChooserActivity extends Activity {
}
mTargets.addAll(getTargets(this, mShortcutType));
-
- final String selectDialogTitle =
- getString(R.string.accessibility_select_shortcut_menu_title);
mTargetAdapter = new ShortcutTargetAdapter(mTargets);
- mMenuDialog = new AlertDialog.Builder(this)
- .setTitle(selectDialogTitle)
- .setAdapter(mTargetAdapter, /* listener= */ null)
- .setPositiveButton(
- getString(R.string.edit_accessibility_shortcut_menu_button),
- /* listener= */ null)
- .setOnDismissListener(dialog -> finish())
- .create();
+ mMenuDialog = createMenuDialog();
mMenuDialog.setOnShowListener(dialog -> updateDialogListeners());
mMenuDialog.show();
}
@@ -154,4 +145,22 @@ public class AccessibilityShortcutChooserActivity extends Activity {
mMenuDialog.getListView().setOnItemClickListener(
isEditMenuMode ? this::onTargetChecked : this::onTargetSelected);
}
+
+ private AlertDialog createMenuDialog() {
+ final String dialogTitle =
+ getString(R.string.accessibility_select_shortcut_menu_title);
+
+ final AlertDialog.Builder builder = new AlertDialog.Builder(this)
+ .setTitle(dialogTitle)
+ .setAdapter(mTargetAdapter, /* listener= */ null)
+ .setOnDismissListener(dialog -> finish());
+
+ if (isUserSetupCompleted(this)) {
+ final String positiveButtonText =
+ getString(R.string.edit_accessibility_shortcut_menu_button);
+ builder.setPositiveButton(positiveButtonText, /* listener= */ null);
+ }
+
+ return builder.create();
+ }
}
diff --git a/core/java/com/android/internal/accessibility/util/AccessibilityUtils.java b/core/java/com/android/internal/accessibility/util/AccessibilityUtils.java
index 9ee0b0ea1891..4b4e20f9181b 100644
--- a/core/java/com/android/internal/accessibility/util/AccessibilityUtils.java
+++ b/core/java/com/android/internal/accessibility/util/AccessibilityUtils.java
@@ -156,4 +156,16 @@ public final class AccessibilityUtils {
return false;
}
+
+ /**
+ * Indicates whether the current user has completed setup via the setup wizard.
+ * {@link android.provider.Settings.Secure#USER_SETUP_COMPLETE}
+ *
+ * @return {@code true} if the setup is completed.
+ */
+ public static boolean isUserSetupCompleted(Context context) {
+ return Settings.Secure.getIntForUser(context.getContentResolver(),
+ Settings.Secure.USER_SETUP_COMPLETE, /* def= */ 0, UserHandle.USER_CURRENT)
+ != /* false */ 0;
+ }
}
diff --git a/core/java/com/android/internal/app/AbstractMultiProfilePagerAdapter.java b/core/java/com/android/internal/app/AbstractMultiProfilePagerAdapter.java
index 493865ac563f..b723db287823 100644
--- a/core/java/com/android/internal/app/AbstractMultiProfilePagerAdapter.java
+++ b/core/java/com/android/internal/app/AbstractMultiProfilePagerAdapter.java
@@ -151,6 +151,13 @@ public abstract class AbstractMultiProfilePagerAdapter extends PagerAdapter {
mOnProfileSelectedListener.onProfileSelected(position);
}
}
+
+ @Override
+ public void onPageScrollStateChanged(int state) {
+ if (mOnProfileSelectedListener != null) {
+ mOnProfileSelectedListener.onProfilePageStateChanged(state);
+ }
+ }
});
viewPager.setAdapter(this);
viewPager.setCurrentItem(mCurrentPage);
@@ -606,6 +613,17 @@ public abstract class AbstractMultiProfilePagerAdapter extends PagerAdapter {
* {@link #PROFILE_WORK} if the work profile was selected.
*/
void onProfileSelected(int profileIndex);
+
+
+ /**
+ * Callback for when the scroll state changes. Useful for discovering when the user begins
+ * dragging, when the pager is automatically settling to the current page, or when it is
+ * fully stopped/idle.
+ * @param state {@link ViewPager#SCROLL_STATE_IDLE}, {@link ViewPager#SCROLL_STATE_DRAGGING}
+ * or {@link ViewPager#SCROLL_STATE_SETTLING}
+ * @see ViewPager.OnPageChangeListener#onPageScrollStateChanged
+ */
+ void onProfilePageStateChanged(int state);
}
/**
diff --git a/core/java/com/android/internal/app/ChooserActivity.java b/core/java/com/android/internal/app/ChooserActivity.java
index 5533e1eda52d..67c97ae29186 100644
--- a/core/java/com/android/internal/app/ChooserActivity.java
+++ b/core/java/com/android/internal/app/ChooserActivity.java
@@ -102,6 +102,7 @@ import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.view.ViewGroup.LayoutParams;
import android.view.ViewTreeObserver;
+import android.view.WindowInsets;
import android.view.animation.AccelerateInterpolator;
import android.view.animation.DecelerateInterpolator;
import android.widget.Button;
@@ -129,6 +130,7 @@ import com.android.internal.util.FrameworkStatsLog;
import com.android.internal.widget.GridLayoutManager;
import com.android.internal.widget.RecyclerView;
import com.android.internal.widget.ResolverDrawerLayout;
+import com.android.internal.widget.ViewPager;
import com.google.android.collect.Lists;
@@ -204,6 +206,10 @@ public class ChooserActivity extends ResolverActivity implements
public static final int SELECTION_TYPE_STANDARD = 3;
public static final int SELECTION_TYPE_COPY = 4;
+ private static final int SCROLL_STATUS_IDLE = 0;
+ private static final int SCROLL_STATUS_SCROLLING_VERTICAL = 1;
+ private static final int SCROLL_STATUS_SCROLLING_HORIZONTAL = 2;
+
// statsd logger wrapper
protected ChooserActivityLogger mChooserActivityLogger;
@@ -293,6 +299,7 @@ public class ChooserActivity extends ResolverActivity implements
protected MetricsLogger mMetricsLogger;
private ContentPreviewCoordinator mPreviewCoord;
+ private int mScrollStatus = SCROLL_STATUS_IDLE;
@VisibleForTesting
protected ChooserMultiProfilePagerAdapter mChooserMultiProfilePagerAdapter;
@@ -786,7 +793,6 @@ public class ChooserActivity extends ResolverActivity implements
private AppPredictor.Callback createAppPredictorCallback(
ChooserListAdapter chooserListAdapter) {
return resultList -> {
- //TODO(arangelov) Take care of edge case when callback called after swiping tabs
if (isFinishing() || isDestroyed()) {
return;
}
@@ -795,8 +801,6 @@ public class ChooserActivity extends ResolverActivity implements
}
if (resultList.isEmpty()) {
// APS may be disabled, so try querying targets ourselves.
- //TODO(arangelov) queryDirectShareTargets indirectly uses mIntents.
- // Investigate implications for work tab.
queryDirectShareTargets(chooserListAdapter, true);
return;
}
@@ -1117,7 +1121,7 @@ public class ChooserActivity extends ResolverActivity implements
final ComponentName cn = getNearbySharingComponent();
if (cn == null) return null;
- final Intent resolveIntent = new Intent();
+ final Intent resolveIntent = new Intent(originalIntent);
resolveIntent.setComponent(cn);
final ResolveInfo ri = getPackageManager().resolveActivity(
resolveIntent, PackageManager.GET_META_DATA);
@@ -1281,6 +1285,12 @@ public class ChooserActivity extends ResolverActivity implements
ViewGroup parent) {
ViewGroup contentPreviewLayout = (ViewGroup) layoutInflater.inflate(
R.layout.chooser_grid_preview_image, parent, false);
+
+ final ViewGroup actionRow =
+ (ViewGroup) contentPreviewLayout.findViewById(R.id.chooser_action_row);
+ //TODO: addActionButton(actionRow, createCopyButton());
+ addActionButton(actionRow, createNearbyButton(targetIntent));
+
mPreviewCoord = new ContentPreviewCoordinator(contentPreviewLayout, true);
String action = targetIntent.getAction();
@@ -1391,10 +1401,11 @@ public class ChooserActivity extends ResolverActivity implements
ViewGroup contentPreviewLayout = (ViewGroup) layoutInflater.inflate(
R.layout.chooser_grid_preview_file, parent, false);
- // TODO(b/120417119): Disable file copy until after moving to sysui,
- // due to permissions issues
- //((ViewGroup) contentPreviewLayout.findViewById(R.id.chooser_action_row))
- // .addView(createCopyButton());
+ final ViewGroup actionRow =
+ (ViewGroup) contentPreviewLayout.findViewById(R.id.chooser_action_row);
+ //TODO(b/120417119): addActionButton(actionRow, createCopyButton());
+ addActionButton(actionRow, createNearbyButton(targetIntent));
+
String action = targetIntent.getAction();
if (Intent.ACTION_SEND.equals(action)) {
@@ -1802,7 +1813,8 @@ public class ChooserActivity extends ResolverActivity implements
}
}
- void queryTargetServices(ChooserListAdapter adapter) {
+ @VisibleForTesting
+ protected void queryTargetServices(ChooserListAdapter adapter) {
mQueriedTargetServicesTimeMs = System.currentTimeMillis();
Context selectedProfileContext = createContextAsUser(
@@ -1955,7 +1967,8 @@ public class ChooserActivity extends ResolverActivity implements
return driList;
}
- private void queryDirectShareTargets(
+ @VisibleForTesting
+ protected void queryDirectShareTargets(
ChooserListAdapter adapter, boolean skipAppPredictionService) {
mQueriedSharingShortcutsTimeMs = System.currentTimeMillis();
UserHandle userHandle = adapter.getUserHandle();
@@ -1967,7 +1980,6 @@ public class ChooserActivity extends ResolverActivity implements
}
}
// Default to just querying ShortcutManager if AppPredictor not present.
- //TODO(arangelov) we're using mIntents here, investicate possible implications on work tab
final IntentFilter filter = getTargetIntentFilter();
if (filter == null) {
return;
@@ -2182,6 +2194,9 @@ public class ChooserActivity extends ResolverActivity implements
}
void updateModelAndChooserCounts(TargetInfo info) {
+ if (info != null && info instanceof MultiDisplayResolveInfo) {
+ info = ((MultiDisplayResolveInfo) info).getSelectedTarget();
+ }
if (info != null) {
sendClickToAppPredictor(info);
final ResolveInfo ri = info.getResolveInfo();
@@ -2644,6 +2659,7 @@ public class ChooserActivity extends ResolverActivity implements
if (recyclerView.getVisibility() == View.VISIBLE) {
int directShareHeight = 0;
rowsToShow = Math.min(4, rowsToShow);
+ boolean shouldShowExtraRow = shouldShowExtraRow(rowsToShow);
mLastNumberOfChildren = recyclerView.getChildCount();
for (int i = 0, childCount = recyclerView.getChildCount();
i < childCount && rowsToShow > 0; i++) {
@@ -2654,6 +2670,9 @@ public class ChooserActivity extends ResolverActivity implements
}
int height = child.getHeight();
offset += height;
+ if (shouldShowExtraRow) {
+ offset += height;
+ }
if (gridAdapter.getTargetType(
recyclerView.getChildAdapterPosition(child))
@@ -2677,7 +2696,7 @@ public class ChooserActivity extends ResolverActivity implements
offset = Math.min(offset, minHeight);
}
} else {
- ViewGroup currentEmptyStateView = getCurrentEmptyStateView();
+ ViewGroup currentEmptyStateView = getActiveEmptyStateView();
if (currentEmptyStateView.getVisibility() == View.VISIBLE) {
offset += currentEmptyStateView.getHeight();
}
@@ -2689,6 +2708,18 @@ public class ChooserActivity extends ResolverActivity implements
}
/**
+ * If we have a tabbed view and are showing 1 row in the current profile and an empty
+ * state screen in the other profile, to prevent cropping of the empty state screen we show
+ * a second row in the current profile.
+ */
+ private boolean shouldShowExtraRow(int rowsToShow) {
+ return shouldShowTabs()
+ && rowsToShow == 1
+ && mChooserMultiProfilePagerAdapter.shouldShowEmptyStateScreen(
+ mChooserMultiProfilePagerAdapter.getInactiveListAdapter());
+ }
+
+ /**
* Returns {@link #PROFILE_PERSONAL}, {@link #PROFILE_WORK}, or -1 if the given user handle
* does not match either the personal or work user handle.
**/
@@ -2702,7 +2733,7 @@ public class ChooserActivity extends ResolverActivity implements
return -1;
}
- private ViewGroup getCurrentEmptyStateView() {
+ private ViewGroup getActiveEmptyStateView() {
int currentPage = mChooserMultiProfilePagerAdapter.getCurrentPage();
return mChooserMultiProfilePagerAdapter.getItem(currentPage).getEmptyStateView();
}
@@ -2784,6 +2815,13 @@ public class ChooserActivity extends ResolverActivity implements
return;
}
+ // no need to query direct share for work profile when its turned off
+ UserManager userManager = getSystemService(UserManager.class);
+ if (userManager.isQuietModeEnabled(chooserListAdapter.getUserHandle())) {
+ getChooserActivityLogger().logSharesheetAppLoadComplete();
+ return;
+ }
+
if (ChooserFlags.USE_SHORTCUT_MANAGER_FOR_DIRECT_TARGETS
|| ChooserFlags.USE_PREDICTION_MANAGER_FOR_DIRECT_TARGETS) {
if (DEBUG) {
@@ -2812,10 +2850,20 @@ public class ChooserActivity extends ResolverActivity implements
final float defaultElevation = elevatedView.getElevation();
final float chooserHeaderScrollElevation =
getResources().getDimensionPixelSize(R.dimen.chooser_header_scroll_elevation);
-
mChooserMultiProfilePagerAdapter.getActiveAdapterView().addOnScrollListener(
new RecyclerView.OnScrollListener() {
public void onScrollStateChanged(RecyclerView view, int scrollState) {
+ if (scrollState == RecyclerView.SCROLL_STATE_IDLE) {
+ if (mScrollStatus == SCROLL_STATUS_SCROLLING_VERTICAL) {
+ mScrollStatus = SCROLL_STATUS_IDLE;
+ setHorizontalScrollingEnabled(true);
+ }
+ } else if (scrollState == RecyclerView.SCROLL_STATE_DRAGGING) {
+ if (mScrollStatus == SCROLL_STATUS_IDLE) {
+ mScrollStatus = SCROLL_STATUS_SCROLLING_VERTICAL;
+ setHorizontalScrollingEnabled(false);
+ }
+ }
}
public void onScrolled(RecyclerView view, int dx, int dy) {
@@ -3016,6 +3064,44 @@ public class ChooserActivity extends ResolverActivity implements
currentRootAdapter.updateDirectShareExpansion();
}
+ @Override
+ protected WindowInsets onApplyWindowInsets(View v, WindowInsets insets) {
+ if (shouldShowTabs()) {
+ mChooserMultiProfilePagerAdapter
+ .setEmptyStateBottomOffset(insets.getSystemWindowInsetBottom());
+ mChooserMultiProfilePagerAdapter.setupContainerPadding(
+ getActiveEmptyStateView().findViewById(R.id.resolver_empty_state_container));
+ }
+ return super.onApplyWindowInsets(v, insets);
+ }
+
+ private void setHorizontalScrollingEnabled(boolean enabled) {
+ ResolverViewPager viewPager = findViewById(R.id.profile_pager);
+ viewPager.setSwipingEnabled(enabled);
+ }
+
+ private void setVerticalScrollEnabled(boolean enabled) {
+ ChooserGridLayoutManager layoutManager =
+ (ChooserGridLayoutManager) mChooserMultiProfilePagerAdapter.getActiveAdapterView()
+ .getLayoutManager();
+ layoutManager.setVerticalScrollEnabled(enabled);
+ }
+
+ @Override
+ void onHorizontalSwipeStateChanged(int state) {
+ if (state == ViewPager.SCROLL_STATE_DRAGGING) {
+ if (mScrollStatus == SCROLL_STATUS_IDLE) {
+ mScrollStatus = SCROLL_STATUS_SCROLLING_HORIZONTAL;
+ setVerticalScrollEnabled(false);
+ }
+ } else if (state == ViewPager.SCROLL_STATE_IDLE) {
+ if (mScrollStatus == SCROLL_STATUS_SCROLLING_VERTICAL) {
+ mScrollStatus = SCROLL_STATUS_IDLE;
+ setVerticalScrollEnabled(true);
+ }
+ }
+ }
+
/**
* Adapter for all types of items and targets in ShareSheet.
* Note that ranked sections like Direct Share - while appearing grid-like - are handled on the
@@ -3506,10 +3592,9 @@ public class ChooserActivity extends ResolverActivity implements
* Only expand direct share area if there is a minimum number of targets.
*/
private boolean canExpandDirectShare() {
- int orientation = getResources().getConfiguration().orientation;
- return mChooserListAdapter.getNumServiceTargetsForExpand() > getMaxTargetsPerRow()
- && orientation == Configuration.ORIENTATION_PORTRAIT
- && !isInMultiWindowMode();
+ // Do not enable until we have confirmed more apps are using sharing shortcuts
+ // Check git history for enablement logic
+ return false;
}
public ChooserListAdapter getListAdapter() {
diff --git a/core/java/com/android/internal/app/ChooserGridLayoutManager.java b/core/java/com/android/internal/app/ChooserGridLayoutManager.java
index 317a987cf359..c50ebd9562c9 100644
--- a/core/java/com/android/internal/app/ChooserGridLayoutManager.java
+++ b/core/java/com/android/internal/app/ChooserGridLayoutManager.java
@@ -28,6 +28,8 @@ import com.android.internal.widget.RecyclerView;
*/
public class ChooserGridLayoutManager extends GridLayoutManager {
+ private boolean mVerticalScrollEnabled = true;
+
/**
* Constructor used when layout manager is set in XML by RecyclerView attribute
* "layoutManager". If spanCount is not specified in the XML, it defaults to a
@@ -67,4 +69,13 @@ public class ChooserGridLayoutManager extends GridLayoutManager {
// Do not count the footer view in the official count
return super.getRowCountForAccessibility(recycler, state) - 1;
}
+
+ void setVerticalScrollEnabled(boolean verticalScrollEnabled) {
+ mVerticalScrollEnabled = verticalScrollEnabled;
+ }
+
+ @Override
+ public boolean canScrollVertically() {
+ return mVerticalScrollEnabled && super.canScrollVertically();
+ }
}
diff --git a/core/java/com/android/internal/app/ChooserListAdapter.java b/core/java/com/android/internal/app/ChooserListAdapter.java
index f4fb993fbb93..d6ff7b13c934 100644
--- a/core/java/com/android/internal/app/ChooserListAdapter.java
+++ b/core/java/com/android/internal/app/ChooserListAdapter.java
@@ -181,6 +181,7 @@ public class ChooserListAdapter extends ResolverListAdapter {
ri.icon = 0;
}
mCallerTargets.add(new DisplayResolveInfo(ii, ri, ii, makePresentationGetter(ri)));
+ if (mCallerTargets.size() == MAX_SUGGESTED_APP_TARGETS) break;
}
}
}
@@ -320,7 +321,7 @@ public class ChooserListAdapter extends ResolverListAdapter {
public int getCallerTargetCount() {
- return Math.min(mCallerTargets.size(), MAX_SUGGESTED_APP_TARGETS);
+ return mCallerTargets.size();
}
/**
@@ -346,8 +347,9 @@ public class ChooserListAdapter extends ResolverListAdapter {
}
int getAlphaTargetCount() {
- int standardCount = mSortedList.size();
- return standardCount > mChooserListCommunicator.getMaxRankedTargets() ? standardCount : 0;
+ int groupedCount = mSortedList.size();
+ int ungroupedCount = mCallerTargets.size() + mDisplayList.size();
+ return ungroupedCount > mChooserListCommunicator.getMaxRankedTargets() ? groupedCount : 0;
}
/**
diff --git a/core/java/com/android/internal/app/ChooserMultiProfilePagerAdapter.java b/core/java/com/android/internal/app/ChooserMultiProfilePagerAdapter.java
index 774be3c9c4b8..ffa6041721c6 100644
--- a/core/java/com/android/internal/app/ChooserMultiProfilePagerAdapter.java
+++ b/core/java/com/android/internal/app/ChooserMultiProfilePagerAdapter.java
@@ -38,6 +38,7 @@ public class ChooserMultiProfilePagerAdapter extends AbstractMultiProfilePagerAd
private final ChooserProfileDescriptor[] mItems;
private final boolean mIsSendAction;
+ private int mBottomOffset;
ChooserMultiProfilePagerAdapter(Context context,
ChooserActivity.ChooserGridAdapter adapter,
@@ -245,6 +246,16 @@ public class ChooserMultiProfilePagerAdapter extends AbstractMultiProfilePagerAd
}
}
+ void setEmptyStateBottomOffset(int bottomOffset) {
+ mBottomOffset = bottomOffset;
+ }
+
+ @Override
+ protected void setupContainerPadding(View container) {
+ container.setPadding(container.getPaddingLeft(), container.getPaddingTop(),
+ container.getPaddingRight(), container.getPaddingBottom() + mBottomOffset);
+ }
+
class ChooserProfileDescriptor extends ProfileDescriptor {
private ChooserActivity.ChooserGridAdapter chooserGridAdapter;
private RecyclerView recyclerView;
diff --git a/core/java/com/android/internal/app/ChooserTargetActionsDialogFragment.java b/core/java/com/android/internal/app/ChooserTargetActionsDialogFragment.java
index 3991a7674f38..21063d5d5857 100644
--- a/core/java/com/android/internal/app/ChooserTargetActionsDialogFragment.java
+++ b/core/java/com/android/internal/app/ChooserTargetActionsDialogFragment.java
@@ -26,7 +26,6 @@ import static java.util.stream.Collectors.toList;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.ActivityManager;
-import android.app.AlertDialog.Builder;
import android.app.Dialog;
import android.app.DialogFragment;
import android.content.ComponentName;
@@ -34,21 +33,25 @@ import android.content.DialogInterface;
import android.content.SharedPreferences;
import android.content.pm.PackageManager;
import android.content.res.Configuration;
+import android.graphics.Color;
+import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.os.UserHandle;
import android.util.Pair;
+import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
-import android.widget.ArrayAdapter;
import android.widget.ImageView;
import android.widget.TextView;
import com.android.internal.R;
import com.android.internal.app.chooser.DisplayResolveInfo;
+import com.android.internal.widget.RecyclerView;
import java.util.ArrayList;
import java.util.List;
+import java.util.Optional;
/**
* Shows a dialog with actions to take on a chooser target.
@@ -68,47 +71,86 @@ public class ChooserTargetActionsDialogFragment extends DialogFragment
mTargetInfos = targets;
}
- @Override
- public Dialog onCreateDialog(Bundle savedInstanceState) {
+ /**
+ * Recreate the layout from scratch to match new Sharesheet redlines
+ */
+ public View onCreateView(LayoutInflater inflater,
+ @Nullable ViewGroup container,
+ Bundle savedInstanceState) {
+
+ // Make the background transparent to show dialog rounding
+ Optional.of(getDialog()).map(Dialog::getWindow)
+ .ifPresent(window -> {
+ window.setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));
+ });
// Fetch UI details from target info
- List<Pair<CharSequence, Drawable>> items = mTargetInfos.stream().map(dri -> {
- return new Pair<>(getItemLabel(dri), getItemIcon(dri));
+ List<Pair<Drawable, CharSequence>> items = mTargetInfos.stream().map(dri -> {
+ return new Pair<>(getItemIcon(dri), getItemLabel(dri));
}).collect(toList());
+ View v = inflater.inflate(R.layout.chooser_dialog, container, false);
+
+ TextView title = v.findViewById(R.id.title);
+ ImageView icon = v.findViewById(R.id.icon);
+ RecyclerView rv = v.findViewById(R.id.listContainer);
+
final ResolveInfoPresentationGetter pg = getProvidingAppPresentationGetter();
- return new Builder(getContext())
- .setTitle(pg.getLabel())
- .setIcon(pg.getIcon(mUserHandle))
- .setCancelable(true)
- .setAdapter(getAdapterForContent(items), this)
- .create();
+ title.setText(pg.getLabel());
+ icon.setImageDrawable(pg.getIcon(mUserHandle));
+ rv.setAdapter(new VHAdapter(items));
+
+ return v;
+ }
+
+ class VHAdapter extends RecyclerView.Adapter<VH> {
+
+ List<Pair<Drawable, CharSequence>> mItems;
+
+ VHAdapter(List<Pair<Drawable, CharSequence>> items) {
+ mItems = items;
+ }
+
+ @NonNull
+ @Override
+ public VH onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
+ return new VH(LayoutInflater.from(parent.getContext()).inflate(
+ R.layout.chooser_dialog_item, parent, false));
+ }
+
+ @Override
+ public void onBindViewHolder(@NonNull VH holder, int position) {
+ holder.bind(mItems.get(position), position);
+ }
+
+ @Override
+ public int getItemCount() {
+ return mItems.size();
+ }
}
- protected ArrayAdapter<Pair<CharSequence, Drawable>> getAdapterForContent(
- List<Pair<CharSequence, Drawable>> items) {
- return new ArrayAdapter<Pair<CharSequence, Drawable>>(getContext(),
- R.layout.chooser_dialog_item, R.id.text, items) {
- @Override
- public View getView(int position, View convertView, ViewGroup parent) {
- View v = super.getView(position, convertView, parent); // super recycles views
- TextView label = v.findViewById(R.id.text);
- ImageView icon = v.findViewById(R.id.icon);
-
- Pair<CharSequence, Drawable> pair = getItem(position);
- label.setText(pair.first);
-
- // Hide icon view if one isn't available
- if (pair.second == null) {
- icon.setVisibility(View.GONE);
- } else {
- icon.setImageDrawable(pair.second);
- icon.setVisibility(View.VISIBLE);
- }
-
- return v;
+ class VH extends RecyclerView.ViewHolder {
+ TextView mLabel;
+ ImageView mIcon;
+
+ VH(@NonNull View itemView) {
+ super(itemView);
+ mLabel = itemView.findViewById(R.id.text);
+ mIcon = itemView.findViewById(R.id.icon);
+ }
+
+ public void bind(Pair<Drawable, CharSequence> item, int position) {
+ mLabel.setText(item.second);
+
+ if (item.first == null) {
+ mIcon.setVisibility(View.GONE);
+ } else {
+ mIcon.setVisibility(View.VISIBLE);
+ mIcon.setImageDrawable(item.first);
}
- };
+
+ itemView.setOnClickListener(v -> onClick(getDialog(), position));
+ }
}
@Override
diff --git a/core/java/com/android/internal/app/IAppOpsService.aidl b/core/java/com/android/internal/app/IAppOpsService.aidl
index 06c21ab8832d..e614a0eb996b 100644
--- a/core/java/com/android/internal/app/IAppOpsService.aidl
+++ b/core/java/com/android/internal/app/IAppOpsService.aidl
@@ -76,6 +76,7 @@ interface IAppOpsService {
void addHistoricalOps(in AppOpsManager.HistoricalOps ops);
void resetHistoryParameters();
void clearHistory();
+ void rebootHistory(long offlineDurationMillis);
List<AppOpsManager.PackageOps> getUidOps(int uid, in int[] ops);
void setUidMode(int code, int uid, int mode);
@UnsupportedAppUsage
diff --git a/core/java/com/android/internal/app/IVoiceInteractionManagerService.aidl b/core/java/com/android/internal/app/IVoiceInteractionManagerService.aidl
index 71ee8af8b11a..15ba8e8c11f7 100644
--- a/core/java/com/android/internal/app/IVoiceInteractionManagerService.aidl
+++ b/core/java/com/android/internal/app/IVoiceInteractionManagerService.aidl
@@ -265,4 +265,16 @@ interface IVoiceInteractionManagerService {
void performDirectAction(in IBinder token, String actionId, in Bundle arguments, int taskId,
IBinder assistToken, in RemoteCallback cancellationCallback,
in RemoteCallback resultCallback);
+
+ /**
+ * Temporarily disables voice interaction (for example, on Automotive when the display is off).
+ *
+ * It will shutdown the service, and only re-enable it after it's called again (or after a
+ * system restart).
+ *
+ * NOTE: it's only effective when the service itself is available / enabled in the device, so
+ * calling setDisable(false) would be a no-op when it isn't.
+ */
+ void setDisabled(boolean disabled);
+
}
diff --git a/core/java/com/android/internal/app/IntentForwarderActivity.java b/core/java/com/android/internal/app/IntentForwarderActivity.java
index e65d1fe9ce53..61a52bcc03f9 100644
--- a/core/java/com/android/internal/app/IntentForwarderActivity.java
+++ b/core/java/com/android/internal/app/IntentForwarderActivity.java
@@ -18,6 +18,7 @@ package com.android.internal.app;
import static android.content.pm.PackageManager.MATCH_DEFAULT_ONLY;
+import static com.android.internal.app.ResolverActivity.EXTRA_CALLING_USER;
import static com.android.internal.app.ResolverActivity.EXTRA_SELECTED_PROFILE;
import android.annotation.Nullable;
@@ -246,6 +247,7 @@ public class IntentForwarderActivity extends Activity {
int selectedProfile = findSelectedProfile(className);
sanitizeIntent(intentReceived);
intentReceived.putExtra(EXTRA_SELECTED_PROFILE, selectedProfile);
+ intentReceived.putExtra(EXTRA_CALLING_USER, UserHandle.of(callingUserId));
startActivityAsCaller(intentReceived, null, null, false, userId);
finish();
}
diff --git a/core/java/com/android/internal/app/ResolverActivity.java b/core/java/com/android/internal/app/ResolverActivity.java
index b82f0dfcbe12..daacd459a1a7 100644
--- a/core/java/com/android/internal/app/ResolverActivity.java
+++ b/core/java/com/android/internal/app/ResolverActivity.java
@@ -159,9 +159,6 @@ public class ResolverActivity extends Activity implements
protected static final String METRICS_CATEGORY_RESOLVER = "intent_resolver";
protected static final String METRICS_CATEGORY_CHOOSER = "intent_chooser";
- /**
- * TODO(arangelov): Remove a couple of weeks after work/personal tabs are finalized.
- */
@VisibleForTesting
public static boolean ENABLE_TABBED_VIEW = true;
private static final String TAB_TAG_PERSONAL = "personal";
@@ -184,6 +181,18 @@ public class ResolverActivity extends Activity implements
static final String EXTRA_SELECTED_PROFILE =
"com.android.internal.app.ResolverActivity.EXTRA_SELECTED_PROFILE";
+ /**
+ * {@link UserHandle} extra to indicate the user of the user that the starting intent
+ * originated from.
+ * <p>This is not necessarily the same as {@link #getUserId()} or {@link UserHandle#myUserId()},
+ * as there are edge cases when the intent resolver is launched in the other profile.
+ * For example, when we have 0 resolved apps in current profile and multiple resolved
+ * apps in the other profile, opening a link from the current profile launches the intent
+ * resolver in the other one. b/148536209 for more info.
+ */
+ static final String EXTRA_CALLING_USER =
+ "com.android.internal.app.ResolverActivity.EXTRA_CALLING_USER";
+
static final int PROFILE_PERSONAL = AbstractMultiProfilePagerAdapter.PROFILE_PERSONAL;
static final int PROFILE_WORK = AbstractMultiProfilePagerAdapter.PROFILE_WORK;
@@ -470,17 +479,20 @@ public class ResolverActivity extends Activity implements
// the intent resolver is started in the other profile. Since this is the only case when
// this happens, we check for it here and set the current profile's tab.
int selectedProfile = getCurrentProfile();
- UserHandle intentUser = UserHandle.of(getLaunchingUserId());
+ UserHandle intentUser = getIntent().hasExtra(EXTRA_CALLING_USER)
+ ? getIntent().getParcelableExtra(EXTRA_CALLING_USER)
+ : getUser();
if (!getUser().equals(intentUser)) {
if (getPersonalProfileUserHandle().equals(intentUser)) {
selectedProfile = PROFILE_PERSONAL;
} else if (getWorkProfileUserHandle().equals(intentUser)) {
selectedProfile = PROFILE_WORK;
}
- }
- int selectedProfileExtra = getSelectedProfileExtra();
- if (selectedProfileExtra != -1) {
- selectedProfile = selectedProfileExtra;
+ } else {
+ int selectedProfileExtra = getSelectedProfileExtra();
+ if (selectedProfileExtra != -1) {
+ selectedProfile = selectedProfileExtra;
+ }
}
// We only show the default app for the profile of the current user. The filterLastUsed
// flag determines whether to show a default app and that app is not shown in the
@@ -535,22 +547,6 @@ public class ResolverActivity extends Activity implements
return selectedProfile;
}
- /**
- * Returns the user id of the user that the starting intent originated from.
- * <p>This is not necessarily equal to {@link #getUserId()} or {@link UserHandle#myUserId()},
- * as there are edge cases when the intent resolver is launched in the other profile.
- * For example, when we have 0 resolved apps in current profile and multiple resolved apps
- * in the other profile, opening a link from the current profile launches the intent resolver
- * in the other one. b/148536209 for more info.
- */
- private int getLaunchingUserId() {
- int contentUserHint = getIntent().getContentUserHint();
- if (contentUserHint == UserHandle.USER_CURRENT) {
- return UserHandle.myUserId();
- }
- return contentUserHint;
- }
-
protected @Profile int getCurrentProfile() {
return (UserHandle.myUserId() == UserHandle.USER_SYSTEM ? PROFILE_PERSONAL : PROFILE_WORK);
}
@@ -1235,8 +1231,8 @@ public class ResolverActivity extends Activity implements
}
if (target != null) {
- if (intent != null) {
- intent.fixUris(UserHandle.myUserId());
+ if (intent != null && isLaunchingTargetInOtherProfile()) {
+ prepareIntentForCrossProfileLaunch(intent);
}
safelyStartActivity(target);
@@ -1250,6 +1246,15 @@ public class ResolverActivity extends Activity implements
return true;
}
+ private void prepareIntentForCrossProfileLaunch(Intent intent) {
+ intent.fixUris(UserHandle.myUserId());
+ }
+
+ private boolean isLaunchingTargetInOtherProfile() {
+ return mMultiProfilePagerAdapter.getCurrentUserHandle().getIdentifier()
+ != UserHandle.myUserId();
+ }
+
@VisibleForTesting
public void safelyStartActivity(TargetInfo cti) {
// We're dispatching intents that might be coming from legacy apps, so
@@ -1646,10 +1651,18 @@ public class ResolverActivity extends Activity implements
viewPager.setVisibility(View.VISIBLE);
tabHost.setCurrentTab(mMultiProfilePagerAdapter.getCurrentPage());
mMultiProfilePagerAdapter.setOnProfileSelectedListener(
- index -> {
- tabHost.setCurrentTab(index);
- resetButtonBar();
- resetCheckedItem();
+ new AbstractMultiProfilePagerAdapter.OnProfileSelectedListener() {
+ @Override
+ public void onProfileSelected(int index) {
+ tabHost.setCurrentTab(index);
+ resetButtonBar();
+ resetCheckedItem();
+ }
+
+ @Override
+ public void onProfilePageStateChanged(int state) {
+ onHorizontalSwipeStateChanged(state);
+ }
});
mMultiProfilePagerAdapter.setOnSwitchOnWorkSelectedListener(
() -> {
@@ -1661,6 +1674,8 @@ public class ResolverActivity extends Activity implements
findViewById(R.id.resolver_tab_divider).setVisibility(View.VISIBLE);
}
+ void onHorizontalSwipeStateChanged(int state) {}
+
private void maybeHideDivider() {
if (!isIntentPicker()) {
return;
@@ -1801,6 +1816,12 @@ public class ResolverActivity extends Activity implements
ResolverListAdapter activeListAdapter =
mMultiProfilePagerAdapter.getActiveListAdapter();
View buttonBarDivider = findViewById(R.id.resolver_button_bar_divider);
+ if (!useLayoutWithDefault()) {
+ int inset = mSystemWindowInsets != null ? mSystemWindowInsets.bottom : 0;
+ buttonLayout.setPadding(buttonLayout.getPaddingLeft(), buttonLayout.getPaddingTop(),
+ buttonLayout.getPaddingRight(), getResources().getDimensionPixelSize(
+ R.dimen.resolver_button_bar_spacing) + inset);
+ }
if (activeListAdapter.isTabLoaded()
&& mMultiProfilePagerAdapter.shouldShowEmptyStateScreen(activeListAdapter)
&& !useLayoutWithDefault()) {
@@ -1817,12 +1838,6 @@ public class ResolverActivity extends Activity implements
buttonLayout.setVisibility(View.VISIBLE);
setButtonBarIgnoreOffset(/* ignoreOffset */ true);
- if (!useLayoutWithDefault()) {
- int inset = mSystemWindowInsets != null ? mSystemWindowInsets.bottom : 0;
- buttonLayout.setPadding(buttonLayout.getPaddingLeft(), buttonLayout.getPaddingTop(),
- buttonLayout.getPaddingRight(), getResources().getDimensionPixelSize(
- R.dimen.resolver_button_bar_spacing) + inset);
- }
mOnceButton = (Button) buttonLayout.findViewById(R.id.button_once);
mAlwaysButton = (Button) buttonLayout.findViewById(R.id.button_always);
diff --git a/core/java/com/android/internal/app/ResolverListAdapter.java b/core/java/com/android/internal/app/ResolverListAdapter.java
index 97f43d27a9ce..d63ebda5117e 100644
--- a/core/java/com/android/internal/app/ResolverListAdapter.java
+++ b/core/java/com/android/internal/app/ResolverListAdapter.java
@@ -423,7 +423,6 @@ public class ResolverListAdapter extends BaseAdapter {
// We assume that at this point we've already filtered out the only intent for a different
// targetUserId which we're going to use.
private void addResolveInfo(DisplayResolveInfo dri) {
- // TODO(arangelov): Is that UserHandle.USER_CURRENT check okay?
if (dri != null && dri.getResolveInfo() != null
&& dri.getResolveInfo().targetUserId == UserHandle.USER_CURRENT) {
if (shouldAddResolveInfo(dri)) {
@@ -618,7 +617,8 @@ public class ResolverListAdapter extends BaseAdapter {
}
}
- UserHandle getUserHandle() {
+ @VisibleForTesting
+ public UserHandle getUserHandle() {
return mResolverListController.getUserHandle();
}
diff --git a/core/java/com/android/internal/app/ResolverViewPager.java b/core/java/com/android/internal/app/ResolverViewPager.java
index 4eb6e3bd2071..9cdfc2f5c763 100644
--- a/core/java/com/android/internal/app/ResolverViewPager.java
+++ b/core/java/com/android/internal/app/ResolverViewPager.java
@@ -18,6 +18,7 @@ package com.android.internal.app;
import android.content.Context;
import android.util.AttributeSet;
+import android.view.MotionEvent;
import android.view.View;
import com.android.internal.widget.ViewPager;
@@ -30,6 +31,8 @@ import com.android.internal.widget.ViewPager;
*/
public class ResolverViewPager extends ViewPager {
+ private boolean mSwipingEnabled = true;
+
public ResolverViewPager(Context context) {
super(context);
}
@@ -70,4 +73,13 @@ public class ResolverViewPager extends ViewPager {
heightMeasureSpec = MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY);
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
+
+ void setSwipingEnabled(boolean swipingEnabled) {
+ mSwipingEnabled = swipingEnabled;
+ }
+
+ @Override
+ public boolean onInterceptTouchEvent(MotionEvent ev) {
+ return mSwipingEnabled && super.onInterceptTouchEvent(ev);
+ }
}
diff --git a/core/java/com/android/internal/app/SimpleIconFactory.java b/core/java/com/android/internal/app/SimpleIconFactory.java
index ffe2dbe4ccc0..2d91e64b2e67 100644
--- a/core/java/com/android/internal/app/SimpleIconFactory.java
+++ b/core/java/com/android/internal/app/SimpleIconFactory.java
@@ -19,6 +19,7 @@ package com.android.internal.app;
import static android.content.Context.ACTIVITY_SERVICE;
import static android.graphics.Paint.DITHER_FLAG;
import static android.graphics.Paint.FILTER_BITMAP_FLAG;
+import static android.graphics.drawable.AdaptiveIconDrawable.getExtraInsetFraction;
import android.annotation.AttrRes;
import android.annotation.NonNull;
@@ -54,6 +55,7 @@ import com.android.internal.R;
import org.xmlpull.v1.XmlPullParser;
import java.nio.ByteBuffer;
+import java.util.Optional;
/**
@@ -64,6 +66,7 @@ import java.nio.ByteBuffer;
@Deprecated
public class SimpleIconFactory {
+
private static final SynchronizedPool<SimpleIconFactory> sPool =
new SynchronizedPool<>(Runtime.getRuntime().availableProcessors());
@@ -251,7 +254,7 @@ public class SimpleIconFactory {
} else if (w > h && h > 0) {
scale = (float) w / h;
}
- Bitmap bitmap = createIconBitmap(icon, scale);
+ Bitmap bitmap = createIconBitmapNoInsetOrMask(icon, scale);
bitmap = maskBitmapToCircle(bitmap);
icon = new BitmapDrawable(mContext.getResources(), bitmap);
@@ -281,15 +284,19 @@ public class SimpleIconFactory {
final Bitmap output = Bitmap.createBitmap(bitmap.getWidth(),
bitmap.getHeight(), Bitmap.Config.ARGB_8888);
final Canvas canvas = new Canvas(output);
- final Paint paint = new Paint();
- paint.setAntiAlias(true);
+ final Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.DITHER_FLAG
+ | Paint.FILTER_BITMAP_FLAG);
+
+ // Apply an offset to enable shadow to be drawn
+ final int size = bitmap.getWidth();
+ int offset = Math.max((int) Math.ceil(BLUR_FACTOR * size), 1);
// Draw mask
paint.setColor(0xffffffff);
canvas.drawARGB(0, 0, 0, 0);
canvas.drawCircle(bitmap.getWidth() / 2f,
bitmap.getHeight() / 2f,
- bitmap.getWidth() / 2f - 1 /* -1 to avoid circles with flat sides */,
+ bitmap.getWidth() / 2f - offset,
paint);
// Draw masked bitmap
@@ -306,24 +313,61 @@ public class SimpleIconFactory {
}
private Bitmap createIconBitmap(Drawable icon, float scale) {
- return createIconBitmap(icon, scale, mIconBitmapSize);
+ return createIconBitmap(icon, scale, mIconBitmapSize, true, false);
+ }
+
+ private Bitmap createIconBitmapNoInsetOrMask(Drawable icon, float scale) {
+ return createIconBitmap(icon, scale, mIconBitmapSize, false, true);
}
/**
* @param icon drawable that should be flattened to a bitmap
* @param scale the scale to apply before drawing {@param icon} on the canvas
+ * @param insetAdiForShadow when rendering AdaptiveIconDrawables inset to make room for a shadow
+ * @param ignoreAdiMask when rendering AdaptiveIconDrawables ignore the current system mask
*/
- private Bitmap createIconBitmap(Drawable icon, float scale, int size) {
+ private Bitmap createIconBitmap(Drawable icon, float scale, int size, boolean insetAdiForShadow,
+ boolean ignoreAdiMask) {
Bitmap bitmap = Bitmap.createBitmap(size, size, Bitmap.Config.ARGB_8888);
mCanvas.setBitmap(bitmap);
mOldBounds.set(icon.getBounds());
if (icon instanceof AdaptiveIconDrawable) {
- int offset = Math.max((int) Math.ceil(BLUR_FACTOR * size),
- Math.round(size * (1 - scale) / 2));
- icon.setBounds(offset, offset, size - offset, size - offset);
- icon.draw(mCanvas);
+ final AdaptiveIconDrawable adi = (AdaptiveIconDrawable) icon;
+
+ // By default assumes the output bitmap will have a shadow directly applied and makes
+ // room for it by insetting. If there are intermediate steps before applying the shadow
+ // insetting is disableable.
+ int offset = Math.round(size * (1 - scale) / 2);
+ if (insetAdiForShadow) {
+ offset = Math.max((int) Math.ceil(BLUR_FACTOR * size), offset);
+ }
+ Rect bounds = new Rect(offset, offset, size - offset, size - offset);
+
+ // AdaptiveIconDrawables are by default masked by the user's icon shape selection.
+ // If further masking is to be done, directly render to avoid the system masking.
+ if (ignoreAdiMask) {
+ final int cX = bounds.width() / 2;
+ final int cY = bounds.height() / 2;
+ final float portScale = 1f / (1 + 2 * getExtraInsetFraction());
+ final int insetWidth = (int) (bounds.width() / (portScale * 2));
+ final int insetHeight = (int) (bounds.height() / (portScale * 2));
+
+ Rect childRect = new Rect(cX - insetWidth, cY - insetHeight, cX + insetWidth,
+ cY + insetHeight);
+ Optional.ofNullable(adi.getBackground()).ifPresent(drawable -> {
+ drawable.setBounds(childRect);
+ drawable.draw(mCanvas);
+ });
+ Optional.ofNullable(adi.getForeground()).ifPresent(drawable -> {
+ drawable.setBounds(childRect);
+ drawable.draw(mCanvas);
+ });
+ } else {
+ adi.setBounds(bounds);
+ adi.draw(mCanvas);
+ }
} else {
if (icon instanceof BitmapDrawable) {
BitmapDrawable bitmapDrawable = (BitmapDrawable) icon;
diff --git a/core/java/com/android/internal/app/chooser/DisplayResolveInfo.java b/core/java/com/android/internal/app/chooser/DisplayResolveInfo.java
index 86a9af3db196..fe0e7d012262 100644
--- a/core/java/com/android/internal/app/chooser/DisplayResolveInfo.java
+++ b/core/java/com/android/internal/app/chooser/DisplayResolveInfo.java
@@ -40,8 +40,10 @@ import java.util.List;
* resolve it to an activity.
*/
public class DisplayResolveInfo implements TargetInfo {
- // Temporary flag for new chooser delegate behavior.
- private static final boolean ENABLE_CHOOSER_DELEGATE = true;
+ // Temporary flag for new chooser delegate behavior. There are occassional token
+ // permission errors from bouncing through the delegate. Watch out before reenabling:
+ // b/157272342 is one example but this issue has been reported many times
+ private static final boolean ENABLE_CHOOSER_DELEGATE = false;
private final ResolveInfo mResolveInfo;
private CharSequence mDisplayLabel;
diff --git a/core/java/com/android/internal/app/chooser/MultiDisplayResolveInfo.java b/core/java/com/android/internal/app/chooser/MultiDisplayResolveInfo.java
index e58258352106..cf921d734d48 100644
--- a/core/java/com/android/internal/app/chooser/MultiDisplayResolveInfo.java
+++ b/core/java/com/android/internal/app/chooser/MultiDisplayResolveInfo.java
@@ -70,6 +70,13 @@ public class MultiDisplayResolveInfo extends DisplayResolveInfo {
}
/**
+ * Return selected target.
+ */
+ public DisplayResolveInfo getSelectedTarget() {
+ return hasSelected() ? mTargetInfos.get(mSelected) : null;
+ }
+
+ /**
* Whether or not the user has selected a specific target for this MultiInfo.
*/
public boolean hasSelected() {
diff --git a/core/java/com/android/internal/app/procstats/ProcessState.java b/core/java/com/android/internal/app/procstats/ProcessState.java
index b8142607ebd7..ab58fc0eeafc 100644
--- a/core/java/com/android/internal/app/procstats/ProcessState.java
+++ b/core/java/com/android/internal/app/procstats/ProcessState.java
@@ -49,12 +49,14 @@ import android.os.SystemClock;
import android.os.UserHandle;
import android.service.procstats.ProcessStatsProto;
import android.service.procstats.ProcessStatsStateProto;
+import android.text.TextUtils;
import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.DebugUtils;
import android.util.Log;
import android.util.LongSparseArray;
import android.util.Slog;
+import android.util.SparseArray;
import android.util.SparseLongArray;
import android.util.TimeUtils;
import android.util.proto.ProtoOutputStream;
@@ -1420,10 +1422,38 @@ public final class ProcessState {
proto.end(token);
}
+ /**
+ * Assume the atom already includes a UID field, write the process name only if
+ * it's different from the package name; and only write the suffix if possible.
+ */
+ static void writeCompressedProcessName(final ProtoOutputStream proto, final long fieldId,
+ final String procName, final String packageName, final boolean sharedUid) {
+ if (sharedUid) {
+ // This UID has multiple packages running, write the full process name here
+ proto.write(fieldId, procName);
+ return;
+ }
+ if (TextUtils.equals(procName, packageName)) {
+ // Same name, don't bother to write the process name here.
+ return;
+ }
+ if (procName.startsWith(packageName)) {
+ final int pkgLength = packageName.length();
+ if (procName.charAt(pkgLength) == ':') {
+ // Only write the suffix starting with ':'
+ proto.write(fieldId, procName.substring(pkgLength));
+ return;
+ }
+ }
+ // Write the full process name
+ proto.write(fieldId, procName);
+ }
+
/** Similar to {@code #dumpDebug}, but with a reduced/aggregated subset of states. */
public void dumpAggregatedProtoForStatsd(ProtoOutputStream proto, long fieldId,
String procName, int uid, long now,
- final ProcessMap<ArraySet<PackageState>> procToPkgMap) {
+ final ProcessMap<ArraySet<PackageState>> procToPkgMap,
+ final SparseArray<ArraySet<String>> uidToPkgMap) {
// Group proc stats by aggregated type (only screen state + process state)
SparseLongArray durationByState = new SparseLongArray();
boolean didCurState = false;
@@ -1503,7 +1533,8 @@ public final class ProcessState {
// build the output
final long token = proto.start(fieldId);
- proto.write(ProcessStatsProto.PROCESS, procName);
+ writeCompressedProcessName(proto, ProcessStatsProto.PROCESS, procName, mPackage,
+ mMultiPackage || (uidToPkgMap.get(mUid).size() > 1));
proto.write(ProcessStatsProto.UID, uid);
for (int i = 0; i < durationByState.size(); i++) {
@@ -1528,7 +1559,7 @@ public final class ProcessState {
}
mStats.dumpFilteredAssociationStatesProtoForProc(proto, ProcessStatsProto.ASSOCS,
- now, this, procToPkgMap);
+ now, this, procToPkgMap, uidToPkgMap);
proto.end(token);
}
}
diff --git a/core/java/com/android/internal/app/procstats/ProcessStats.java b/core/java/com/android/internal/app/procstats/ProcessStats.java
index 928ba35595d3..7455ad009873 100644
--- a/core/java/com/android/internal/app/procstats/ProcessStats.java
+++ b/core/java/com/android/internal/app/procstats/ProcessStats.java
@@ -2235,8 +2235,9 @@ public final class ProcessStats implements Parcelable {
public void dumpAggregatedProtoForStatsd(ProtoOutputStream proto) {
dumpProtoPreamble(proto);
final ArrayMap<String, SparseArray<ProcessState>> procMap = mProcesses.getMap();
- final ProcessMap<ArraySet<PackageState>> procToPkgMap =
- collectProcessPackageMaps(null, false);
+ final ProcessMap<ArraySet<PackageState>> procToPkgMap = new ProcessMap<>();
+ final SparseArray<ArraySet<String>> uidToPkgMap = new SparseArray<>();
+ collectProcessPackageMaps(null, false, procToPkgMap, uidToPkgMap);
for (int ip = 0; ip < procMap.size(); ip++) {
final String procName = procMap.keyAt(ip);
final SparseArray<ProcessState> uids = procMap.valueAt(ip);
@@ -2245,7 +2246,8 @@ public final class ProcessStats implements Parcelable {
final ProcessState procState = uids.valueAt(iu);
procState.dumpAggregatedProtoForStatsd(proto,
ProcessStatsSectionProto.PROCESS_STATS,
- procName, uid, mTimePeriodEndRealtime, procToPkgMap);
+ procName, uid, mTimePeriodEndRealtime,
+ procToPkgMap, uidToPkgMap);
}
}
}
@@ -2279,10 +2281,9 @@ public final class ProcessStats implements Parcelable {
/**
* Walk through the known processes and build up the process -> packages map if necessary.
*/
- public ProcessMap<ArraySet<PackageState>> collectProcessPackageMaps(
- String reqPackage, boolean activeOnly) {
- final ProcessMap<ArraySet<PackageState>> map = new ProcessMap<>();
-
+ private void collectProcessPackageMaps(String reqPackage, boolean activeOnly,
+ final ProcessMap<ArraySet<PackageState>> procToPkgMap,
+ final SparseArray<ArraySet<String>> uidToPkgMap) {
final ArrayMap<String, SparseArray<LongSparseArray<PackageState>>> pkgMap =
mPackages.getMap();
for (int ip = pkgMap.size() - 1; ip >= 0; ip--) {
@@ -2304,17 +2305,22 @@ public final class ProcessStats implements Parcelable {
final String name = proc.getName();
final int uid = proc.getUid();
- ArraySet<PackageState> pkgStates = map.get(name, uid);
+ ArraySet<PackageState> pkgStates = procToPkgMap.get(name, uid);
if (pkgStates == null) {
pkgStates = new ArraySet<>();
- map.put(name, uid, pkgStates);
+ procToPkgMap.put(name, uid, pkgStates);
}
pkgStates.add(state);
+ ArraySet<String> packages = uidToPkgMap.get(uid);
+ if (packages == null) {
+ packages = new ArraySet<>();
+ uidToPkgMap.put(uid, packages);
+ }
+ packages.add(state.mPackageName);
}
}
}
}
- return map;
}
/**
@@ -2329,10 +2335,12 @@ public final class ProcessStats implements Parcelable {
* @param now The timestamp when the dump was initiated.
* @param procState The target process where its association states should be dumped.
* @param proc2Pkg The map between process to packages running within it.
+ * @param uidToPkgMap The map between UID to packages with this UID
*/
public void dumpFilteredAssociationStatesProtoForProc(ProtoOutputStream proto,
long fieldId, long now, ProcessState procState,
- final ProcessMap<ArraySet<PackageState>> proc2Pkg) {
+ final ProcessMap<ArraySet<PackageState>> proc2Pkg,
+ final SparseArray<ArraySet<String>> uidToPkgMap) {
if (procState.isMultiPackage() && procState.getCommonProcess() != procState) {
// It's a per-package process state, don't bother to write into statsd
return;
@@ -2395,8 +2403,11 @@ public final class ProcessStats implements Parcelable {
final SourceKey key = assocVals.keyAt(i);
final long[] vals = assocVals.valueAt(i);
final long token = proto.start(fieldId);
- proto.write(ProcessStatsAssociationProto.ASSOC_PROCESS_NAME, key.mProcess);
- proto.write(ProcessStatsAssociationProto.ASSOC_PACKAGE_NAME, key.mPackage);
+ ProcessState.writeCompressedProcessName(proto,
+ ProcessStatsAssociationProto.ASSOC_PROCESS_NAME,
+ key.mProcess, key.mPackage,
+ uidToPkgMap.get(key.mUid).size() > 1);
+ proto.write(ProcessStatsAssociationProto.ASSOC_UID, key.mUid);
proto.write(ProcessStatsAssociationProto.TOTAL_COUNT, (int) vals[1]);
proto.write(ProcessStatsAssociationProto.TOTAL_DURATION_SECS,
(int) (vals[0] / 1000));
diff --git a/core/java/com/android/internal/inputmethod/StartInputReason.java b/core/java/com/android/internal/inputmethod/StartInputReason.java
index a01c45919b8f..a4eaa21538f7 100644
--- a/core/java/com/android/internal/inputmethod/StartInputReason.java
+++ b/core/java/com/android/internal/inputmethod/StartInputReason.java
@@ -50,8 +50,9 @@ public @interface StartInputReason {
int WINDOW_FOCUS_GAIN = 1;
/**
* {@link android.view.Window} gained focus but there is no {@link android.view.View} that is
- * eligible to have IME focus. {@link android.view.inputmethod.InputMethodManager} just reports
- * this window focus change event.
+ * eligible to have IME focus, or the focused view is same as current served view and its
+ * input connection remains. {@link android.view.inputmethod.InputMethodManager} just reports
+ * this window focus change event to sync IME input target for system.
*/
int WINDOW_FOCUS_GAIN_REPORT_ONLY = 2;
/**
diff --git a/core/java/com/android/internal/logging/UiEventLogger.java b/core/java/com/android/internal/logging/UiEventLogger.java
index 67ffd4d93404..5212265f6c8a 100644
--- a/core/java/com/android/internal/logging/UiEventLogger.java
+++ b/core/java/com/android/internal/logging/UiEventLogger.java
@@ -60,4 +60,28 @@ public interface UiEventLogger {
*/
void logWithInstanceId(@NonNull UiEventEnum event, int uid, @Nullable String packageName,
@Nullable InstanceId instance);
+
+ /**
+ * Log an event with ranked-choice information along with package.
+ * Does nothing if event.getId() <= 0.
+ * @param event an enum implementing UiEventEnum interface.
+ * @param uid the uid of the relevant app, if known (0 otherwise).
+ * @param packageName the package name of the relevant app, if known (null otherwise).
+ * @param position the position picked.
+ */
+ void logWithPosition(@NonNull UiEventEnum event, int uid, @Nullable String packageName,
+ int position);
+
+ /**
+ * Log an event with ranked-choice information along with package and instance ID.
+ * Does nothing if event.getId() <= 0.
+ * @param event an enum implementing UiEventEnum interface.
+ * @param uid the uid of the relevant app, if known (0 otherwise).
+ * @param packageName the package name of the relevant app, if known (null otherwise).
+ * @param instance An identifier obtained from an InstanceIdSequence. If null, reduces to
+ * logWithPosition().
+ * @param position the position picked.
+ */
+ void logWithInstanceIdAndPosition(@NonNull UiEventEnum event, int uid,
+ @Nullable String packageName, @Nullable InstanceId instance, int position);
}
diff --git a/core/java/com/android/internal/logging/UiEventLoggerImpl.java b/core/java/com/android/internal/logging/UiEventLoggerImpl.java
index 4d171ec8a3a8..c9156c13aae3 100644
--- a/core/java/com/android/internal/logging/UiEventLoggerImpl.java
+++ b/core/java/com/android/internal/logging/UiEventLoggerImpl.java
@@ -48,4 +48,31 @@ public class UiEventLoggerImpl implements UiEventLogger {
log(event, uid, packageName);
}
}
+
+ @Override
+ public void logWithPosition(UiEventEnum event, int uid, String packageName, int position) {
+ final int eventID = event.getId();
+ if (eventID > 0) {
+ FrameworkStatsLog.write(FrameworkStatsLog.RANKING_SELECTED,
+ /* event_id = 1 */ eventID,
+ /* package_name = 2 */ packageName,
+ /* instance_id = 3 */ 0,
+ /* position_picked = 4 */ position);
+ }
+ }
+
+ @Override
+ public void logWithInstanceIdAndPosition(UiEventEnum event, int uid, String packageName,
+ InstanceId instance, int position) {
+ final int eventID = event.getId();
+ if ((eventID > 0) && (instance != null)) {
+ FrameworkStatsLog.write(FrameworkStatsLog.RANKING_SELECTED,
+ /* event_id = 1 */ eventID,
+ /* package_name = 2 */ packageName,
+ /* instance_id = 3 */ instance.getId(),
+ /* position_picked = 4 */ position);
+ } else {
+ logWithPosition(event, uid, packageName, position);
+ }
+ }
}
diff --git a/core/java/com/android/internal/logging/testing/UiEventLoggerFake.java b/core/java/com/android/internal/logging/testing/UiEventLoggerFake.java
index 180ab0810f5b..2d09434807a6 100644
--- a/core/java/com/android/internal/logging/testing/UiEventLoggerFake.java
+++ b/core/java/com/android/internal/logging/testing/UiEventLoggerFake.java
@@ -35,13 +35,15 @@ public class UiEventLoggerFake implements UiEventLogger {
public final int eventId;
public final int uid;
public final String packageName;
- public final InstanceId instanceId; // Used only for WithInstanceId variant
+ public final InstanceId instanceId; // Used only for WithInstanceId variants
+ public final int position; // Used only for Position variants
FakeUiEvent(int eventId, int uid, String packageName) {
this.eventId = eventId;
this.uid = uid;
this.packageName = packageName;
this.instanceId = null;
+ this.position = 0;
}
FakeUiEvent(int eventId, int uid, String packageName, InstanceId instanceId) {
@@ -49,6 +51,15 @@ public class UiEventLoggerFake implements UiEventLogger {
this.uid = uid;
this.packageName = packageName;
this.instanceId = instanceId;
+ this.position = 0;
+ }
+
+ FakeUiEvent(int eventId, int uid, String packageName, InstanceId instanceId, int position) {
+ this.eventId = eventId;
+ this.uid = uid;
+ this.packageName = packageName;
+ this.instanceId = instanceId;
+ this.position = position;
}
}
@@ -92,4 +103,21 @@ public class UiEventLoggerFake implements UiEventLogger {
mLogs.add(new FakeUiEvent(eventId, uid, packageName, instance));
}
}
+
+ @Override
+ public void logWithPosition(UiEventEnum event, int uid, String packageName, int position) {
+ final int eventId = event.getId();
+ if (eventId > 0) {
+ mLogs.add(new FakeUiEvent(eventId, uid, packageName, null, position));
+ }
+ }
+
+ @Override
+ public void logWithInstanceIdAndPosition(UiEventEnum event, int uid, String packageName,
+ InstanceId instance, int position) {
+ final int eventId = event.getId();
+ if (eventId > 0) {
+ mLogs.add(new FakeUiEvent(eventId, uid, packageName, instance, position));
+ }
+ }
}
diff --git a/core/java/com/android/internal/util/ScreenshotHelper.java b/core/java/com/android/internal/util/ScreenshotHelper.java
index ad6c7e8f7f60..d0052ab01331 100644
--- a/core/java/com/android/internal/util/ScreenshotHelper.java
+++ b/core/java/com/android/internal/util/ScreenshotHelper.java
@@ -8,10 +8,10 @@ import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
-import android.graphics.Bitmap;
import android.graphics.Insets;
import android.graphics.Rect;
import android.net.Uri;
+import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.os.Message;
@@ -37,10 +37,12 @@ public class ScreenshotHelper {
private int mSource;
private boolean mHasStatusBar;
private boolean mHasNavBar;
- private Bitmap mBitmap;
+ private Bundle mBitmapBundle;
private Rect mBoundsInScreen;
private Insets mInsets;
private int mTaskId;
+ private int mUserId;
+ private ComponentName mTopComponent;
ScreenshotRequest(int source, boolean hasStatus, boolean hasNav) {
mSource = source;
@@ -48,24 +50,29 @@ public class ScreenshotHelper {
mHasNavBar = hasNav;
}
- ScreenshotRequest(
- int source, Bitmap bitmap, Rect boundsInScreen, Insets insets, int taskId) {
+ ScreenshotRequest(int source, Bundle bitmapBundle, Rect boundsInScreen, Insets insets,
+ int taskId, int userId, ComponentName topComponent) {
mSource = source;
- mBitmap = bitmap;
+ mBitmapBundle = bitmapBundle;
mBoundsInScreen = boundsInScreen;
mInsets = insets;
mTaskId = taskId;
+ mUserId = userId;
+ mTopComponent = topComponent;
}
ScreenshotRequest(Parcel in) {
mSource = in.readInt();
mHasStatusBar = in.readBoolean();
mHasNavBar = in.readBoolean();
+
if (in.readInt() == 1) {
- mBitmap = in.readParcelable(Bitmap.class.getClassLoader());
+ mBitmapBundle = in.readBundle(getClass().getClassLoader());
mBoundsInScreen = in.readParcelable(Rect.class.getClassLoader());
mInsets = in.readParcelable(Insets.class.getClassLoader());
mTaskId = in.readInt();
+ mUserId = in.readInt();
+ mTopComponent = in.readParcelable(ComponentName.class.getClassLoader());
}
}
@@ -81,8 +88,8 @@ public class ScreenshotHelper {
return mHasNavBar;
}
- public Bitmap getBitmap() {
- return mBitmap;
+ public Bundle getBitmapBundle() {
+ return mBitmapBundle;
}
public Rect getBoundsInScreen() {
@@ -97,6 +104,15 @@ public class ScreenshotHelper {
return mTaskId;
}
+
+ public int getUserId() {
+ return mUserId;
+ }
+
+ public ComponentName getTopComponent() {
+ return mTopComponent;
+ }
+
@Override
public int describeContents() {
return 0;
@@ -107,14 +123,16 @@ public class ScreenshotHelper {
dest.writeInt(mSource);
dest.writeBoolean(mHasStatusBar);
dest.writeBoolean(mHasNavBar);
- if (mBitmap == null) {
+ if (mBitmapBundle == null) {
dest.writeInt(0);
} else {
dest.writeInt(1);
- dest.writeParcelable(mBitmap, 0);
+ dest.writeBundle(mBitmapBundle);
dest.writeParcelable(mBoundsInScreen, 0);
dest.writeParcelable(mInsets, 0);
dest.writeInt(mTaskId);
+ dest.writeInt(mUserId);
+ dest.writeParcelable(mTopComponent, 0);
}
}
@@ -234,19 +252,22 @@ public class ScreenshotHelper {
/**
* Request that provided image be handled as if it was a screenshot.
*
- * @param screenshot The bitmap to treat as the screen shot.
+ * @param screenshotBundle Bundle containing the buffer and color space of the screenshot.
* @param boundsInScreen The bounds in screen coordinates that the bitmap orginated from.
* @param insets The insets that the image was shown with, inside the screenbounds.
* @param taskId The taskId of the task that the screen shot was taken of.
+ * @param userId The userId of user running the task provided in taskId.
+ * @param topComponent The component name of the top component running in the task.
* @param handler A handler used in case the screenshot times out
* @param completionConsumer Consumes `false` if a screenshot was not taken, and `true` if the
* screenshot was taken.
*/
- public void provideScreenshot(@NonNull Bitmap screenshot, @NonNull Rect boundsInScreen,
- @NonNull Insets insets, int taskId, int source,
+ public void provideScreenshot(@NonNull Bundle screenshotBundle, @NonNull Rect boundsInScreen,
+ @NonNull Insets insets, int taskId, int userId, ComponentName topComponent, int source,
@NonNull Handler handler, @Nullable Consumer<Uri> completionConsumer) {
ScreenshotRequest screenshotRequest =
- new ScreenshotRequest(source, screenshot, boundsInScreen, insets, taskId);
+ new ScreenshotRequest(source, screenshotBundle, boundsInScreen, insets, taskId,
+ userId, topComponent);
takeScreenshot(WindowManager.TAKE_SCREENSHOT_PROVIDED_IMAGE, SCREENSHOT_TIMEOUT_MS,
handler, screenshotRequest, completionConsumer);
}
@@ -330,8 +351,11 @@ public class ScreenshotHelper {
mContext.unbindService(mScreenshotConnection);
mScreenshotConnection = null;
mScreenshotService = null;
- handler.removeCallbacks(mScreenshotTimeout);
- notifyScreenshotError();
+ // only log an error if we're still within the timeout period
+ if (handler.hasCallbacks(mScreenshotTimeout)) {
+ handler.removeCallbacks(mScreenshotTimeout);
+ notifyScreenshotError();
+ }
}
}
}
diff --git a/core/java/com/android/internal/util/SyncResultReceiver.java b/core/java/com/android/internal/util/SyncResultReceiver.java
index 00e91017a9eb..6b1358293d02 100644
--- a/core/java/com/android/internal/util/SyncResultReceiver.java
+++ b/core/java/com/android/internal/util/SyncResultReceiver.java
@@ -182,7 +182,7 @@ public final class SyncResultReceiver extends IResultReceiver.Stub {
}
/** @hide */
- public static final class TimeoutException extends RuntimeException {
+ public static final class TimeoutException extends Exception {
private TimeoutException(String msg) {
super(msg);
}
diff --git a/core/java/com/android/internal/widget/ConversationLayout.java b/core/java/com/android/internal/widget/ConversationLayout.java
index 688e00bc5a29..075159671b17 100644
--- a/core/java/com/android/internal/widget/ConversationLayout.java
+++ b/core/java/com/android/internal/widget/ConversationLayout.java
@@ -21,6 +21,10 @@ import static com.android.internal.widget.MessagingGroup.IMAGE_DISPLAY_LOCATION_
import static com.android.internal.widget.MessagingPropertyAnimator.ALPHA_IN;
import static com.android.internal.widget.MessagingPropertyAnimator.ALPHA_OUT;
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.AnimatorSet;
+import android.animation.ValueAnimator;
import android.annotation.AttrRes;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -36,6 +40,7 @@ import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Rect;
import android.graphics.Typeface;
+import android.graphics.drawable.GradientDrawable;
import android.graphics.drawable.Icon;
import android.os.Bundle;
import android.os.Parcelable;
@@ -80,7 +85,7 @@ public class ConversationLayout extends FrameLayout
private static final float COLOR_SHIFT_AMOUNT = 60;
/**
- * Pattren for filter some ingonable characters.
+ * Pattern for filter some ignorable characters.
* p{Z} for any kind of whitespace or invisible separator.
* p{C} for any kind of punctuation character.
*/
@@ -93,8 +98,12 @@ public class ConversationLayout extends FrameLayout
public static final Interpolator LINEAR_OUT_SLOW_IN = new PathInterpolator(0f, 0f, 0.2f, 1f);
public static final Interpolator FAST_OUT_LINEAR_IN = new PathInterpolator(0.4f, 0f, 1f, 1f);
public static final Interpolator FAST_OUT_SLOW_IN = new PathInterpolator(0.4f, 0f, 0.2f, 1f);
+ public static final Interpolator OVERSHOOT = new PathInterpolator(0.4f, 0f, 0.2f, 1.4f);
public static final OnLayoutChangeListener MESSAGING_PROPERTY_ANIMATOR
= new MessagingPropertyAnimator();
+ public static final int IMPORTANCE_ANIM_GROW_DURATION = 250;
+ public static final int IMPORTANCE_ANIM_SHRINK_DURATION = 200;
+ public static final int IMPORTANCE_ANIM_SHRINK_DELAY = 25;
private List<MessagingMessage> mMessages = new ArrayList<>();
private List<MessagingMessage> mHistoricMessages = new ArrayList<>();
private MessagingLinearLayout mMessagingLinearLayout;
@@ -161,6 +170,7 @@ public class ConversationLayout extends FrameLayout
private Rect mAppOpsTouchRect = new Rect();
private float mMinTouchSize;
private Icon mConversationIcon;
+ private Icon mShortcutIcon;
private View mAppNameDivider;
public ConversationLayout(@NonNull Context context) {
@@ -330,14 +340,74 @@ public class ConversationLayout extends FrameLayout
mNameReplacement = nameReplacement;
}
- /**
- * Sets this conversation as "important", adding some additional UI treatment.
- */
+ /** Sets this conversation as "important", adding some additional UI treatment. */
@RemotableViewMethod
public void setIsImportantConversation(boolean isImportantConversation) {
+ setIsImportantConversation(isImportantConversation, false);
+ }
+
+ /** @hide **/
+ public void setIsImportantConversation(boolean isImportantConversation, boolean animate) {
mImportantConversation = isImportantConversation;
- mImportanceRingView.setVisibility(isImportantConversation
- && mIcon.getVisibility() != GONE ? VISIBLE : GONE);
+ mImportanceRingView.setVisibility(isImportantConversation && mIcon.getVisibility() != GONE
+ ? VISIBLE : GONE);
+
+ if (animate && isImportantConversation) {
+ GradientDrawable ring = (GradientDrawable) mImportanceRingView.getDrawable();
+ ring.mutate();
+ GradientDrawable bg = (GradientDrawable) mConversationIconBadgeBg.getDrawable();
+ bg.mutate();
+ int ringColor = getResources()
+ .getColor(R.color.conversation_important_highlight);
+ int standardThickness = getResources()
+ .getDimensionPixelSize(R.dimen.importance_ring_stroke_width);
+ int largeThickness = getResources()
+ .getDimensionPixelSize(R.dimen.importance_ring_anim_max_stroke_width);
+ int standardSize = getResources().getDimensionPixelSize(
+ R.dimen.importance_ring_size);
+ int baseSize = standardSize - standardThickness * 2;
+ int bgSize = getResources()
+ .getDimensionPixelSize(R.dimen.conversation_icon_size_badged);
+
+ ValueAnimator.AnimatorUpdateListener animatorUpdateListener = animation -> {
+ int strokeWidth = Math.round((float) animation.getAnimatedValue());
+ ring.setStroke(strokeWidth, ringColor);
+ int newSize = baseSize + strokeWidth * 2;
+ ring.setSize(newSize, newSize);
+ mImportanceRingView.invalidate();
+ };
+
+ ValueAnimator growAnimation = ValueAnimator.ofFloat(0, largeThickness);
+ growAnimation.setInterpolator(LINEAR_OUT_SLOW_IN);
+ growAnimation.setDuration(IMPORTANCE_ANIM_GROW_DURATION);
+ growAnimation.addUpdateListener(animatorUpdateListener);
+
+ ValueAnimator shrinkAnimation =
+ ValueAnimator.ofFloat(largeThickness, standardThickness);
+ shrinkAnimation.setDuration(IMPORTANCE_ANIM_SHRINK_DURATION);
+ shrinkAnimation.setStartDelay(IMPORTANCE_ANIM_SHRINK_DELAY);
+ shrinkAnimation.setInterpolator(OVERSHOOT);
+ shrinkAnimation.addUpdateListener(animatorUpdateListener);
+ shrinkAnimation.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationStart(Animator animation) {
+ // Shrink the badge bg so that it doesn't peek behind the animation
+ bg.setSize(baseSize, baseSize);
+ mConversationIconBadgeBg.invalidate();
+ }
+
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ // Reset bg back to normal size
+ bg.setSize(bgSize, bgSize);
+ mConversationIconBadgeBg.invalidate();
+ }
+ });
+
+ AnimatorSet anims = new AnimatorSet();
+ anims.playSequentially(growAnimation, shrinkAnimation);
+ anims.start();
+ }
}
public boolean isImportantConversation() {
@@ -465,10 +535,9 @@ public class ConversationLayout extends FrameLayout
private void updateConversationLayout() {
// Set avatar and name
CharSequence conversationText = mConversationTitle;
+ mConversationIcon = mShortcutIcon;
if (mIsOneToOne) {
// Let's resolve the icon / text from the last sender
- mConversationIconView.setVisibility(VISIBLE);
- mConversationFacePile.setVisibility(GONE);
CharSequence userKey = getKey(mUser);
for (int i = mGroups.size() - 1; i >= 0; i--) {
MessagingGroup messagingGroup = mGroups.get(i);
@@ -480,30 +549,31 @@ public class ConversationLayout extends FrameLayout
// (This usually happens for most 1:1 conversations)
conversationText = messagingGroup.getSenderName();
}
- Icon avatarIcon = messagingGroup.getAvatarIcon();
- if (avatarIcon == null) {
- avatarIcon = createAvatarSymbol(conversationText, "", mLayoutColor);
+ if (mConversationIcon == null) {
+ Icon avatarIcon = messagingGroup.getAvatarIcon();
+ if (avatarIcon == null) {
+ avatarIcon = createAvatarSymbol(conversationText, "", mLayoutColor);
+ }
+ mConversationIcon = avatarIcon;
}
- mConversationIcon = avatarIcon;
- mConversationIconView.setImageIcon(mConversationIcon);
break;
}
}
+ }
+ if (mConversationIcon == null) {
+ mConversationIcon = mLargeIcon;
+ }
+ if (mIsOneToOne || mConversationIcon != null) {
+ mConversationIconView.setVisibility(VISIBLE);
+ mConversationFacePile.setVisibility(GONE);
+ mConversationIconView.setImageIcon(mConversationIcon);
} else {
- if (mLargeIcon != null) {
- mConversationIcon = mLargeIcon;
- mConversationIconView.setVisibility(VISIBLE);
- mConversationFacePile.setVisibility(GONE);
- mConversationIconView.setImageIcon(mLargeIcon);
- } else {
- mConversationIcon = null;
- mConversationIconView.setVisibility(GONE);
- // This will also inflate it!
- mConversationFacePile.setVisibility(VISIBLE);
- // rebind the value to the inflated view instead of the stub
- mConversationFacePile = findViewById(R.id.conversation_face_pile);
- bindFacePile();
- }
+ mConversationIconView.setVisibility(GONE);
+ // This will also inflate it!
+ mConversationFacePile.setVisibility(VISIBLE);
+ // rebind the value to the inflated view instead of the stub
+ mConversationFacePile = findViewById(R.id.conversation_face_pile);
+ bindFacePile();
}
if (TextUtils.isEmpty(conversationText)) {
conversationText = mIsOneToOne ? mFallbackChatName : mFallbackGroupChatName;
@@ -691,9 +761,13 @@ public class ConversationLayout extends FrameLayout
// group
: mExpandedGroupMessagePadding;
+ int iconPadding = mIsOneToOne || mIsCollapsed
+ ? mConversationIconTopPadding
+ : mConversationIconTopPaddingExpandedGroup;
+
mConversationIconContainer.setPaddingRelative(
mConversationIconContainer.getPaddingStart(),
- mConversationIconTopPadding,
+ iconPadding,
mConversationIconContainer.getPaddingEnd(),
mConversationIconContainer.getPaddingBottom());
@@ -709,6 +783,11 @@ public class ConversationLayout extends FrameLayout
mLargeIcon = largeIcon;
}
+ @RemotableViewMethod
+ public void setShortcutIcon(Icon conversationIcon) {
+ mConversationIcon = conversationIcon;
+ }
+
/**
* Sets the conversation title of this conversation.
*
@@ -1170,7 +1249,6 @@ public class ConversationLayout extends FrameLayout
}
private void updateContentEndPaddings() {
-
// Let's make sure the conversation header can't run into the expand button when we're
// collapsed and update the paddings of the content
int headerPaddingEnd;
@@ -1216,7 +1294,6 @@ public class ConversationLayout extends FrameLayout
mExpandButtonContainer.setVisibility(VISIBLE);
mExpandButtonInnerContainer.setOnClickListener(onClickListener);
} else {
- // TODO: handle content paddings to end of layout
mExpandButtonContainer.setVisibility(GONE);
}
updateContentEndPaddings();
diff --git a/core/jni/android_media_AudioEffectDescriptor.cpp b/core/jni/android_media_AudioEffectDescriptor.cpp
index 37d8114052b8..1435e879053c 100644
--- a/core/jni/android_media_AudioEffectDescriptor.cpp
+++ b/core/jni/android_media_AudioEffectDescriptor.cpp
@@ -102,9 +102,9 @@ void convertAudioEffectDescriptorVectorFromNative(JNIEnv *env, jobjectArray *jDe
*jDescriptors = env->NewObjectArray(actualSize, audioEffectDescriptorClass(), NULL);
for (size_t i = 0; i < actualSize; i++) {
- env->SetObjectArrayElement(*jDescriptors,
- i,
- env->GetObjectArrayElement(temp, i));
+ jobject jdesc = env->GetObjectArrayElement(temp, i);
+ env->SetObjectArrayElement(*jDescriptors, i, jdesc);
+ env->DeleteLocalRef(jdesc);
}
env->DeleteLocalRef(temp);
}
diff --git a/core/jni/com_android_internal_os_Zygote.cpp b/core/jni/com_android_internal_os_Zygote.cpp
index fc2005a31696..9eede83e21e5 100644
--- a/core/jni/com_android_internal_os_Zygote.cpp
+++ b/core/jni/com_android_internal_os_Zygote.cpp
@@ -526,8 +526,16 @@ static void UnsetChldSignalHandler() {
// Calls POSIX setgroups() using the int[] object as an argument.
// A nullptr argument is tolerated.
-static void SetGids(JNIEnv* env, jintArray managed_gids, fail_fn_t fail_fn) {
+static void SetGids(JNIEnv* env, jintArray managed_gids, jboolean is_child_zygote,
+ fail_fn_t fail_fn) {
if (managed_gids == nullptr) {
+ if (is_child_zygote) {
+ // For child zygotes like webview and app zygote, we want to clear out
+ // any supplemental groups the parent zygote had.
+ if (setgroups(0, NULL) == -1) {
+ fail_fn(CREATE_ERROR("Failed to remove supplementary groups for child zygote"));
+ }
+ }
return;
}
@@ -1351,7 +1359,13 @@ static void isolateAppData(JNIEnv* env, const std::vector<std::string>& merged_d
}
closedir(dir);
- bool legacySymlinkCreated = false;
+ // Prepare default dirs for user 0 as user 0 always exists.
+ int result = symlink("/data/data", "/data/user/0");
+ if (result != 0) {
+ fail_fn(CREATE_ERROR("Failed to create symlink /data/user/0 %s", strerror(errno)));
+ }
+ PrepareDirIfNotPresent("/data/user_de/0", DEFAULT_DATA_DIR_PERMISSION,
+ AID_ROOT, AID_ROOT, fail_fn);
for (int i = 0; i < size; i += 3) {
std::string const & packageName = merged_data_info_list[i];
@@ -1392,17 +1406,8 @@ static void isolateAppData(JNIEnv* env, const std::vector<std::string>& merged_d
char internalDeUserPath[PATH_MAX];
snprintf(internalCeUserPath, PATH_MAX, "/data/user/%d", userId);
snprintf(internalDeUserPath, PATH_MAX, "/data/user_de/%d", userId);
- // If it's user 0, create a symlink /data/user/0 -> /data/data,
- // otherwise create /data/user/$USER
+ // If it's not user 0, create /data/user/$USER.
if (userId == 0) {
- if (!legacySymlinkCreated) {
- legacySymlinkCreated = true;
- int result = symlink(internalLegacyCePath, internalCeUserPath);
- if (result != 0) {
- fail_fn(CREATE_ERROR("Failed to create symlink %s %s", internalCeUserPath,
- strerror(errno)));
- }
- }
actualCePath = internalLegacyCePath;
} else {
PrepareDirIfNotPresent(internalCeUserPath, DEFAULT_DATA_DIR_PERMISSION,
@@ -1579,10 +1584,6 @@ static void BindMountStorageDirs(JNIEnv* env, jobjectArray pkg_data_info_list,
// Fuse is ready, so we can start using fuse path.
int size = (pkg_data_info_list != nullptr) ? env->GetArrayLength(pkg_data_info_list) : 0;
- if (size == 0) {
- fail_fn(CREATE_ERROR("Data package list cannot be empty"));
- }
-
// Create tmpfs on Android/obb and Android/data so these 2 dirs won't enter fuse anymore.
std::string androidObbDir = StringPrintf("/storage/emulated/%d/Android/obb", user_id);
MountAppDataTmpFs(androidObbDir, fail_fn);
@@ -1665,7 +1666,7 @@ static void SpecializeCommon(JNIEnv* env, uid_t uid, gid_t gid, jintArray gids,
}
}
- SetGids(env, gids, fail_fn);
+ SetGids(env, gids, is_child_zygote, fail_fn);
SetRLimits(env, rlimits, fail_fn);
if (need_pre_initialize_native_bridge) {
@@ -1736,6 +1737,8 @@ static void SpecializeCommon(JNIEnv* env, uid_t uid, gid_t gid, jintArray gids,
heap_tagging_level = M_HEAP_TAGGING_LEVEL_NONE;
}
android_mallopt(M_SET_HEAP_TAGGING_LEVEL, &heap_tagging_level, sizeof(heap_tagging_level));
+ // Now that we've used the flag, clear it so that we don't pass unknown flags to the ART runtime.
+ runtime_flags &= ~RuntimeFlags::MEMORY_TAG_LEVEL_MASK;
bool forceEnableGwpAsan = false;
switch (runtime_flags & RuntimeFlags::GWP_ASAN_LEVEL_MASK) {
@@ -1748,6 +1751,8 @@ static void SpecializeCommon(JNIEnv* env, uid_t uid, gid_t gid, jintArray gids,
case RuntimeFlags::GWP_ASAN_LEVEL_LOTTERY:
android_mallopt(M_INITIALIZE_GWP_ASAN, &forceEnableGwpAsan, sizeof(forceEnableGwpAsan));
}
+ // Now that we've used the flag, clear it so that we don't pass unknown flags to the ART runtime.
+ runtime_flags &= ~RuntimeFlags::GWP_ASAN_LEVEL_MASK;
if (NeedsNoRandomizeWorkaround()) {
// Work around ARM kernel ASLR lossage (http://b/5817320).
diff --git a/core/proto/android/server/connectivity/data_stall_event.proto b/core/proto/android/server/connectivity/data_stall_event.proto
index 23fcf6ebc2cc..787074ba494e 100644
--- a/core/proto/android/server/connectivity/data_stall_event.proto
+++ b/core/proto/android/server/connectivity/data_stall_event.proto
@@ -32,6 +32,7 @@ enum ApBand {
AP_BAND_UNKNOWN = 0;
AP_BAND_2GHZ = 1;
AP_BAND_5GHZ = 2;
+ AP_BAND_6GHZ = 3;
}
// Refer to definition in TelephonyManager.java.
diff --git a/core/proto/android/service/notification.proto b/core/proto/android/service/notification.proto
index ecb4193a2c6c..8e4006aa6861 100644
--- a/core/proto/android/service/notification.proto
+++ b/core/proto/android/service/notification.proto
@@ -274,4 +274,74 @@ message PackageRemoteViewInfoProto {
// Next Tag: 2
message NotificationRemoteViewsProto {
repeated PackageRemoteViewInfoProto package_remote_view_info = 1;
-} \ No newline at end of file
+}
+
+/**
+ * Atom that represents an item in the list of Do Not Disturb rules, pulled from
+ * NotificationManagerService.java.
+ */
+message DNDModeProto {
+ enum Mode {
+ ROOT_CONFIG = -1; // Used to distinguish the config (one per user) from the rules.
+ ZEN_MODE_OFF = 0;
+ ZEN_MODE_IMPORTANT_INTERRUPTIONS = 1;
+ ZEN_MODE_NO_INTERRUPTIONS = 2;
+ ZEN_MODE_ALARMS = 3;
+ }
+ optional int32 user = 1; // Android user ID (0, 1, 10, ...)
+ optional bool enabled = 2; // true for ROOT_CONFIG if a manualRule is enabled
+ optional bool channels_bypassing = 3; // only valid for ROOT_CONFIG
+ optional Mode zen_mode = 4;
+ // id is one of the system default rule IDs, or empty
+ // May also be "MANUAL_RULE" to indicate app-activation of the manual rule.
+ optional string id = 5;
+ optional int32 uid = 6; // currently only SYSTEM_UID or 0 for other
+ optional DNDPolicyProto policy = 7;
+}
+
+/**
+ * Atom that represents a Do Not Disturb policy, an optional detail proto for DNDModeProto.
+ */
+message DNDPolicyProto {
+ enum State {
+ STATE_UNSET = 0;
+ STATE_ALLOW = 1;
+ STATE_DISALLOW = 2;
+ }
+ optional State calls = 1;
+ optional State repeat_callers = 2;
+ optional State messages = 3;
+ optional State conversations = 4;
+ optional State reminders = 5;
+ optional State events = 6;
+ optional State alarms = 7;
+ optional State media = 8;
+ optional State system = 9;
+ optional State fullscreen = 10;
+ optional State lights = 11;
+ optional State peek = 12;
+ optional State status_bar = 13;
+ optional State badge = 14;
+ optional State ambient = 15;
+ optional State notification_list = 16;
+
+ enum PeopleType {
+ PEOPLE_UNSET = 0;
+ PEOPLE_ANYONE = 1;
+ PEOPLE_CONTACTS = 2;
+ PEOPLE_STARRED = 3;
+ PEOPLE_NONE = 4;
+ }
+
+ optional PeopleType allow_calls_from = 17;
+ optional PeopleType allow_messages_from = 18;
+
+ enum ConversationType {
+ CONV_UNSET = 0;
+ CONV_ANYONE = 1;
+ CONV_IMPORTANT = 2;
+ CONV_NONE = 3;
+ }
+
+ optional ConversationType allow_conversations_from = 19;
+}
diff --git a/core/proto/android/service/procstats.proto b/core/proto/android/service/procstats.proto
index dd830a85edc9..7a4c0706e119 100644
--- a/core/proto/android/service/procstats.proto
+++ b/core/proto/android/service/procstats.proto
@@ -179,13 +179,16 @@ message ProcessStatsProto {
repeated ProcessStatsAssociationProto assocs = 7;
}
-// Next Tag: 5
+// Next Tag: 6
message ProcessStatsAssociationProto {
// Procss Name of the associated process/package
optional string assoc_process_name = 1;
// Package Name of the associated process/package
- optional string assoc_package_name = 2;
+ optional string assoc_package_name = 2 [deprecated = true];
+
+ // UID of the associated process/package
+ optional int32 assoc_uid = 5;
// Total count of the times this association appeared.
optional int32 total_count = 3;
diff --git a/core/proto/android/stats/mediametrics/mediametrics.proto b/core/proto/android/stats/mediametrics/mediametrics.proto
index e1af9622adb3..9f0ff591a506 100644
--- a/core/proto/android/stats/mediametrics/mediametrics.proto
+++ b/core/proto/android/stats/mediametrics/mediametrics.proto
@@ -131,7 +131,7 @@ message AudioTrackData {
* Logged from:
* frameworks/av/media/libstagefright/MediaCodec.cpp
* frameworks/av/services/mediaanalytics/statsd_codec.cpp
- * Next Tag: 21
+ * Next Tag: 26
*/
message CodecData {
optional string codec = 1;
@@ -156,6 +156,9 @@ message CodecData {
optional int64 latency_unknown = 20;
optional int32 queue_input_buffer_error = 21;
optional int32 queue_secure_input_buffer_error = 22;
+ optional string bitrate_mode = 23;
+ optional int32 bitrate = 24;
+ optional int64 lifetime_millis = 25;
}
/**
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index fd8460f9c478..f71d4063b847 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -3158,7 +3158,7 @@
@hide
-->
<permission android:name="android.permission.HIDE_NON_SYSTEM_OVERLAY_WINDOWS"
- android:protectionLevel="signature|installer" />
+ android:protectionLevel="signature|preinstalled" />
<!-- @SystemApi Allows an application to manage (create, destroy,
Z-order) application tokens in the window manager.
@@ -3656,7 +3656,8 @@
<p>The package installer v2 APIs are still a work in progress and we're
currently validating they work in all scenarios.
<p>Not for use by third-party applications.
- TODO(b/152310230): remove this permission once the APIs are confirmed to be sufficient.
+ TODO(b/152310230): use this permission to protect only Incremental installations
+ once the APIs are confirmed to be sufficient.
@hide
-->
<permission android:name="com.android.permission.USE_INSTALLER_V2"
@@ -5227,7 +5228,7 @@
</activity>
<activity android:name="com.android.internal.app.SuspendedAppActivity"
- android:theme="@style/Theme.Dialog.Confirmation"
+ android:theme="@style/Theme.DeviceDefault.Dialog.Alert.DayNight"
android:excludeFromRecents="true"
android:process=":ui">
</activity>
diff --git a/packages/SystemUI/res/color/qs_user_detail_avatar_tint.xml b/core/res/res/drawable/chooser_dialog_background.xml
index 696e9b121564..b914d63187e7 100644
--- a/packages/SystemUI/res/color/qs_user_detail_avatar_tint.xml
+++ b/core/res/res/drawable/chooser_dialog_background.xml
@@ -1,7 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
-
<!--
- ~ Copyright (C) 2016 The Android Open Source Project
+ ~ 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.
@@ -13,10 +12,10 @@
~ 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
+ ~ limitations under the License.
-->
-<selector xmlns:android="http://schemas.android.com/apk/res/android">
- <item android:state_enabled="false" android:color="?android:attr/textColorPrimary" />
- <item android:color="@android:color/transparent" />
-</selector>
+<shape android:shape="rectangle" xmlns:android="http://schemas.android.com/apk/res/android">
+ <corners android:radius="?attr/dialogCornerRadius" />
+ <solid android:color="?attr/colorBackgroundFloating" />
+</shape> \ No newline at end of file
diff --git a/core/res/res/drawable/conversation_badge_background.xml b/core/res/res/drawable/conversation_badge_background.xml
index 0dd0dcda40fb..9e6405dc1040 100644
--- a/core/res/res/drawable/conversation_badge_background.xml
+++ b/core/res/res/drawable/conversation_badge_background.xml
@@ -22,7 +22,7 @@
android:color="#ffffff"/>
<size
- android:width="26dp"
- android:height="26dp"/>
+ android:width="20dp"
+ android:height="20dp"/>
</shape>
diff --git a/core/res/res/drawable/conversation_badge_ring.xml b/core/res/res/drawable/conversation_badge_ring.xml
index 11ba8ad69505..eee53d1c21b5 100644
--- a/core/res/res/drawable/conversation_badge_ring.xml
+++ b/core/res/res/drawable/conversation_badge_ring.xml
@@ -16,17 +16,18 @@
-->
<shape xmlns:android="http://schemas.android.com/apk/res/android"
- android:shape="oval">
-
- <solid
- android:color="@color/transparent"/>
+ android:shape="oval"
+>
+ <solid android:color="@color/transparent" />
<stroke
android:color="@color/conversation_important_highlight"
- android:width="2dp"/>
+ android:width="@dimen/importance_ring_stroke_width"
+ />
<size
- android:width="26dp"
- android:height="26dp"/>
+ android:width="@dimen/importance_ring_size"
+ android:height="@dimen/importance_ring_size"
+ />
</shape>
diff --git a/core/res/res/layout/chooser_dialog.xml b/core/res/res/layout/chooser_dialog.xml
new file mode 100644
index 000000000000..824136cd970a
--- /dev/null
+++ b/core/res/res/layout/chooser_dialog.xml
@@ -0,0 +1,60 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ 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.
+ -->
+
+<LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:background="@drawable/chooser_dialog_background"
+ android:orientation="vertical"
+ android:paddingBottom="8dp"
+ android:paddingTop="8dp"
+ android:layout_width="240dp"
+ android:layout_height="wrap_content">
+
+ <LinearLayout
+ android:gravity="start|center_vertical"
+ android:paddingStart="16dp"
+ android:paddingEnd="16dp"
+ android:minHeight="56dp"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content">
+
+ <ImageView android:id="@+id/icon"
+ android:layout_marginEnd="16dp"
+ android:layout_width="24dp"
+ android:layout_height="24dp"/>
+
+ <TextView android:id="@+id/title"
+ android:textSize="16sp"
+ android:textColor="?android:attr/textColorPrimary"
+ android:textAppearance="@android:style/TextAppearance.DeviceDefault.WindowTitle"
+ android:text="App name"
+ android:lines="1"
+ android:ellipsize="end"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"/>
+
+ </LinearLayout>
+
+ <com.android.internal.widget.RecyclerView
+ xmlns:app="http://schemas.android.com/apk/res-auto"
+ app:layoutManager="com.android.internal.widget.LinearLayoutManager"
+ android:id="@+id/listContainer"
+ android:overScrollMode="never"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"/>
+
+</LinearLayout> \ No newline at end of file
diff --git a/core/res/res/layout/chooser_dialog_item.xml b/core/res/res/layout/chooser_dialog_item.xml
index 1d6369793bfb..4a88bb02372e 100644
--- a/core/res/res/layout/chooser_dialog_item.xml
+++ b/core/res/res/layout/chooser_dialog_item.xml
@@ -16,27 +16,28 @@
-->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:background="?android:attr/selectableItemBackground"
+ android:clickable="true"
+ android:paddingStart="16dp"
+ android:paddingEnd="16dp"
android:orientation="horizontal"
android:gravity="start|center_vertical"
- android:paddingStart="?attr/dialogPreferredPadding"
- android:paddingEnd="?attr/dialogPreferredPadding"
- android:minHeight="48dp"
+ android:minHeight="56dp"
android:layout_width="match_parent"
- android:layout_height="match_parent">
+ android:layout_height="wrap_content">
- <!-- Icon and text aligns with aligns with alert_dialog_title_material -->
<ImageView android:id="@+id/icon"
- android:tint="?android:attr/textColorAlertDialogListItem"
- android:padding="4dp"
- android:layout_marginEnd="8dp"
- android:layout_width="32dp"
- android:layout_height="32dp"/>
+ android:alpha="0.54"
+ android:tint="?android:attr/textColorPrimary"
+ android:layout_marginEnd="16dp"
+ android:layout_width="24dp"
+ android:layout_height="24dp"/>
- <!-- Using text style from select_dialog_item_material -->
<TextView android:id="@+id/text"
- android:textAppearance="?android:attr/textAppearanceListItemSmall"
- android:textColor="?android:attr/textColorAlertDialogListItem"
- android:lines="1"
+ android:textAppearance="?android:attr/textAppearanceSmall"
+ android:textColor="?android:attr/textColorPrimary"
+ android:textSize="16sp"
+ android:maxLines="2"
android:ellipsize="end"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
diff --git a/core/res/res/layout/chooser_grid_preview_text.xml b/core/res/res/layout/chooser_grid_preview_text.xml
index 002917463ab3..1d18648b9ef7 100644
--- a/core/res/res/layout/chooser_grid_preview_text.xml
+++ b/core/res/res/layout/chooser_grid_preview_text.xml
@@ -44,6 +44,8 @@
android:ellipsize="end"
android:fontFamily="@android:string/config_headlineFontFamily"
android:textColor="?android:attr/textColorPrimary"
+ android:textAlignment="gravity"
+ android:textDirection="locale"
android:maxLines="2"
android:focusable="true"/>
@@ -90,6 +92,8 @@
android:layout_gravity="center_vertical"
android:ellipsize="end"
android:maxLines="2"
+ android:textAlignment="gravity"
+ android:textDirection="locale"
android:textAppearance="@style/TextAppearance.DeviceDefault.WindowTitle"
android:fontFamily="@android:string/config_headlineFontFamily"/>
</LinearLayout>
diff --git a/core/res/res/layout/notification_material_action_list.xml b/core/res/res/layout/notification_material_action_list.xml
index ec54091e5a20..3615b9e2f9cb 100644
--- a/core/res/res/layout/notification_material_action_list.xml
+++ b/core/res/res/layout/notification_material_action_list.xml
@@ -22,10 +22,11 @@
android:layout_gravity="bottom">
<LinearLayout
+ android:id="@+id/actions_container_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
- android:paddingEnd="12dp"
+ android:paddingEnd="@dimen/bubble_gone_padding_end"
>
<com.android.internal.widget.NotificationActionListLayout
diff --git a/core/res/res/layout/notification_template_material_conversation.xml b/core/res/res/layout/notification_template_material_conversation.xml
index 9a9d8b96c677..139185f98b69 100644
--- a/core/res/res/layout/notification_template_material_conversation.xml
+++ b/core/res/res/layout/notification_template_material_conversation.xml
@@ -38,6 +38,8 @@
<FrameLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
+ android:clipChildren="false"
+ android:clipToPadding="false"
android:layout_gravity="top|center_horizontal"
>
@@ -63,13 +65,17 @@
android:layout_height="@dimen/conversation_icon_size_badged"
android:layout_marginLeft="@dimen/conversation_badge_side_margin"
android:layout_marginTop="@dimen/conversation_badge_side_margin"
+ android:clipChildren="false"
+ android:clipToPadding="false"
>
<com.android.internal.widget.CachingIconView
android:id="@+id/conversation_icon_badge_bg"
android:layout_width="match_parent"
android:layout_height="match_parent"
+ android:layout_gravity="center"
android:src="@drawable/conversation_badge_background"
android:forceHasOverlappingRendering="false"
+ android:scaleType="center"
/>
<com.android.internal.widget.CachingIconView
android:id="@+id/icon"
@@ -81,11 +87,14 @@
/>
<com.android.internal.widget.CachingIconView
android:id="@+id/conversation_icon_badge_ring"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center"
android:src="@drawable/conversation_badge_ring"
android:visibility="gone"
android:forceHasOverlappingRendering="false"
+ android:clipToPadding="false"
+ android:scaleType="center"
/>
</FrameLayout>
</FrameLayout>
@@ -132,21 +141,20 @@
android:id="@+id/conversation_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:layout_marginEnd="@dimen/notification_header_separating_margin"
+ android:layout_marginEnd="@dimen/notification_conversation_header_separating_margin"
android:textAppearance="@style/TextAppearance.DeviceDefault.Notification.Title"
android:textSize="16sp"
android:singleLine="true"
android:layout_weight="1"
/>
-
<TextView
android:id="@+id/app_name_divider"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="?attr/notificationHeaderTextAppearance"
- android:layout_marginStart="@dimen/notification_header_separating_margin"
- android:layout_marginEnd="@dimen/notification_header_separating_margin"
+ android:layout_marginStart="@dimen/notification_conversation_header_separating_margin"
+ android:layout_marginEnd="@dimen/notification_conversation_header_separating_margin"
android:text="@string/notification_header_divider_symbol"
android:layout_gravity="center"
android:paddingTop="1sp"
@@ -161,9 +169,11 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
- android:layout_marginStart="@dimen/notification_header_separating_margin"
+ android:layout_marginStart="@dimen/notification_conversation_header_separating_margin"
+ android:layout_marginEnd="@dimen/notification_conversation_header_separating_margin"
android:paddingTop="1sp"
android:singleLine="true"
+ android:visibility="gone"
/>
<TextView
@@ -171,8 +181,8 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="?attr/notificationHeaderTextAppearance"
- android:layout_marginStart="@dimen/notification_header_separating_margin"
- android:layout_marginEnd="@dimen/notification_header_separating_margin"
+ android:layout_marginStart="@dimen/notification_conversation_header_separating_margin"
+ android:layout_marginEnd="@dimen/notification_conversation_header_separating_margin"
android:text="@string/notification_header_divider_symbol"
android:layout_gravity="center"
android:paddingTop="1sp"
@@ -182,11 +192,11 @@
<DateTimeView
android:id="@+id/time"
- android:textAppearance="@style/TextAppearance.Material.Notification.Time"
+ android:textAppearance="@style/TextAppearance.DeviceDefault.Notification.Time"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
- android:layout_marginStart="@dimen/notification_header_separating_margin"
+ android:layout_marginStart="@dimen/notification_conversation_header_separating_margin"
android:paddingTop="1sp"
android:showRelative="true"
android:singleLine="true"
diff --git a/core/res/res/values-af/strings.xml b/core/res/res/values-af/strings.xml
index 6ea49596325d..8a68217d966a 100644
--- a/core/res/res/values-af/strings.xml
+++ b/core/res/res/values-af/strings.xml
@@ -202,10 +202,8 @@
<string name="printing_disabled_by" msgid="3517499806528864633">"Druk is gedeaktiveer deur <xliff:g id="OWNER_APP">%s</xliff:g>."</string>
<string name="personal_apps_suspension_title" msgid="7561416677884286600">"Skakel jou werkprofiel aan"</string>
<string name="personal_apps_suspension_text" msgid="6115455688932935597">"Jou persoonlike programme word geblokkeer totdat jy jou werkprofiel aanskakel"</string>
- <!-- no translation found for personal_apps_suspension_soon_text (8123898693479590) -->
- <skip />
- <!-- no translation found for personal_apps_suspended_turn_profile_on (2758012869627513689) -->
- <skip />
+ <string name="personal_apps_suspension_soon_text" msgid="8123898693479590">"Persoonlike programme sal op <xliff:g id="DATE">%1$s</xliff:g> om <xliff:g id="TIME">%2$s</xliff:g> geblokkeer word. Jou IT-admin laat nie toe dat jou werkprofiel langer as <xliff:g id="NUMBER">%3$d</xliff:g> dae af bly nie."</string>
+ <string name="personal_apps_suspended_turn_profile_on" msgid="2758012869627513689">"Skakel aan"</string>
<string name="me" msgid="6207584824693813140">"Ek"</string>
<string name="power_dialog" product="tablet" msgid="8333207765671417261">"Tablet-opsies"</string>
<string name="power_dialog" product="tv" msgid="7792839006640933763">"Android TV-opsies"</string>
diff --git a/core/res/res/values-am/strings.xml b/core/res/res/values-am/strings.xml
index 8291ad70c8bd..a05cfbfc99fd 100644
--- a/core/res/res/values-am/strings.xml
+++ b/core/res/res/values-am/strings.xml
@@ -202,10 +202,8 @@
<string name="printing_disabled_by" msgid="3517499806528864633">"ማተም በ<xliff:g id="OWNER_APP">%s</xliff:g> ተሰናክሏል።"</string>
<string name="personal_apps_suspension_title" msgid="7561416677884286600">"የስራ መገለጫዎን ያብሩት"</string>
<string name="personal_apps_suspension_text" msgid="6115455688932935597">"የስራ መገለጫዎን እስኪያበሩት ድረስ የግል መተግበሪያዎችዎ ታግደዋል"</string>
- <!-- no translation found for personal_apps_suspension_soon_text (8123898693479590) -->
- <skip />
- <!-- no translation found for personal_apps_suspended_turn_profile_on (2758012869627513689) -->
- <skip />
+ <string name="personal_apps_suspension_soon_text" msgid="8123898693479590">"የግል መተግበሪያዎች <xliff:g id="DATE">%1$s</xliff:g> <xliff:g id="TIME">%2$s</xliff:g> ላይ ይታገዳሉ። የእርስዎ የአይቲ አስተዳዳሪ የሥራ መገለጫዎ ከ<xliff:g id="NUMBER">%3$d</xliff:g> ቀኖች በላይ ጠፍቶ እንዲቆይ አይፈቅዱም።"</string>
+ <string name="personal_apps_suspended_turn_profile_on" msgid="2758012869627513689">"አብራ"</string>
<string name="me" msgid="6207584824693813140">"እኔ"</string>
<string name="power_dialog" product="tablet" msgid="8333207765671417261">"የጡባዊ አማራጮች"</string>
<string name="power_dialog" product="tv" msgid="7792839006640933763">"Android TV አማራጮች"</string>
diff --git a/core/res/res/values-ar/strings.xml b/core/res/res/values-ar/strings.xml
index cae96722a907..02a0eb476505 100644
--- a/core/res/res/values-ar/strings.xml
+++ b/core/res/res/values-ar/strings.xml
@@ -210,10 +210,8 @@
<string name="printing_disabled_by" msgid="3517499806528864633">"تم إيقاف الطباعة بواسطة <xliff:g id="OWNER_APP">%s</xliff:g>."</string>
<string name="personal_apps_suspension_title" msgid="7561416677884286600">"تفعيل الملف الشخصي للعمل"</string>
<string name="personal_apps_suspension_text" msgid="6115455688932935597">"تم حظر تطبيقاتك الشخصية إلى أن تفعِّل ملفك الشخصي للعمل."</string>
- <!-- no translation found for personal_apps_suspension_soon_text (8123898693479590) -->
- <skip />
- <!-- no translation found for personal_apps_suspended_turn_profile_on (2758012869627513689) -->
- <skip />
+ <string name="personal_apps_suspension_soon_text" msgid="8123898693479590">"سيتم حظر التطبيقات الشخصية في <xliff:g id="DATE">%1$s</xliff:g> في <xliff:g id="TIME">%2$s</xliff:g>. لا يسمح مشرف تكنولوجيا المعلومات في مؤسستك بإيقاف الملف الشخصي للعمل أكثر من <xliff:g id="NUMBER">%3$d</xliff:g> يوم."</string>
+ <string name="personal_apps_suspended_turn_profile_on" msgid="2758012869627513689">"تفعيل"</string>
<string name="me" msgid="6207584824693813140">"أنا"</string>
<string name="power_dialog" product="tablet" msgid="8333207765671417261">"خيارات الجهاز اللوحي"</string>
<string name="power_dialog" product="tv" msgid="7792839006640933763">"‏خيارات Android TV"</string>
@@ -2190,7 +2188,7 @@
<string name="conversation_title_fallback_group_chat" msgid="456073374993104303">"محادثة جماعية"</string>
<string name="unread_convo_overflow" msgid="920517615597353833">"<xliff:g id="MAX_UNREAD_COUNT">%1$d</xliff:g>+"</string>
<string name="resolver_personal_tab" msgid="2051260504014442073">"شخصي"</string>
- <string name="resolver_work_tab" msgid="2690019516263167035">"عمل"</string>
+ <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_cant_share_with_work_apps" msgid="637686613606502219">"تتعذّر مشاركة هذا المحتوى باستخدام تطبيقات العمل"</string>
@@ -2201,9 +2199,9 @@
<string name="resolver_cant_share_with_personal_apps_explanation" msgid="2959282422751315171">"لا يسمح لك مشرف تكنولوجيا المعلومات بمشاركة هذا المحتوى باستخدام التطبيقات في ملفك الشخصي."</string>
<string name="resolver_cant_access_personal_apps" msgid="648291604475669395">"يتعذّر فتح هذا المحتوى باستخدام التطبيقات الشخصية"</string>
<string name="resolver_cant_access_personal_apps_explanation" msgid="2298773629302296519">"لا يسمح لك مشرف تكنولوجيا المعلومات بفتح هذا المحتوى باستخدام التطبيقات في ملفك الشخصي."</string>
- <string name="resolver_turn_on_work_apps" msgid="884910835250037247">"تم إيقاف الملف الشخصي للعمل مؤقتًا."</string>
+ <string name="resolver_turn_on_work_apps" msgid="884910835250037247">"الملف الشخصي للعمل متوقف مؤقتًا."</string>
<string name="resolver_switch_on_work" msgid="2873009160846966379">"تفعيل"</string>
- <string name="resolver_no_work_apps_available_share" msgid="7933949011797699505">"لا يمكن لتطبيقات العمل أن تدعم هذا المحتوى."</string>
+ <string name="resolver_no_work_apps_available_share" msgid="7933949011797699505">"لا يمكن لتطبيقات العمل أن تتوافق مع هذا المحتوى."</string>
<string name="resolver_no_work_apps_available_resolve" msgid="1244844292366099399">"لا يمكن لتطبيقات العمل أن تفتح هذا المحتوى."</string>
<string name="resolver_no_personal_apps_available_share" msgid="5639102815174748732">"لا يمكن للتطبيقات الشخصية أن تدعم هذا المحتوى."</string>
<string name="resolver_no_personal_apps_available_resolve" msgid="5120671970531446978">"لا يمكن للتطبيقات الشخصية أن تفتح هذا المحتوى."</string>
diff --git a/core/res/res/values-as/strings.xml b/core/res/res/values-as/strings.xml
index 43feb19fcfdc..5ac3aaeb9c6c 100644
--- a/core/res/res/values-as/strings.xml
+++ b/core/res/res/values-as/strings.xml
@@ -202,10 +202,8 @@
<string name="printing_disabled_by" msgid="3517499806528864633">"প্ৰিণ্ট কৰা কাৰ্য <xliff:g id="OWNER_APP">%s</xliff:g>এ অক্ষম কৰি ৰাখিছে।"</string>
<string name="personal_apps_suspension_title" msgid="7561416677884286600">"কৰ্মস্থানৰ প্ৰ’ফাইলটো অন কৰক"</string>
<string name="personal_apps_suspension_text" msgid="6115455688932935597">"আপুনি নিজৰ কৰ্মস্থানৰ প্ৰ’ফাইলটো অন নকৰালৈকে আপোনাৰ ব্যক্তিগত এপ্‌সমূহ অৱৰোধ কৰা থাকে"</string>
- <!-- no translation found for personal_apps_suspension_soon_text (8123898693479590) -->
- <skip />
- <!-- no translation found for personal_apps_suspended_turn_profile_on (2758012869627513689) -->
- <skip />
+ <string name="personal_apps_suspension_soon_text" msgid="8123898693479590">"<xliff:g id="DATE">%1$s</xliff:g> তাৰিখে <xliff:g id="TIME">%2$s</xliff:g> বজাত ব্যক্তিগত এপ্‌সমূহ অৱৰোধ কৰা হ’ব। আপোনাৰ আইটি প্ৰশাসকে আপোনাৰ কৰ্মস্থানৰ প্ৰ’ফাইলটো <xliff:g id="NUMBER">%3$d</xliff:g> দিনতকৈ বেছি সময়ৰ বাবে অফ কৰি ৰাখিবলৈ অনুমতি নিদিয়ে।"</string>
+ <string name="personal_apps_suspended_turn_profile_on" msgid="2758012869627513689">"অন কৰক"</string>
<string name="me" msgid="6207584824693813140">"মই"</string>
<string name="power_dialog" product="tablet" msgid="8333207765671417261">"টে\'বলেটৰ বিকল্পসমূহ"</string>
<string name="power_dialog" product="tv" msgid="7792839006640933763">"Android TVৰ বিকল্পসমূহ"</string>
diff --git a/core/res/res/values-az/strings.xml b/core/res/res/values-az/strings.xml
index d8d0c2d29d12..106f7040c1a4 100644
--- a/core/res/res/values-az/strings.xml
+++ b/core/res/res/values-az/strings.xml
@@ -202,10 +202,8 @@
<string name="printing_disabled_by" msgid="3517499806528864633">"Çap <xliff:g id="OWNER_APP">%s</xliff:g> tərəfindən deaktiv edildi."</string>
<string name="personal_apps_suspension_title" msgid="7561416677884286600">"İş profilinizi aktiv edin"</string>
<string name="personal_apps_suspension_text" msgid="6115455688932935597">"İş profilinizi aktiv edənədək şəxsi tətbiqləriniz bloklanır"</string>
- <!-- no translation found for personal_apps_suspension_soon_text (8123898693479590) -->
- <skip />
- <!-- no translation found for personal_apps_suspended_turn_profile_on (2758012869627513689) -->
- <skip />
+ <string name="personal_apps_suspension_soon_text" msgid="8123898693479590">"Şəxsi tətbiqlər bu tarixdə bloklanacaq: <xliff:g id="DATE">%1$s</xliff:g>, <xliff:g id="TIME">%2$s</xliff:g>. İT admini iş profilinizin <xliff:g id="NUMBER">%3$d</xliff:g> gündən çox deaktiv qalmasına icazə vermir."</string>
+ <string name="personal_apps_suspended_turn_profile_on" msgid="2758012869627513689">"Aktiv edin"</string>
<string name="me" msgid="6207584824693813140">"Mən"</string>
<string name="power_dialog" product="tablet" msgid="8333207765671417261">"Planşet seçimləri"</string>
<string name="power_dialog" product="tv" msgid="7792839006640933763">"Android TV seçimləri"</string>
diff --git a/core/res/res/values-b+sr+Latn/strings.xml b/core/res/res/values-b+sr+Latn/strings.xml
index 94439cbb875e..c2d501355d5f 100644
--- a/core/res/res/values-b+sr+Latn/strings.xml
+++ b/core/res/res/values-b+sr+Latn/strings.xml
@@ -204,10 +204,8 @@
<string name="printing_disabled_by" msgid="3517499806528864633">"Štampanje je onemogućila aplikacija <xliff:g id="OWNER_APP">%s</xliff:g>."</string>
<string name="personal_apps_suspension_title" msgid="7561416677884286600">"Uključite poslovni profil"</string>
<string name="personal_apps_suspension_text" msgid="6115455688932935597">"Lične aplikacije su blokirane dok ne uključite poslovni profil"</string>
- <!-- no translation found for personal_apps_suspension_soon_text (8123898693479590) -->
- <skip />
- <!-- no translation found for personal_apps_suspended_turn_profile_on (2758012869627513689) -->
- <skip />
+ <string name="personal_apps_suspension_soon_text" msgid="8123898693479590">"Lične aplikacije će biti blokirane: <xliff:g id="DATE">%1$s</xliff:g> u <xliff:g id="TIME">%2$s</xliff:g>. IT administrator ne dozvoljava da poslovni profil bude isključen duže od <xliff:g id="NUMBER">%3$d</xliff:g> dana."</string>
+ <string name="personal_apps_suspended_turn_profile_on" msgid="2758012869627513689">"Uključi"</string>
<string name="me" msgid="6207584824693813140">"Ja"</string>
<string name="power_dialog" product="tablet" msgid="8333207765671417261">"Opcije za tablet"</string>
<string name="power_dialog" product="tv" msgid="7792839006640933763">"Opcije Android TV-a"</string>
@@ -1151,7 +1149,7 @@
<string name="whichViewApplicationNamed" msgid="415164730629690105">"Otvorite pomoću aplikacije %1$s"</string>
<string name="whichViewApplicationLabel" msgid="7367556735684742409">"Otvori"</string>
<string name="whichOpenHostLinksWith" msgid="7645631470199397485">"Otvarajte <xliff:g id="HOST">%1$s</xliff:g> linkove pomoću"</string>
- <string name="whichOpenLinksWith" msgid="1120936181362907258">"Otvaratej linkove pomoću"</string>
+ <string name="whichOpenLinksWith" msgid="1120936181362907258">"Otvaraj linkove pomoću"</string>
<string name="whichOpenLinksWithApp" msgid="6917864367861910086">"Otvarajte linkove pomoću aplikacije <xliff:g id="APPLICATION">%1$s</xliff:g>"</string>
<string name="whichOpenHostLinksWithApp" msgid="2401668560768463004">"Otvarajte <xliff:g id="HOST">%1$s</xliff:g> linkove pomoću aplikacije <xliff:g id="APPLICATION">%2$s</xliff:g>"</string>
<string name="whichGiveAccessToApplicationLabel" msgid="7805857277166106236">"Dozvoli pristup"</string>
@@ -2101,7 +2099,7 @@
<string name="resolver_cant_access_personal_apps_explanation" msgid="2298773629302296519">"IT administrator vam ne dozvoljava da otvorite ovaj sadržaj pomoću aplikacija na ličnom profilu"</string>
<string name="resolver_turn_on_work_apps" msgid="884910835250037247">"Poslovni profil je pauziran"</string>
<string name="resolver_switch_on_work" msgid="2873009160846966379">"Uključi"</string>
- <string name="resolver_no_work_apps_available_share" msgid="7933949011797699505">"Nijedna aplikacija za posao ne može da podržava ovaj sadržaj"</string>
+ <string name="resolver_no_work_apps_available_share" msgid="7933949011797699505">"Nijedna aplikacija za posao ne podržava ovaj sadržaj"</string>
<string name="resolver_no_work_apps_available_resolve" msgid="1244844292366099399">"Nijedna aplikacija za posao ne može da otvori ovaj sadržaj"</string>
<string name="resolver_no_personal_apps_available_share" msgid="5639102815174748732">"Nijedna lična aplikacija ne može da podržava ovaj sadržaj"</string>
<string name="resolver_no_personal_apps_available_resolve" msgid="5120671970531446978">"Nijedna lična aplikacija ne može da otvori ovaj sadržaj"</string>
diff --git a/core/res/res/values-be/strings.xml b/core/res/res/values-be/strings.xml
index 158602318221..2bdd4f7ad230 100644
--- a/core/res/res/values-be/strings.xml
+++ b/core/res/res/values-be/strings.xml
@@ -206,10 +206,8 @@
<string name="printing_disabled_by" msgid="3517499806528864633">"Друк адключаны ўладальнікам праграмы <xliff:g id="OWNER_APP">%s</xliff:g>."</string>
<string name="personal_apps_suspension_title" msgid="7561416677884286600">"Уключыце працоўны профіль"</string>
<string name="personal_apps_suspension_text" msgid="6115455688932935597">"Вашы асабістыя праграмы будуць заблакіраваны, пакуль вы не ўключыце працоўны профіль"</string>
- <!-- no translation found for personal_apps_suspension_soon_text (8123898693479590) -->
- <skip />
- <!-- no translation found for personal_apps_suspended_turn_profile_on (2758012869627513689) -->
- <skip />
+ <string name="personal_apps_suspension_soon_text" msgid="8123898693479590">"Асабістыя праграмы будуць заблакіраваны ў <xliff:g id="TIME">%2$s</xliff:g> <xliff:g id="DATE">%1$s</xliff:g>. Ваш ІТ-адміністратар не дазволіў выключаць працоўны профіль больш чым на <xliff:g id="NUMBER">%3$d</xliff:g> сут."</string>
+ <string name="personal_apps_suspended_turn_profile_on" msgid="2758012869627513689">"Уключыць"</string>
<string name="me" msgid="6207584824693813140">"Я"</string>
<string name="power_dialog" product="tablet" msgid="8333207765671417261">"Параметры планшэта"</string>
<string name="power_dialog" product="tv" msgid="7792839006640933763">"Параметры Android TV"</string>
diff --git a/core/res/res/values-bg/strings.xml b/core/res/res/values-bg/strings.xml
index a337d01b805f..a574fec312b6 100644
--- a/core/res/res/values-bg/strings.xml
+++ b/core/res/res/values-bg/strings.xml
@@ -202,10 +202,8 @@
<string name="printing_disabled_by" msgid="3517499806528864633">"Отпечатването е деактивиранo от <xliff:g id="OWNER_APP">%s</xliff:g>."</string>
<string name="personal_apps_suspension_title" msgid="7561416677884286600">"Служ. потр. профил: Включване"</string>
<string name="personal_apps_suspension_text" msgid="6115455688932935597">"Личните ви приложения са блокирани, докато не включите служебния си потребителски профил"</string>
- <!-- no translation found for personal_apps_suspension_soon_text (8123898693479590) -->
- <skip />
- <!-- no translation found for personal_apps_suspended_turn_profile_on (2758012869627513689) -->
- <skip />
+ <string name="personal_apps_suspension_soon_text" msgid="8123898693479590">"Личните приложения ще бъдат блокирани на <xliff:g id="DATE">%1$s</xliff:g> в <xliff:g id="TIME">%2$s</xliff:g>. Системният ви администратор не разрешава служебният ви потребителски профил да бъде изключен за повече от <xliff:g id="NUMBER">%3$d</xliff:g> дни."</string>
+ <string name="personal_apps_suspended_turn_profile_on" msgid="2758012869627513689">"Включване"</string>
<string name="me" msgid="6207584824693813140">"Аз"</string>
<string name="power_dialog" product="tablet" msgid="8333207765671417261">"Опции за таблета"</string>
<string name="power_dialog" product="tv" msgid="7792839006640933763">"Опции за Android TV"</string>
diff --git a/core/res/res/values-bn/strings.xml b/core/res/res/values-bn/strings.xml
index 18992c9e5d1e..98c778cbd759 100644
--- a/core/res/res/values-bn/strings.xml
+++ b/core/res/res/values-bn/strings.xml
@@ -202,10 +202,8 @@
<string name="printing_disabled_by" msgid="3517499806528864633">"<xliff:g id="OWNER_APP">%s</xliff:g> প্রিন্টিং বন্ধ রেখেছে।"</string>
<string name="personal_apps_suspension_title" msgid="7561416677884286600">"অফিসের প্রোফাইল চালু করুন"</string>
<string name="personal_apps_suspension_text" msgid="6115455688932935597">"আপনার অফিসের প্রোফাইল চালু না করা পর্যন্ত আপনার ব্যক্তিগত অ্যাপ ব্লক থাকে"</string>
- <!-- no translation found for personal_apps_suspension_soon_text (8123898693479590) -->
- <skip />
- <!-- no translation found for personal_apps_suspended_turn_profile_on (2758012869627513689) -->
- <skip />
+ <string name="personal_apps_suspension_soon_text" msgid="8123898693479590">"ব্যক্তিগত অ্যাপ <xliff:g id="DATE">%1$s</xliff:g>-এ <xliff:g id="TIME">%2$s</xliff:g>টার সময় ব্লক করা হবে। আপনার আইটি অ্যাডমিন আপনার অফিস প্রোফাইল <xliff:g id="NUMBER">%3$d</xliff:g> দিনের বেশি পজ করে রাখার অনুমতি দেয় না।"</string>
+ <string name="personal_apps_suspended_turn_profile_on" msgid="2758012869627513689">"চালু করুন"</string>
<string name="me" msgid="6207584824693813140">"আমাকে"</string>
<string name="power_dialog" product="tablet" msgid="8333207765671417261">"ট্যাবলেট বিকল্পগুলি"</string>
<string name="power_dialog" product="tv" msgid="7792839006640933763">"Android TV-র বিকল্প"</string>
@@ -2065,9 +2063,9 @@
<string name="resolver_cant_share_with_personal_apps_explanation" msgid="2959282422751315171">"আইটি অ্যাডমিন আপনার ব্যক্তিগত প্রোফাইল ব্যবহার করে অ্যাপের মাধ্যমে এই কন্টেন্ট শেয়ার করার অনুমতি দেয় না"</string>
<string name="resolver_cant_access_personal_apps" msgid="648291604475669395">"ব্যক্তিগত অ্যাপের মাধ্যমে খোলা যাবে না"</string>
<string name="resolver_cant_access_personal_apps_explanation" msgid="2298773629302296519">"আইটি অ্যাডমিন আপনার ব্যক্তিগত প্রোফাইল ব্যবহার করে অ্যাপের মাধ্যমে এই কন্টেন্ট খোলার অনুমতি দেয় না"</string>
- <string name="resolver_turn_on_work_apps" msgid="884910835250037247">"কাজের প্রোফাইল পজ করা আছে"</string>
+ <string name="resolver_turn_on_work_apps" msgid="884910835250037247">"অফিস প্রোফাইল বন্ধ করা আছে"</string>
<string name="resolver_switch_on_work" msgid="2873009160846966379">"চালু করুন"</string>
- <string name="resolver_no_work_apps_available_share" msgid="7933949011797699505">"এই ধরনের কন্টেন্ট অফিসের অ্যাপের মাধ্যমে খুলে দেখা যাবে না"</string>
+ <string name="resolver_no_work_apps_available_share" msgid="7933949011797699505">"এই ধরনের কন্টেন্ট অফিস অ্যাপের মাধ্যমে খোলা যাবে না"</string>
<string name="resolver_no_work_apps_available_resolve" msgid="1244844292366099399">"এই ধরনের কন্টেন্ট অফিসের অ্যাপের মাধ্যমে খুলে দেখা যাবে না"</string>
<string name="resolver_no_personal_apps_available_share" msgid="5639102815174748732">"এই ধরনের কন্টেন্ট ব্যক্তিগত অ্যাপের মাধ্যমে খোলা বা দেখা যাবে না"</string>
<string name="resolver_no_personal_apps_available_resolve" msgid="5120671970531446978">"এই ধরনের কন্টেন্ট ব্যক্তিগত অ্যাপের মাধ্যমে খোলা যাবে না"</string>
diff --git a/core/res/res/values-bs/strings.xml b/core/res/res/values-bs/strings.xml
index 7e8fe5342d36..8c0459103696 100644
--- a/core/res/res/values-bs/strings.xml
+++ b/core/res/res/values-bs/strings.xml
@@ -204,10 +204,8 @@
<string name="printing_disabled_by" msgid="3517499806528864633">"Štampanje je onemogućila aplikacija <xliff:g id="OWNER_APP">%s</xliff:g>."</string>
<string name="personal_apps_suspension_title" msgid="7561416677884286600">"Uključite radni profil"</string>
<string name="personal_apps_suspension_text" msgid="6115455688932935597">"Vaše lične aplikacije će biti blokirane dok ne uključite radni profil"</string>
- <!-- no translation found for personal_apps_suspension_soon_text (8123898693479590) -->
- <skip />
- <!-- no translation found for personal_apps_suspended_turn_profile_on (2758012869627513689) -->
- <skip />
+ <string name="personal_apps_suspension_soon_text" msgid="8123898693479590">"Lične aplikacije će biti blokirane <xliff:g id="DATE">%1$s</xliff:g> u <xliff:g id="TIME">%2$s</xliff:g>. Vaš IT administrator ne dozvoljava da radni profil bude isključen duže od <xliff:g id="NUMBER">%3$d</xliff:g> dana."</string>
+ <string name="personal_apps_suspended_turn_profile_on" msgid="2758012869627513689">"Uključi"</string>
<string name="me" msgid="6207584824693813140">"Ja"</string>
<string name="power_dialog" product="tablet" msgid="8333207765671417261">"Opcije tableta"</string>
<string name="power_dialog" product="tv" msgid="7792839006640933763">"Opcije Android TV uređaja"</string>
@@ -216,7 +214,7 @@
<string name="turn_on_radio" msgid="2961717788170634233">"Uključi bežičnu vezu"</string>
<string name="turn_off_radio" msgid="7222573978109933360">"Isključi bežičnu vezu"</string>
<string name="screen_lock" msgid="2072642720826409809">"Zaključavanje ekrana"</string>
- <string name="power_off" msgid="4111692782492232778">"Isključi telefon"</string>
+ <string name="power_off" msgid="4111692782492232778">"Isključi"</string>
<string name="silent_mode_silent" msgid="5079789070221150912">"Zvuk zvona isključen"</string>
<string name="silent_mode_vibrate" msgid="8821830448369552678">"Zvuk zvona na vibraciji"</string>
<string name="silent_mode_ring" msgid="6039011004781526678">"Zvuk zvona uključen"</string>
@@ -240,7 +238,7 @@
<string name="global_actions" product="tv" msgid="3871763739487450369">"Opcije Android TV uređaja"</string>
<string name="global_actions" product="default" msgid="6410072189971495460">"Opcije telefona"</string>
<string name="global_action_lock" msgid="6949357274257655383">"Zaključavanje ekrana"</string>
- <string name="global_action_power_off" msgid="4404936470711393203">"Isključi telefon"</string>
+ <string name="global_action_power_off" msgid="4404936470711393203">"Isključi"</string>
<string name="global_action_power_options" msgid="1185286119330160073">"Napajanje"</string>
<string name="global_action_restart" msgid="4678451019561687074">"Ponovo pokreni"</string>
<string name="global_action_emergency" msgid="1387617624177105088">"Hitno"</string>
@@ -1150,10 +1148,10 @@
<string name="whichViewApplication" msgid="5733194231473132945">"Otvori koristeći"</string>
<string name="whichViewApplicationNamed" msgid="415164730629690105">"Otvori koristeći %1$s"</string>
<string name="whichViewApplicationLabel" msgid="7367556735684742409">"Otvori"</string>
- <string name="whichOpenHostLinksWith" msgid="7645631470199397485">"Otvaranje <xliff:g id="HOST">%1$s</xliff:g> linkova pomoću"</string>
- <string name="whichOpenLinksWith" msgid="1120936181362907258">"Otvaranje linkova pomoću"</string>
- <string name="whichOpenLinksWithApp" msgid="6917864367861910086">"Otvaranje linkova pomoću aplikacije <xliff:g id="APPLICATION">%1$s</xliff:g>"</string>
- <string name="whichOpenHostLinksWithApp" msgid="2401668560768463004">"Otvaranje <xliff:g id="HOST">%1$s</xliff:g> linkova pomoću aplikacije <xliff:g id="APPLICATION">%2$s</xliff:g>"</string>
+ <string name="whichOpenHostLinksWith" msgid="7645631470199397485">"Otvaranje <xliff:g id="HOST">%1$s</xliff:g> linkova pomoću preglednika/aplikacije"</string>
+ <string name="whichOpenLinksWith" msgid="1120936181362907258">"Otvaranje linkova pomoću preglednika"</string>
+ <string name="whichOpenLinksWithApp" msgid="6917864367861910086">"Otvaranje linkova pomoću preglednika <xliff:g id="APPLICATION">%1$s</xliff:g>"</string>
+ <string name="whichOpenHostLinksWithApp" msgid="2401668560768463004">"Otvaranje <xliff:g id="HOST">%1$s</xliff:g> linkova pomoću preglednika <xliff:g id="APPLICATION">%2$s</xliff:g>"</string>
<string name="whichGiveAccessToApplicationLabel" msgid="7805857277166106236">"Dozvoli pristup"</string>
<string name="whichEditApplication" msgid="6191568491456092812">"Uredi koristeći"</string>
<string name="whichEditApplicationNamed" msgid="8096494987978521514">"Uredi koristeći %1$s"</string>
diff --git a/core/res/res/values-ca/strings.xml b/core/res/res/values-ca/strings.xml
index d048a7f8d4a5..fc9471f5d449 100644
--- a/core/res/res/values-ca/strings.xml
+++ b/core/res/res/values-ca/strings.xml
@@ -202,10 +202,8 @@
<string name="printing_disabled_by" msgid="3517499806528864633">"<xliff:g id="OWNER_APP">%s</xliff:g> ha desactivat la impressió."</string>
<string name="personal_apps_suspension_title" msgid="7561416677884286600">"Activa el perfil de treball"</string>
<string name="personal_apps_suspension_text" msgid="6115455688932935597">"Les teves aplicacions personals estan bloquejades fins que activis el perfil de treball"</string>
- <!-- no translation found for personal_apps_suspension_soon_text (8123898693479590) -->
- <skip />
- <!-- no translation found for personal_apps_suspended_turn_profile_on (2758012869627513689) -->
- <skip />
+ <string name="personal_apps_suspension_soon_text" msgid="8123898693479590">"Les aplicacions personals es bloquejaran el dia <xliff:g id="DATE">%1$s</xliff:g> a les <xliff:g id="TIME">%2$s</xliff:g>. L\'administrador de TI no permet desactivar el teu perfil de treball durant més de: <xliff:g id="NUMBER">%3$d</xliff:g> dies."</string>
+ <string name="personal_apps_suspended_turn_profile_on" msgid="2758012869627513689">"Activa"</string>
<string name="me" msgid="6207584824693813140">"Mi"</string>
<string name="power_dialog" product="tablet" msgid="8333207765671417261">"Opcions de la tauleta"</string>
<string name="power_dialog" product="tv" msgid="7792839006640933763">"Opcions d\'Android TV"</string>
diff --git a/core/res/res/values-cs/strings.xml b/core/res/res/values-cs/strings.xml
index a0c5ff0ae8c6..90ee8f25d2bf 100644
--- a/core/res/res/values-cs/strings.xml
+++ b/core/res/res/values-cs/strings.xml
@@ -206,10 +206,8 @@
<string name="printing_disabled_by" msgid="3517499806528864633">"Aplikace <xliff:g id="OWNER_APP">%s</xliff:g> tisk zakazuje."</string>
<string name="personal_apps_suspension_title" msgid="7561416677884286600">"Zapněte pracovní profil"</string>
<string name="personal_apps_suspension_text" msgid="6115455688932935597">"Vaše osobní aplikace jsou zablokovány, dokud nezapnete pracovní profil"</string>
- <!-- no translation found for personal_apps_suspension_soon_text (8123898693479590) -->
- <skip />
- <!-- no translation found for personal_apps_suspended_turn_profile_on (2758012869627513689) -->
- <skip />
+ <string name="personal_apps_suspension_soon_text" msgid="8123898693479590">"Osobní aplikace budou zablokovány <xliff:g id="DATE">%1$s</xliff:g> v <xliff:g id="TIME">%2$s</xliff:g>. Administrátor IT nepovoluje vypnutí pracovního profilu na déle než tento počet dní: <xliff:g id="NUMBER">%3$d</xliff:g>."</string>
+ <string name="personal_apps_suspended_turn_profile_on" msgid="2758012869627513689">"Zapnout"</string>
<string name="me" msgid="6207584824693813140">"Já"</string>
<string name="power_dialog" product="tablet" msgid="8333207765671417261">"Možnosti tabletu"</string>
<string name="power_dialog" product="tv" msgid="7792839006640933763">"Možnosti zařízení Android TV"</string>
diff --git a/core/res/res/values-da/strings.xml b/core/res/res/values-da/strings.xml
index d240f30d6b28..16cae27eb2fa 100644
--- a/core/res/res/values-da/strings.xml
+++ b/core/res/res/values-da/strings.xml
@@ -202,10 +202,8 @@
<string name="printing_disabled_by" msgid="3517499806528864633">"Udskrivning er deaktiveret af <xliff:g id="OWNER_APP">%s</xliff:g>."</string>
<string name="personal_apps_suspension_title" msgid="7561416677884286600">"Aktivér din arbejdsprofil"</string>
<string name="personal_apps_suspension_text" msgid="6115455688932935597">"Dine personlige apps er blokeret, indtil du aktiverer din arbejdsprofil"</string>
- <!-- no translation found for personal_apps_suspension_soon_text (8123898693479590) -->
- <skip />
- <!-- no translation found for personal_apps_suspended_turn_profile_on (2758012869627513689) -->
- <skip />
+ <string name="personal_apps_suspension_soon_text" msgid="8123898693479590">"Personlige apps bliver blokeret <xliff:g id="DATE">%1$s</xliff:g> kl. <xliff:g id="TIME">%2$s</xliff:g>. Din it-administrator tillader ikke, at din arbejdsprofil deaktiveres i mere end <xliff:g id="NUMBER">%3$d</xliff:g> dage."</string>
+ <string name="personal_apps_suspended_turn_profile_on" msgid="2758012869627513689">"Aktivér"</string>
<string name="me" msgid="6207584824693813140">"Mig"</string>
<string name="power_dialog" product="tablet" msgid="8333207765671417261">"Valgmuligheder for tabletcomputeren"</string>
<string name="power_dialog" product="tv" msgid="7792839006640933763">"Valgmuligheder for Android TV"</string>
diff --git a/core/res/res/values-de/strings.xml b/core/res/res/values-de/strings.xml
index 0e425afd207a..2763acad2672 100644
--- a/core/res/res/values-de/strings.xml
+++ b/core/res/res/values-de/strings.xml
@@ -202,10 +202,8 @@
<string name="printing_disabled_by" msgid="3517499806528864633">"Drucken wurde von <xliff:g id="OWNER_APP">%s</xliff:g> deaktiviert."</string>
<string name="personal_apps_suspension_title" msgid="7561416677884286600">"Arbeitsprofil aktivieren"</string>
<string name="personal_apps_suspension_text" msgid="6115455688932935597">"Deine privaten Apps werden blockiert, bis du dein Arbeitsprofil aktivierst"</string>
- <!-- no translation found for personal_apps_suspension_soon_text (8123898693479590) -->
- <skip />
- <!-- no translation found for personal_apps_suspended_turn_profile_on (2758012869627513689) -->
- <skip />
+ <string name="personal_apps_suspension_soon_text" msgid="8123898693479590">"Private Apps werden am <xliff:g id="DATE">%1$s</xliff:g> um <xliff:g id="TIME">%2$s</xliff:g> blockiert. Dein IT-Administrator hat festgelegt, dass dein Arbeitsprofil nicht länger als <xliff:g id="NUMBER">%3$d</xliff:g> Tage pausiert werden darf."</string>
+ <string name="personal_apps_suspended_turn_profile_on" msgid="2758012869627513689">"Aktivieren"</string>
<string name="me" msgid="6207584824693813140">"Eigene"</string>
<string name="power_dialog" product="tablet" msgid="8333207765671417261">"Tablet-Optionen"</string>
<string name="power_dialog" product="tv" msgid="7792839006640933763">"Android TV-Optionen"</string>
diff --git a/core/res/res/values-el/strings.xml b/core/res/res/values-el/strings.xml
index 65872f43f46e..dd19b2769f72 100644
--- a/core/res/res/values-el/strings.xml
+++ b/core/res/res/values-el/strings.xml
@@ -202,10 +202,8 @@
<string name="printing_disabled_by" msgid="3517499806528864633">"Η εκτύπωση απενεργοποιήθηκε από τον χρήστη <xliff:g id="OWNER_APP">%s</xliff:g>."</string>
<string name="personal_apps_suspension_title" msgid="7561416677884286600">"Ενεργοπ. το προφίλ εργασίας"</string>
<string name="personal_apps_suspension_text" msgid="6115455688932935597">"Οι προσωπικές σας εφαρμογές αποκλείονται μέχρι να ενεργοποιήσετε το προφίλ εργασίας σας."</string>
- <!-- no translation found for personal_apps_suspension_soon_text (8123898693479590) -->
- <skip />
- <!-- no translation found for personal_apps_suspended_turn_profile_on (2758012869627513689) -->
- <skip />
+ <string name="personal_apps_suspension_soon_text" msgid="8123898693479590">"Οι προσωπικές εφαρμογές θα αποκλειστούν στις <xliff:g id="DATE">%1$s</xliff:g> και ώρα <xliff:g id="TIME">%2$s</xliff:g>. Ο διαχειριστής IT δεν επιτρέπει το προφίλ εργασίας να παραμένει απενεργοποιημένο για περισσότερες από <xliff:g id="NUMBER">%3$d</xliff:g> ημέρες."</string>
+ <string name="personal_apps_suspended_turn_profile_on" msgid="2758012869627513689">"Ενεργοποίηση"</string>
<string name="me" msgid="6207584824693813140">"Για εμένα"</string>
<string name="power_dialog" product="tablet" msgid="8333207765671417261">"Επιλογές tablet"</string>
<string name="power_dialog" product="tv" msgid="7792839006640933763">"Επιλογές Android TV"</string>
@@ -1309,7 +1307,7 @@
<string name="usb_unsupported_audio_accessory_title" msgid="2335775548086533065">"Εντοπίστηκε αναλογικό αξεσουάρ ήχου"</string>
<string name="usb_unsupported_audio_accessory_message" msgid="1300168007129796621">"Η συνδεδεμένη συσκευή δεν είναι συμβατή με αυτό το τηλέφωνο. Πατήστε για να μάθετε περισσότερα."</string>
<string name="adb_active_notification_title" msgid="408390247354560331">"Συνδέθηκε ο εντοπισμός σφαλμάτων USB"</string>
- <string name="adb_active_notification_message" msgid="5617264033476778211">"Απενεργοποιήστε τον εντοπισμό/διόρθ. σφαλμάτων USB"</string>
+ <string name="adb_active_notification_message" msgid="5617264033476778211">"Πατήστε για απενεργοποίηση εντοπισμού/διόρθ. σφαλμάτων USB"</string>
<string name="adb_active_notification_message" product="tv" msgid="6624498401272780855">"Επιλογή για απενεργοποίηση του εντοπισμού σφαλμάτων USB."</string>
<string name="adbwifi_active_notification_title" msgid="6147343659168302473">"Συνδέθηκε ο ασύρματος εντοπισμός σφαλμάτων"</string>
<string name="adbwifi_active_notification_message" msgid="930987922852867972">"Πατήστε, για να απενεργοποιήσετε τον ασύρματο εντοπισμό σφαλμάτων"</string>
@@ -2057,7 +2055,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_cant_share_with_work_apps" msgid="637686613606502219">"Δεν είναι δυνατή η κοινοποίηση αυτού του περιεχομένου με εφαρμογές εργασιών"</string>
+ <string name="resolver_cant_share_with_work_apps" msgid="637686613606502219">"Δεν είναι δυνατή η κοινοποίηση αυτού του περιεχομένου με εφαρμογές εργασίας"</string>
<string name="resolver_cant_share_with_work_apps_explanation" msgid="3332302070341130545">"Ο διαχειριστής IT δεν σας επιτρέπει να κοινοποιήσετε αυτό το περιεχόμενο με εφαρμογές στο προφίλ εργασίας σας."</string>
<string name="resolver_cant_access_work_apps" msgid="2455757966397563223">"Δεν είναι δυνατό το άνοιγμα με εφαρμογές εργασίας"</string>
<string name="resolver_cant_access_work_apps_explanation" msgid="3626983885525445790">"Ο διαχειριστής IT δεν σας επιτρέπει να ανοίξετε αυτό το περιεχόμενο με εφαρμογές στο προφίλ εργασίας σας."</string>
@@ -2067,8 +2065,8 @@
<string name="resolver_cant_access_personal_apps_explanation" msgid="2298773629302296519">"Ο διαχειριστής IT δεν σας επιτρέπει να ανοίξετε αυτό το περιεχόμενο με εφαρμογές στο προσωπικό προφίλ σας."</string>
<string name="resolver_turn_on_work_apps" msgid="884910835250037247">"Το προφίλ εργασίας σας έχει τεθεί σε παύση."</string>
<string name="resolver_switch_on_work" msgid="2873009160846966379">"Ενεργοποίηση"</string>
- <string name="resolver_no_work_apps_available_share" msgid="7933949011797699505">"Καμία εφαρμογή εργασιών δεν μπορεί να υποστηρίξει αυτό το περιεχόμενο."</string>
- <string name="resolver_no_work_apps_available_resolve" msgid="1244844292366099399">"Καμία εφαρμογή εργασιών δεν μπορεί να ανοίξει αυτό το περιεχόμενο."</string>
+ <string name="resolver_no_work_apps_available_share" msgid="7933949011797699505">"Καμία εφαρμογή εργασίας δεν μπορεί να υποστηρίξει αυτό το περιεχόμενο."</string>
+ <string name="resolver_no_work_apps_available_resolve" msgid="1244844292366099399">"Καμία εφαρμογή εργασίας δεν μπορεί να ανοίξει αυτό το περιεχόμενο."</string>
<string name="resolver_no_personal_apps_available_share" msgid="5639102815174748732">"Καμία προσωπική εφαρμογή δεν μπορεί να υποστηρίξει αυτό το περιεχόμενο."</string>
<string name="resolver_no_personal_apps_available_resolve" msgid="5120671970531446978">"Καμία προσωπική εφαρμογή δεν μπορεί να ανοίξει αυτό το περιεχόμενο."</string>
<string name="PERSOSUBSTATE_SIM_NETWORK_ENTRY" msgid="8050953231914637819">"PIN ξεκλειδώματος δικτύου κάρτας SIM"</string>
diff --git a/core/res/res/values-en-rAU/strings.xml b/core/res/res/values-en-rAU/strings.xml
index 3416e2d53ba6..359052488f52 100644
--- a/core/res/res/values-en-rAU/strings.xml
+++ b/core/res/res/values-en-rAU/strings.xml
@@ -202,10 +202,8 @@
<string name="printing_disabled_by" msgid="3517499806528864633">"Printing disabled by <xliff:g id="OWNER_APP">%s</xliff:g>."</string>
<string name="personal_apps_suspension_title" msgid="7561416677884286600">"Turn on your work profile"</string>
<string name="personal_apps_suspension_text" msgid="6115455688932935597">"Your personal apps are blocked until you turn on your work profile"</string>
- <!-- no translation found for personal_apps_suspension_soon_text (8123898693479590) -->
- <skip />
- <!-- no translation found for personal_apps_suspended_turn_profile_on (2758012869627513689) -->
- <skip />
+ <string name="personal_apps_suspension_soon_text" msgid="8123898693479590">"Personal apps will be blocked on <xliff:g id="DATE">%1$s</xliff:g> at <xliff:g id="TIME">%2$s</xliff:g>. Your IT admin doesn’t allow your work profile to stay off for more than <xliff:g id="NUMBER">%3$d</xliff:g> days."</string>
+ <string name="personal_apps_suspended_turn_profile_on" msgid="2758012869627513689">"Turn on"</string>
<string name="me" msgid="6207584824693813140">"Me"</string>
<string name="power_dialog" product="tablet" msgid="8333207765671417261">"Tablet options"</string>
<string name="power_dialog" product="tv" msgid="7792839006640933763">"Android TV options"</string>
diff --git a/core/res/res/values-en-rCA/strings.xml b/core/res/res/values-en-rCA/strings.xml
index 4d04a3e0d826..baf246cad231 100644
--- a/core/res/res/values-en-rCA/strings.xml
+++ b/core/res/res/values-en-rCA/strings.xml
@@ -202,10 +202,8 @@
<string name="printing_disabled_by" msgid="3517499806528864633">"Printing disabled by <xliff:g id="OWNER_APP">%s</xliff:g>."</string>
<string name="personal_apps_suspension_title" msgid="7561416677884286600">"Turn on your work profile"</string>
<string name="personal_apps_suspension_text" msgid="6115455688932935597">"Your personal apps are blocked until you turn on your work profile"</string>
- <!-- no translation found for personal_apps_suspension_soon_text (8123898693479590) -->
- <skip />
- <!-- no translation found for personal_apps_suspended_turn_profile_on (2758012869627513689) -->
- <skip />
+ <string name="personal_apps_suspension_soon_text" msgid="8123898693479590">"Personal apps will be blocked on <xliff:g id="DATE">%1$s</xliff:g> at <xliff:g id="TIME">%2$s</xliff:g>. Your IT admin doesn’t allow your work profile to stay off for more than <xliff:g id="NUMBER">%3$d</xliff:g> days."</string>
+ <string name="personal_apps_suspended_turn_profile_on" msgid="2758012869627513689">"Turn on"</string>
<string name="me" msgid="6207584824693813140">"Me"</string>
<string name="power_dialog" product="tablet" msgid="8333207765671417261">"Tablet options"</string>
<string name="power_dialog" product="tv" msgid="7792839006640933763">"Android TV options"</string>
diff --git a/core/res/res/values-en-rGB/strings.xml b/core/res/res/values-en-rGB/strings.xml
index 3416e2d53ba6..359052488f52 100644
--- a/core/res/res/values-en-rGB/strings.xml
+++ b/core/res/res/values-en-rGB/strings.xml
@@ -202,10 +202,8 @@
<string name="printing_disabled_by" msgid="3517499806528864633">"Printing disabled by <xliff:g id="OWNER_APP">%s</xliff:g>."</string>
<string name="personal_apps_suspension_title" msgid="7561416677884286600">"Turn on your work profile"</string>
<string name="personal_apps_suspension_text" msgid="6115455688932935597">"Your personal apps are blocked until you turn on your work profile"</string>
- <!-- no translation found for personal_apps_suspension_soon_text (8123898693479590) -->
- <skip />
- <!-- no translation found for personal_apps_suspended_turn_profile_on (2758012869627513689) -->
- <skip />
+ <string name="personal_apps_suspension_soon_text" msgid="8123898693479590">"Personal apps will be blocked on <xliff:g id="DATE">%1$s</xliff:g> at <xliff:g id="TIME">%2$s</xliff:g>. Your IT admin doesn’t allow your work profile to stay off for more than <xliff:g id="NUMBER">%3$d</xliff:g> days."</string>
+ <string name="personal_apps_suspended_turn_profile_on" msgid="2758012869627513689">"Turn on"</string>
<string name="me" msgid="6207584824693813140">"Me"</string>
<string name="power_dialog" product="tablet" msgid="8333207765671417261">"Tablet options"</string>
<string name="power_dialog" product="tv" msgid="7792839006640933763">"Android TV options"</string>
diff --git a/core/res/res/values-en-rIN/strings.xml b/core/res/res/values-en-rIN/strings.xml
index 3416e2d53ba6..359052488f52 100644
--- a/core/res/res/values-en-rIN/strings.xml
+++ b/core/res/res/values-en-rIN/strings.xml
@@ -202,10 +202,8 @@
<string name="printing_disabled_by" msgid="3517499806528864633">"Printing disabled by <xliff:g id="OWNER_APP">%s</xliff:g>."</string>
<string name="personal_apps_suspension_title" msgid="7561416677884286600">"Turn on your work profile"</string>
<string name="personal_apps_suspension_text" msgid="6115455688932935597">"Your personal apps are blocked until you turn on your work profile"</string>
- <!-- no translation found for personal_apps_suspension_soon_text (8123898693479590) -->
- <skip />
- <!-- no translation found for personal_apps_suspended_turn_profile_on (2758012869627513689) -->
- <skip />
+ <string name="personal_apps_suspension_soon_text" msgid="8123898693479590">"Personal apps will be blocked on <xliff:g id="DATE">%1$s</xliff:g> at <xliff:g id="TIME">%2$s</xliff:g>. Your IT admin doesn’t allow your work profile to stay off for more than <xliff:g id="NUMBER">%3$d</xliff:g> days."</string>
+ <string name="personal_apps_suspended_turn_profile_on" msgid="2758012869627513689">"Turn on"</string>
<string name="me" msgid="6207584824693813140">"Me"</string>
<string name="power_dialog" product="tablet" msgid="8333207765671417261">"Tablet options"</string>
<string name="power_dialog" product="tv" msgid="7792839006640933763">"Android TV options"</string>
diff --git a/core/res/res/values-en-rXC/strings.xml b/core/res/res/values-en-rXC/strings.xml
index 36380b822864..31abd8235bf4 100644
--- a/core/res/res/values-en-rXC/strings.xml
+++ b/core/res/res/values-en-rXC/strings.xml
@@ -202,10 +202,8 @@
<string name="printing_disabled_by" msgid="3517499806528864633">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‎‎‎‎‏‏‎‏‎‎‎‎‏‎‏‎‏‎‏‏‎‏‏‏‎‎‎‎‎‎‎‎‎‎‎‏‏‎‏‎‏‎‎‎‏‎‎‎‎‎‎‏‎‏‏‏‏‎‎‏‎Printing disabled by ‎‏‎‎‏‏‎<xliff:g id="OWNER_APP">%s</xliff:g>‎‏‎‎‏‏‏‎.‎‏‎‎‏‎"</string>
<string name="personal_apps_suspension_title" msgid="7561416677884286600">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‏‎‎‎‏‏‏‎‏‏‏‏‏‎‎‎‏‏‎‎‎‏‏‎‏‎‎‎‎‎‎‎‏‏‎‎‎‎‎‎‎‎‎‏‏‏‎‏‎‏‏‎‏‎‎‎‏‎‎‎‎Turn on your work profile‎‏‎‎‏‎"</string>
<string name="personal_apps_suspension_text" msgid="6115455688932935597">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‎‏‎‎‏‏‎‏‏‏‏‎‎‏‏‏‎‏‏‎‏‎‎‎‏‏‎‎‎‏‎‎‏‎‏‎‎‏‏‏‏‏‎‏‎‏‎‎‎‏‏‏‏‎‏‎‏‏‎‏‎Your personal apps are blocked until you turn on your work profile‎‏‎‎‏‎"</string>
- <!-- no translation found for personal_apps_suspension_soon_text (8123898693479590) -->
- <skip />
- <!-- no translation found for personal_apps_suspended_turn_profile_on (2758012869627513689) -->
- <skip />
+ <string name="personal_apps_suspension_soon_text" msgid="8123898693479590">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‎‏‎‏‏‏‏‎‎‏‏‎‏‏‏‎‎‏‎‏‎‎‏‎‎‏‎‎‎‏‏‏‏‏‏‎‏‎‎‎‎‏‏‏‎‏‏‎‎‏‎‏‎‎‏‏‎‎Personal apps will be blocked on ‎‏‎‎‏‏‎<xliff:g id="DATE">%1$s</xliff:g>‎‏‎‎‏‏‏‎ at ‎‏‎‎‏‏‎<xliff:g id="TIME">%2$s</xliff:g>‎‏‎‎‏‏‏‎. Your IT admin doesn’t allow your work profile to stay off for more than ‎‏‎‎‏‏‎<xliff:g id="NUMBER">%3$d</xliff:g>‎‏‎‎‏‏‏‎ days.‎‏‎‎‏‎"</string>
+ <string name="personal_apps_suspended_turn_profile_on" msgid="2758012869627513689">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‎‏‏‎‎‏‎‎‎‏‏‎‎‏‏‎‏‏‏‎‎‎‎‏‎‏‏‏‏‎‏‎‎‏‎‎‎‎‎‏‏‎‏‎‏‎‎‎‏‎‏‏‎‏‎‏‏‎‎‏‎Turn on‎‏‎‎‏‎"</string>
<string name="me" msgid="6207584824693813140">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‎‏‏‎‎‎‏‎‎‏‎‏‏‏‎‎‎‏‎‏‏‎‎‎‎‎‏‎‎‏‎‎‎‏‎‎‏‏‏‏‏‎‏‎‏‏‏‎‏‏‏‏‏‎‎‏‎‏‎‎‎Me‎‏‎‎‏‎"</string>
<string name="power_dialog" product="tablet" msgid="8333207765671417261">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‎‎‏‏‏‎‏‎‎‏‎‏‏‎‎‎‎‎‎‎‎‏‎‎‏‏‏‏‏‏‎‎‏‎‎‎‎‏‎‏‏‏‏‏‎‎‎‏‎‏‎‏‏‎‏‎‏‏‎‏‎Tablet options‎‏‎‎‏‎"</string>
<string name="power_dialog" product="tv" msgid="7792839006640933763">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‏‏‎‎‎‎‏‎‎‏‎‏‏‎‏‏‏‎‎‏‏‏‎‎‏‎‎‏‏‏‎‎‏‏‏‎‏‎‏‎‎‏‎‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‏‎Android TV options‎‏‎‎‏‎"</string>
diff --git a/core/res/res/values-es-rUS/strings.xml b/core/res/res/values-es-rUS/strings.xml
index 7f511aec6feb..005dd5d5f6de 100644
--- a/core/res/res/values-es-rUS/strings.xml
+++ b/core/res/res/values-es-rUS/strings.xml
@@ -202,10 +202,8 @@
<string name="printing_disabled_by" msgid="3517499806528864633">"<xliff:g id="OWNER_APP">%s</xliff:g> inhabilitó la impresión."</string>
<string name="personal_apps_suspension_title" msgid="7561416677884286600">"Activa tu perfil de trabajo"</string>
<string name="personal_apps_suspension_text" msgid="6115455688932935597">"Las apps personales estarán bloqueadas hasta que actives tu perfil de trabajo"</string>
- <!-- no translation found for personal_apps_suspension_soon_text (8123898693479590) -->
- <skip />
- <!-- no translation found for personal_apps_suspended_turn_profile_on (2758012869627513689) -->
- <skip />
+ <string name="personal_apps_suspension_soon_text" msgid="8123898693479590">"Se bloquearán las apps personales el <xliff:g id="DATE">%1$s</xliff:g> a la(s) <xliff:g id="TIME">%2$s</xliff:g>. Tu administrador de TI no permite que mantengas tu perfil de trabajo desactivado durante más de <xliff:g id="NUMBER">%3$d</xliff:g> días."</string>
+ <string name="personal_apps_suspended_turn_profile_on" msgid="2758012869627513689">"Activar"</string>
<string name="me" msgid="6207584824693813140">"Yo"</string>
<string name="power_dialog" product="tablet" msgid="8333207765671417261">"Opciones de tablet"</string>
<string name="power_dialog" product="tv" msgid="7792839006640933763">"Opciones de Android TV"</string>
diff --git a/core/res/res/values-es/strings.xml b/core/res/res/values-es/strings.xml
index 657649316bfe..e18fc11bc7c3 100644
--- a/core/res/res/values-es/strings.xml
+++ b/core/res/res/values-es/strings.xml
@@ -202,10 +202,8 @@
<string name="printing_disabled_by" msgid="3517499806528864633">"<xliff:g id="OWNER_APP">%s</xliff:g> ha inhabilitado la impresión."</string>
<string name="personal_apps_suspension_title" msgid="7561416677884286600">"Activa tu perfil de trabajo"</string>
<string name="personal_apps_suspension_text" msgid="6115455688932935597">"Tus aplicaciones personales estarán bloqueadas hasta que actives tu perfil de trabajo"</string>
- <!-- no translation found for personal_apps_suspension_soon_text (8123898693479590) -->
- <skip />
- <!-- no translation found for personal_apps_suspended_turn_profile_on (2758012869627513689) -->
- <skip />
+ <string name="personal_apps_suspension_soon_text" msgid="8123898693479590">"Las aplicaciones personales se bloquearán el <xliff:g id="DATE">%1$s</xliff:g> a las <xliff:g id="TIME">%2$s</xliff:g>. Tu administrador de TI no permite que tu perfil de trabajo esté más de <xliff:g id="NUMBER">%3$d</xliff:g> días desactivado."</string>
+ <string name="personal_apps_suspended_turn_profile_on" msgid="2758012869627513689">"Activar"</string>
<string name="me" msgid="6207584824693813140">"Yo"</string>
<string name="power_dialog" product="tablet" msgid="8333207765671417261">"Opciones del tablet"</string>
<string name="power_dialog" product="tv" msgid="7792839006640933763">"Opciones de Android TV"</string>
@@ -2057,10 +2055,10 @@
<string name="resolver_work_tab" msgid="2690019516263167035">"Trabajo"</string>
<string name="resolver_personal_tab_accessibility" msgid="5739524949153091224">"Ver contenido personal"</string>
<string name="resolver_work_tab_accessibility" msgid="4753168230363802734">"Ver contenido de trabajo"</string>
- <string name="resolver_cant_share_with_work_apps" msgid="637686613606502219">"No se puede compartir con una aplicación de trabajo"</string>
- <string name="resolver_cant_share_with_work_apps_explanation" msgid="3332302070341130545">"Tu administrador de TI no te permite compartir este contenido con ninguna aplicación de tu perfil de trabajo"</string>
+ <string name="resolver_cant_share_with_work_apps" msgid="637686613606502219">"No se puede compartir con aplicaciones de trabajo"</string>
+ <string name="resolver_cant_share_with_work_apps_explanation" msgid="3332302070341130545">"Tu administrador de TI no te permite compartir este contenido con aplicaciones de tu perfil de trabajo"</string>
<string name="resolver_cant_access_work_apps" msgid="2455757966397563223">"No se puede abrir con una aplicación de trabajo"</string>
- <string name="resolver_cant_access_work_apps_explanation" msgid="3626983885525445790">"Tu administrador de TI no te permite abrir este contenido con ninguna aplicación de tu perfil de trabajo"</string>
+ <string name="resolver_cant_access_work_apps_explanation" msgid="3626983885525445790">"Tu administrador de TI no te permite abrir este contenido con aplicaciones de tu perfil de trabajo"</string>
<string name="resolver_cant_share_with_personal_apps" msgid="3079139799233316203">"No se puede compartir con una aplicación personal"</string>
<string name="resolver_cant_share_with_personal_apps_explanation" msgid="2959282422751315171">"Tu administrador de TI no te permite compartir este contenido con ninguna aplicación de tu perfil personal"</string>
<string name="resolver_cant_access_personal_apps" msgid="648291604475669395">"No se puede abrir con una aplicación personal"</string>
diff --git a/core/res/res/values-et/strings.xml b/core/res/res/values-et/strings.xml
index 8b99b44f64db..56887d822483 100644
--- a/core/res/res/values-et/strings.xml
+++ b/core/res/res/values-et/strings.xml
@@ -202,10 +202,8 @@
<string name="printing_disabled_by" msgid="3517499806528864633">"Rakendus <xliff:g id="OWNER_APP">%s</xliff:g> on printimise keelanud."</string>
<string name="personal_apps_suspension_title" msgid="7561416677884286600">"Lülitage oma tööprofiil sisse"</string>
<string name="personal_apps_suspension_text" msgid="6115455688932935597">"Teie isiklikud rakendused on blokeeritud, kuni lülitate oma tööprofiili sisse"</string>
- <!-- no translation found for personal_apps_suspension_soon_text (8123898693479590) -->
- <skip />
- <!-- no translation found for personal_apps_suspended_turn_profile_on (2758012869627513689) -->
- <skip />
+ <string name="personal_apps_suspension_soon_text" msgid="8123898693479590">"Isiklikud rakendused blokeeritakse <xliff:g id="DATE">%1$s</xliff:g> kell <xliff:g id="TIME">%2$s</xliff:g>. IT-administraator ei luba teie tööprofiili üle <xliff:g id="NUMBER">%3$d</xliff:g> päeva väljalülitatuna hoida."</string>
+ <string name="personal_apps_suspended_turn_profile_on" msgid="2758012869627513689">"Lülita sisse"</string>
<string name="me" msgid="6207584824693813140">"Mina"</string>
<string name="power_dialog" product="tablet" msgid="8333207765671417261">"Tahvelarvuti valikud"</string>
<string name="power_dialog" product="tv" msgid="7792839006640933763">"Android TV valikud"</string>
diff --git a/core/res/res/values-eu/strings.xml b/core/res/res/values-eu/strings.xml
index 5d0b90cea7d5..9f927c3015d5 100644
--- a/core/res/res/values-eu/strings.xml
+++ b/core/res/res/values-eu/strings.xml
@@ -202,10 +202,8 @@
<string name="printing_disabled_by" msgid="3517499806528864633">"<xliff:g id="OWNER_APP">%s</xliff:g> aplikazioak desgaitu egin du inprimatzeko aukera."</string>
<string name="personal_apps_suspension_title" msgid="7561416677884286600">"Aktibatu laneko profila"</string>
<string name="personal_apps_suspension_text" msgid="6115455688932935597">"Aplikazio pertsonalak blokeatuta egongo dira laneko profila aktibatzen duzun arte"</string>
- <!-- no translation found for personal_apps_suspension_soon_text (8123898693479590) -->
- <skip />
- <!-- no translation found for personal_apps_suspended_turn_profile_on (2758012869627513689) -->
- <skip />
+ <string name="personal_apps_suspension_soon_text" msgid="8123898693479590">"Aplikazio pertsonalak egun eta ordu honetan blokeatuko dira: <xliff:g id="DATE">%1$s</xliff:g>, <xliff:g id="TIME">%2$s</xliff:g>. IKT saileko administratzaileak ez dizu ematen baimenik laneko profila <xliff:g id="NUMBER">%3$d</xliff:g> egunez baino gehiagoz desaktibatuta edukitzeko."</string>
+ <string name="personal_apps_suspended_turn_profile_on" msgid="2758012869627513689">"Aktibatu"</string>
<string name="me" msgid="6207584824693813140">"Ni"</string>
<string name="power_dialog" product="tablet" msgid="8333207765671417261">"Tabletaren aukerak"</string>
<string name="power_dialog" product="tv" msgid="7792839006640933763">"Android TV gailuaren aukerak"</string>
diff --git a/core/res/res/values-fa/strings.xml b/core/res/res/values-fa/strings.xml
index 29ac9e7fc1d3..2287160a70d2 100644
--- a/core/res/res/values-fa/strings.xml
+++ b/core/res/res/values-fa/strings.xml
@@ -202,10 +202,8 @@
<string name="printing_disabled_by" msgid="3517499806528864633">"<xliff:g id="OWNER_APP">%s</xliff:g> چاپ کردن را غیرفعال کرده است."</string>
<string name="personal_apps_suspension_title" msgid="7561416677884286600">"نمایه کاری‌تان را روشن کنید"</string>
<string name="personal_apps_suspension_text" msgid="6115455688932935597">"تا زمانی‌که نمایه کاری‌تان را روشن نکنید، برنامه‌های شخصی‌تان مسدودند"</string>
- <!-- no translation found for personal_apps_suspension_soon_text (8123898693479590) -->
- <skip />
- <!-- no translation found for personal_apps_suspended_turn_profile_on (2758012869627513689) -->
- <skip />
+ <string name="personal_apps_suspension_soon_text" msgid="8123898693479590">"برنامه‌های شخصی در تاریخ <xliff:g id="DATE">%1$s</xliff:g> ساعت <xliff:g id="TIME">%2$s</xliff:g> مسدود خواهند شد. سرپرست فناوری اطلاعات اجازه نمی‌دهد نمایه کاری شما بیشتر از <xliff:g id="NUMBER">%3$d</xliff:g> روز خاموش بماند."</string>
+ <string name="personal_apps_suspended_turn_profile_on" msgid="2758012869627513689">"روشن کردن"</string>
<string name="me" msgid="6207584824693813140">"من"</string>
<string name="power_dialog" product="tablet" msgid="8333207765671417261">"گزینه‌های رایانهٔ لوحی"</string>
<string name="power_dialog" product="tv" msgid="7792839006640933763">"‏گزینه‌های Android TV"</string>
@@ -556,7 +554,7 @@
<string name="face_authenticated_confirmation_required" msgid="6872632732508013755">"چهره احراز هویت شد، لطفاً تأیید را فشار دهید"</string>
<string name="fingerprint_error_hw_not_available" msgid="4571700896929561202">"سخت‌افزار اثرانگشت در دسترس نیست."</string>
<string name="fingerprint_error_no_space" msgid="6126456006769817485">"ذخیره اثر انگشت ممکن نیست. لطفاً یک اثر انگشت موجود را حذف کنید."</string>
- <string name="fingerprint_error_timeout" msgid="2946635815726054226">"مهلت زمانی ثبت اثر انگشت به پایان رسید. دوباره امتحان کنید."</string>
+ <string name="fingerprint_error_timeout" msgid="2946635815726054226">"درنگ ثبت اثر انگشت به پایان رسید. دوباره امتحان کنید."</string>
<string name="fingerprint_error_canceled" msgid="540026881380070750">"عملکرد اثر انگشت لغو شد."</string>
<string name="fingerprint_error_user_canceled" msgid="7685676229281231614">"کاربر عملیات اثر انگشت را لغو کرد"</string>
<string name="fingerprint_error_lockout" msgid="7853461265604738671">"تلاش‌های زیادی انجام شده است. بعداً دوباره امتحان کنید."</string>
diff --git a/core/res/res/values-fi/strings.xml b/core/res/res/values-fi/strings.xml
index e785f0097531..f0ce863c5bb8 100644
--- a/core/res/res/values-fi/strings.xml
+++ b/core/res/res/values-fi/strings.xml
@@ -202,10 +202,8 @@
<string name="printing_disabled_by" msgid="3517499806528864633">"<xliff:g id="OWNER_APP">%s</xliff:g> on poistanut tulostuksen käytöstä."</string>
<string name="personal_apps_suspension_title" msgid="7561416677884286600">"Laita työprofiilisi päälle"</string>
<string name="personal_apps_suspension_text" msgid="6115455688932935597">"Henkilökohtaiset sovelluksesi estetään, kunnes laitat työprofiilisi päälle"</string>
- <!-- no translation found for personal_apps_suspension_soon_text (8123898693479590) -->
- <skip />
- <!-- no translation found for personal_apps_suspended_turn_profile_on (2758012869627513689) -->
- <skip />
+ <string name="personal_apps_suspension_soon_text" msgid="8123898693479590">"Henkilökohtaiset sovellukset estetään <xliff:g id="DATE">%1$s</xliff:g> klo <xliff:g id="TIME">%2$s</xliff:g>. IT-järjestelmänvalvoja ei salli työprofiilisi pysyä pois päältä yli <xliff:g id="NUMBER">%3$d</xliff:g> päivää."</string>
+ <string name="personal_apps_suspended_turn_profile_on" msgid="2758012869627513689">"Laita päälle"</string>
<string name="me" msgid="6207584824693813140">"Minä"</string>
<string name="power_dialog" product="tablet" msgid="8333207765671417261">"Tablet-laitteen asetukset"</string>
<string name="power_dialog" product="tv" msgid="7792839006640933763">"Android TV ‑vaihtoehdot"</string>
diff --git a/core/res/res/values-fr-rCA/strings.xml b/core/res/res/values-fr-rCA/strings.xml
index 804b5c9b00c4..2eba43f5ae7a 100644
--- a/core/res/res/values-fr-rCA/strings.xml
+++ b/core/res/res/values-fr-rCA/strings.xml
@@ -202,10 +202,8 @@
<string name="printing_disabled_by" msgid="3517499806528864633">"Impression désactivée par <xliff:g id="OWNER_APP">%s</xliff:g>."</string>
<string name="personal_apps_suspension_title" msgid="7561416677884286600">"Activer profil professionnel"</string>
<string name="personal_apps_suspension_text" msgid="6115455688932935597">"Vos applications personnelles sont bloquées jusqu\'à ce que vous activiez votre profil professionnel"</string>
- <!-- no translation found for personal_apps_suspension_soon_text (8123898693479590) -->
- <skip />
- <!-- no translation found for personal_apps_suspended_turn_profile_on (2758012869627513689) -->
- <skip />
+ <string name="personal_apps_suspension_soon_text" msgid="8123898693479590">"Les applications personnelles seront bloquées le <xliff:g id="DATE">%1$s</xliff:g> à <xliff:g id="TIME">%2$s</xliff:g>. Votre administrateur informatique ne vous autorise pas à laisser votre profil professionnel désactivé pendant plus de <xliff:g id="NUMBER">%3$d</xliff:g> jours."</string>
+ <string name="personal_apps_suspended_turn_profile_on" msgid="2758012869627513689">"Activer"</string>
<string name="me" msgid="6207584824693813140">"Moi"</string>
<string name="power_dialog" product="tablet" msgid="8333207765671417261">"Options de la tablette"</string>
<string name="power_dialog" product="tv" msgid="7792839006640933763">"Options d\'Android TV"</string>
diff --git a/core/res/res/values-fr/strings.xml b/core/res/res/values-fr/strings.xml
index 410275761404..151f13d5176b 100644
--- a/core/res/res/values-fr/strings.xml
+++ b/core/res/res/values-fr/strings.xml
@@ -202,10 +202,8 @@
<string name="printing_disabled_by" msgid="3517499806528864633">"Impression désactivée par <xliff:g id="OWNER_APP">%s</xliff:g>."</string>
<string name="personal_apps_suspension_title" msgid="7561416677884286600">"Activez profil professionnel"</string>
<string name="personal_apps_suspension_text" msgid="6115455688932935597">"Vos applications personnelles sont bloquées jusqu\'à ce que vous activiez votre profil professionnel"</string>
- <!-- no translation found for personal_apps_suspension_soon_text (8123898693479590) -->
- <skip />
- <!-- no translation found for personal_apps_suspended_turn_profile_on (2758012869627513689) -->
- <skip />
+ <string name="personal_apps_suspension_soon_text" msgid="8123898693479590">"Les applications personnelles seront bloquées le <xliff:g id="DATE">%1$s</xliff:g> à <xliff:g id="TIME">%2$s</xliff:g>. Votre administrateur informatique ne vous autorise pas à désactiver votre profil professionnel pendant plus de <xliff:g id="NUMBER">%3$d</xliff:g> jours."</string>
+ <string name="personal_apps_suspended_turn_profile_on" msgid="2758012869627513689">"Activer"</string>
<string name="me" msgid="6207584824693813140">"Moi"</string>
<string name="power_dialog" product="tablet" msgid="8333207765671417261">"Options de la tablette"</string>
<string name="power_dialog" product="tv" msgid="7792839006640933763">"Options Android TV"</string>
diff --git a/core/res/res/values-gl/strings.xml b/core/res/res/values-gl/strings.xml
index 91a8d0585709..8272fed8cc97 100644
--- a/core/res/res/values-gl/strings.xml
+++ b/core/res/res/values-gl/strings.xml
@@ -202,10 +202,8 @@
<string name="printing_disabled_by" msgid="3517499806528864633">"<xliff:g id="OWNER_APP">%s</xliff:g> desactivou a impresión."</string>
<string name="personal_apps_suspension_title" msgid="7561416677884286600">"Activa o perfil de traballo"</string>
<string name="personal_apps_suspension_text" msgid="6115455688932935597">"As túas aplicacións persoais están bloqueadas ata que actives o teu perfil de traballo"</string>
- <!-- no translation found for personal_apps_suspension_soon_text (8123898693479590) -->
- <skip />
- <!-- no translation found for personal_apps_suspended_turn_profile_on (2758012869627513689) -->
- <skip />
+ <string name="personal_apps_suspension_soon_text" msgid="8123898693479590">"As aplicacións persoais bloquearanse o <xliff:g id="DATE">%1$s</xliff:g> á seguinte hora: <xliff:g id="TIME">%2$s</xliff:g>. O administrador de TI non permite que o teu perfil de traballo estea desactivado máis de <xliff:g id="NUMBER">%3$d</xliff:g> días."</string>
+ <string name="personal_apps_suspended_turn_profile_on" msgid="2758012869627513689">"Activar"</string>
<string name="me" msgid="6207584824693813140">"Eu"</string>
<string name="power_dialog" product="tablet" msgid="8333207765671417261">"Opcións da tableta"</string>
<string name="power_dialog" product="tv" msgid="7792839006640933763">"Opcións de Android TV"</string>
@@ -1788,7 +1786,7 @@
<string name="managed_profile_label_badge" msgid="6762559569999499495">"<xliff:g id="LABEL">%1$s</xliff:g> do traballo"</string>
<string name="managed_profile_label_badge_2" msgid="5673187309555352550">"2.º <xliff:g id="LABEL">%1$s</xliff:g> do traballo"</string>
<string name="managed_profile_label_badge_3" msgid="6882151970556391957">"3.º <xliff:g id="LABEL">%1$s</xliff:g> do traballo"</string>
- <string name="lock_to_app_unlock_pin" msgid="3890940811866290782">"Solicitar PIN para soltar fixación"</string>
+ <string name="lock_to_app_unlock_pin" msgid="3890940811866290782">"Solicitar PIN para deixar de fixar"</string>
<string name="lock_to_app_unlock_pattern" msgid="2694204070499712503">"Solicitar un padrón de desbloqueo antes de deixar de fixar a pantalla"</string>
<string name="lock_to_app_unlock_password" msgid="9126722403506560473">"Solicitar un contrasinal para deixar de fixar a pantalla"</string>
<string name="package_installed_device_owner" msgid="7035926868974878525">"Instalado polo teu administrador"</string>
@@ -2032,7 +2030,7 @@
<item quantity="other"><xliff:g id="FILE_NAME_2">%s</xliff:g> + <xliff:g id="COUNT_3">%d</xliff:g> ficheiros</item>
<item quantity="one"><xliff:g id="FILE_NAME_0">%s</xliff:g> + <xliff:g id="COUNT_1">%d</xliff:g> ficheiro</item>
</plurals>
- <string name="chooser_no_direct_share_targets" msgid="1511722103987329028">"Non hai persoas recomendadas coas que compartir contido"</string>
+ <string name="chooser_no_direct_share_targets" msgid="1511722103987329028">"Non hai recomendacións de persoas coas que compartir contido"</string>
<string name="chooser_all_apps_button_label" msgid="3230427756238666328">"Lista de aplicacións"</string>
<string name="usb_device_resolve_prompt_warn" msgid="325871329788064199">"Esta aplicación non está autorizada a realizar gravacións, pero pode capturar audio a través deste dispositivo USB."</string>
<string name="accessibility_system_action_home_label" msgid="3234748160850301870">"Inicio"</string>
diff --git a/core/res/res/values-gu/strings.xml b/core/res/res/values-gu/strings.xml
index ae95949ff3a0..a2317e9e1cad 100644
--- a/core/res/res/values-gu/strings.xml
+++ b/core/res/res/values-gu/strings.xml
@@ -202,10 +202,8 @@
<string name="printing_disabled_by" msgid="3517499806528864633">"<xliff:g id="OWNER_APP">%s</xliff:g> દ્વારા પ્રિન્ટ કરવાનું બંધ કરાયું છે."</string>
<string name="personal_apps_suspension_title" msgid="7561416677884286600">"કાર્યાલયની પ્રોફાઇલ ચાલુ કરો"</string>
<string name="personal_apps_suspension_text" msgid="6115455688932935597">"જ્યાં સુધી તમે કાર્યાલયની પ્રોફાઇલ ચાલુ ન કરો ત્યાં સુધી તમારી વ્યક્તિગત ઍપ બ્લૉક કરેલી રહે છે"</string>
- <!-- no translation found for personal_apps_suspension_soon_text (8123898693479590) -->
- <skip />
- <!-- no translation found for personal_apps_suspended_turn_profile_on (2758012869627513689) -->
- <skip />
+ <string name="personal_apps_suspension_soon_text" msgid="8123898693479590">"વ્યક્તિગત ઍપને <xliff:g id="DATE">%1$s</xliff:g>ના રોજ <xliff:g id="TIME">%2$s</xliff:g> વાગ્યે બ્લૉક કરવામાં આવશે. તમારા IT વ્યવસ્થાપક તમારી ઑફિસની પ્રોફાઇલને <xliff:g id="NUMBER">%3$d</xliff:g> દિવસ કરતાં વધુ સમય માટે બંધ રાખવાની મંજૂરી આપતા નથી."</string>
+ <string name="personal_apps_suspended_turn_profile_on" msgid="2758012869627513689">"ચાલુ કરો"</string>
<string name="me" msgid="6207584824693813140">"હું"</string>
<string name="power_dialog" product="tablet" msgid="8333207765671417261">"ટેબ્લેટ વિકલ્પો"</string>
<string name="power_dialog" product="tv" msgid="7792839006640933763">"Android TVના વિકલ્પો"</string>
@@ -2057,10 +2055,10 @@
<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_cant_share_with_work_apps" msgid="637686613606502219">"આને ઑફિસ માટેની ઍપ સાથે શેર કરી શકતાં નથી"</string>
+ <string name="resolver_cant_share_with_work_apps" msgid="637686613606502219">"આને ઑફિસ માટેના ઍપ સાથે શેર કરી શકતાં નથી"</string>
<string name="resolver_cant_share_with_work_apps_explanation" msgid="3332302070341130545">"તમારા IT વ્યવસ્થાપક તમને તમારી કાર્યાલયની પ્રોફાઇલમાંની ઍપ વડે આ કન્ટેન્ટ શેર કરવાની મંજૂરી આપતા નથી"</string>
<string name="resolver_cant_access_work_apps" msgid="2455757966397563223">"ઑફિસ માટેની ઍપ વડે આને ખોલી શકતાં નથી"</string>
- <string name="resolver_cant_access_work_apps_explanation" msgid="3626983885525445790">"તમારા IT વ્યવસ્થાપક તમને તમારી કાર્યાલયની પ્રોફાઇલમાંની ઍપ વડે આ કન્ટેન્ટ ખોલવાની મંજૂરી આપતા નથી"</string>
+ <string name="resolver_cant_access_work_apps_explanation" msgid="3626983885525445790">"તમારા IT વ્યવસ્થાપક તમને તમારી ઑફિસની પ્રોફાઇલમાંની ઍપ વડે આ કન્ટેન્ટ ખોલવાની મંજૂરી આપતા નથી"</string>
<string name="resolver_cant_share_with_personal_apps" msgid="3079139799233316203">"આને વ્યક્તિગત ઍપ સાથે શેર કરી શકતાં નથી"</string>
<string name="resolver_cant_share_with_personal_apps_explanation" msgid="2959282422751315171">"તમારા IT વ્યવસ્થાપક તમને તમારી વ્યક્તિગત પ્રોફાઇલમાંની ઍપ વડે આ કન્ટેન્ટ શેર કરવાની મંજૂરી આપતા નથી"</string>
<string name="resolver_cant_access_personal_apps" msgid="648291604475669395">"વ્યક્તિગત ઍપ વડે આને ખોલી શકતાં નથી"</string>
diff --git a/core/res/res/values-hi/strings.xml b/core/res/res/values-hi/strings.xml
index 6fd163153b0e..0890ae13e421 100644
--- a/core/res/res/values-hi/strings.xml
+++ b/core/res/res/values-hi/strings.xml
@@ -202,10 +202,8 @@
<string name="printing_disabled_by" msgid="3517499806528864633">"<xliff:g id="OWNER_APP">%s</xliff:g> ने प्रिंटिंग सुविधा बंद कर दी है."</string>
<string name="personal_apps_suspension_title" msgid="7561416677884286600">"अपनी वर्क प्रोफ़ाइल चालू करें"</string>
<string name="personal_apps_suspension_text" msgid="6115455688932935597">"निजी ऐप्लिकेशन अनब्लॉक करने के लिए, अपनी वर्क प्रोफ़ाइल चालू करें"</string>
- <!-- no translation found for personal_apps_suspension_soon_text (8123898693479590) -->
- <skip />
- <!-- no translation found for personal_apps_suspended_turn_profile_on (2758012869627513689) -->
- <skip />
+ <string name="personal_apps_suspension_soon_text" msgid="8123898693479590">"निजी ऐप्लिकेशन <xliff:g id="DATE">%1$s</xliff:g> को <xliff:g id="TIME">%2$s</xliff:g> पर ब्लॉक कर दिए जाएंगे. आपका आईटी एडमिन आपकी वर्क प्रोफ़ाइल को <xliff:g id="NUMBER">%3$d</xliff:g> दिन से ज़्यादा बंद रखने की अनुमति नहीं देता."</string>
+ <string name="personal_apps_suspended_turn_profile_on" msgid="2758012869627513689">"चालू करें"</string>
<string name="me" msgid="6207584824693813140">"मैं"</string>
<string name="power_dialog" product="tablet" msgid="8333207765671417261">"टैबलेट विकल्‍प"</string>
<string name="power_dialog" product="tv" msgid="7792839006640933763">"Android TV डिवाइस में फ़ोन से जुड़े विकल्प"</string>
diff --git a/core/res/res/values-hr/strings.xml b/core/res/res/values-hr/strings.xml
index c7ec2be91752..17f40f15bbe3 100644
--- a/core/res/res/values-hr/strings.xml
+++ b/core/res/res/values-hr/strings.xml
@@ -204,10 +204,8 @@
<string name="printing_disabled_by" msgid="3517499806528864633">"Ispis je onemogućila aplikacija <xliff:g id="OWNER_APP">%s</xliff:g>."</string>
<string name="personal_apps_suspension_title" msgid="7561416677884286600">"Uključite poslovni profil"</string>
<string name="personal_apps_suspension_text" msgid="6115455688932935597">"Vaše su osobne aplikacije blokirane dok ne uključite poslovni profil"</string>
- <!-- no translation found for personal_apps_suspension_soon_text (8123898693479590) -->
- <skip />
- <!-- no translation found for personal_apps_suspended_turn_profile_on (2758012869627513689) -->
- <skip />
+ <string name="personal_apps_suspension_soon_text" msgid="8123898693479590">"Osobne aplikacije blokirat će se <xliff:g id="DATE">%1$s</xliff:g> u <xliff:g id="TIME">%2$s</xliff:g>. Vaš IT administrator ne dopušta da vaš poslovni profil ostane isključen dulje od <xliff:g id="NUMBER">%3$d</xliff:g> dana."</string>
+ <string name="personal_apps_suspended_turn_profile_on" msgid="2758012869627513689">"Uključi"</string>
<string name="me" msgid="6207584824693813140">"Ja"</string>
<string name="power_dialog" product="tablet" msgid="8333207765671417261">"Opcije tabletnog uređaja"</string>
<string name="power_dialog" product="tv" msgid="7792839006640933763">"Opcije Android TV-a"</string>
@@ -1150,7 +1148,7 @@
<string name="whichViewApplication" msgid="5733194231473132945">"Otvaranje pomoću aplikacije"</string>
<string name="whichViewApplicationNamed" msgid="415164730629690105">"Otvaranje pomoću aplikacije %1$s"</string>
<string name="whichViewApplicationLabel" msgid="7367556735684742409">"Otvori"</string>
- <string name="whichOpenHostLinksWith" msgid="7645631470199397485">"Otvaranje veza s <xliff:g id="HOST">%1$s</xliff:g> u aplikaciji"</string>
+ <string name="whichOpenHostLinksWith" msgid="7645631470199397485">"Otvaranje veza sa stranice <xliff:g id="HOST">%1$s</xliff:g> u aplikaciji"</string>
<string name="whichOpenLinksWith" msgid="1120936181362907258">"Otvaranje veza u aplikaciji"</string>
<string name="whichOpenLinksWithApp" msgid="6917864367861910086">"Otvaranje veza u aplikaciji <xliff:g id="APPLICATION">%1$s</xliff:g>"</string>
<string name="whichOpenHostLinksWithApp" msgid="2401668560768463004">"Otvaranje veza s <xliff:g id="HOST">%1$s</xliff:g> u aplikaciji <xliff:g id="APPLICATION">%2$s</xliff:g>"</string>
@@ -2091,14 +2089,14 @@
<string name="resolver_work_tab" msgid="2690019516263167035">"Posao"</string>
<string name="resolver_personal_tab_accessibility" msgid="5739524949153091224">"Osobni prikaz"</string>
<string name="resolver_work_tab_accessibility" msgid="4753168230363802734">"Poslovni prikaz"</string>
- <string name="resolver_cant_share_with_work_apps" msgid="637686613606502219">"To se ne može dijeliti pomoću poslovnih aplikacija"</string>
- <string name="resolver_cant_share_with_work_apps_explanation" msgid="3332302070341130545">"Vaš IT administrator ne dopušta vam dijeljenje tog sadržaja pomoću aplikacija s vašeg poslovnog profila"</string>
- <string name="resolver_cant_access_work_apps" msgid="2455757966397563223">"To se ne može otvoriti pomoću poslovnih aplikacija"</string>
- <string name="resolver_cant_access_work_apps_explanation" msgid="3626983885525445790">"Vaš IT administrator ne dopušta vam otvaranje tog sadržaja pomoću aplikacija s vašeg poslovnog profila"</string>
+ <string name="resolver_cant_share_with_work_apps" msgid="637686613606502219">"Nije moguće dijeljenje s poslovnim aplikacijama"</string>
+ <string name="resolver_cant_share_with_work_apps_explanation" msgid="3332302070341130545">"Vaš IT administrator ne dopušta vam dijeljenje tog sadržaja s aplikacijama na vašem poslovnom profilu"</string>
+ <string name="resolver_cant_access_work_apps" msgid="2455757966397563223">"Nije moguće otvaranje pomoću poslovnih aplikacija"</string>
+ <string name="resolver_cant_access_work_apps_explanation" msgid="3626983885525445790">"Vaš IT administrator ne dopušta vam otvaranje tog sadržaja pomoću aplikacija na vašem poslovnom profilu"</string>
<string name="resolver_cant_share_with_personal_apps" msgid="3079139799233316203">"To se ne može dijeliti pomoću osobnih aplikacija"</string>
<string name="resolver_cant_share_with_personal_apps_explanation" msgid="2959282422751315171">"Vaš IT administrator ne dopušta vam dijeljenje tog sadržaja pomoću aplikacija s vašeg osobnog profila"</string>
- <string name="resolver_cant_access_personal_apps" msgid="648291604475669395">"To se ne može otvoriti pomoću osobnih aplikacija"</string>
- <string name="resolver_cant_access_personal_apps_explanation" msgid="2298773629302296519">"Vaš IT administrator ne dopušta vam otvaranje tog sadržaja pomoću aplikacija s vašeg osobnog profila"</string>
+ <string name="resolver_cant_access_personal_apps" msgid="648291604475669395">"Nije moguće otvaranje pomoću osobnih aplikacija"</string>
+ <string name="resolver_cant_access_personal_apps_explanation" msgid="2298773629302296519">"Vaš IT administrator ne dopušta vam otvaranje tog sadržaja pomoću aplikacija na vašem osobnom profilu"</string>
<string name="resolver_turn_on_work_apps" msgid="884910835250037247">"Poslovni je profil pauziran"</string>
<string name="resolver_switch_on_work" msgid="2873009160846966379">"Uključi"</string>
<string name="resolver_no_work_apps_available_share" msgid="7933949011797699505">"Nijedna poslovna aplikacija ne može podržati taj sadržaj"</string>
diff --git a/core/res/res/values-hu/strings.xml b/core/res/res/values-hu/strings.xml
index 29bb05250ece..302dc6925085 100644
--- a/core/res/res/values-hu/strings.xml
+++ b/core/res/res/values-hu/strings.xml
@@ -202,10 +202,8 @@
<string name="printing_disabled_by" msgid="3517499806528864633">"A(z) <xliff:g id="OWNER_APP">%s</xliff:g> letiltotta a nyomtatást."</string>
<string name="personal_apps_suspension_title" msgid="7561416677884286600">"Munkaprofil bekapcsolása"</string>
<string name="personal_apps_suspension_text" msgid="6115455688932935597">"A személyes alkalmazások le lesznek tiltva, amíg be nem kapcsolja a munkaprofilt"</string>
- <!-- no translation found for personal_apps_suspension_soon_text (8123898693479590) -->
- <skip />
- <!-- no translation found for personal_apps_suspended_turn_profile_on (2758012869627513689) -->
- <skip />
+ <string name="personal_apps_suspension_soon_text" msgid="8123898693479590">"A rendszer a következő időpontban letiltja a személyes alkalmazásokat: <xliff:g id="DATE">%1$s</xliff:g>, <xliff:g id="TIME">%2$s</xliff:g>. Rendszergazdája nem engedélyezi, hogy a munkaprofil <xliff:g id="NUMBER">%3$d</xliff:g> napnál tovább kikapcsolva legyen."</string>
+ <string name="personal_apps_suspended_turn_profile_on" msgid="2758012869627513689">"Bekapcsolás"</string>
<string name="me" msgid="6207584824693813140">"Saját"</string>
<string name="power_dialog" product="tablet" msgid="8333207765671417261">"Táblagép beállításai"</string>
<string name="power_dialog" product="tv" msgid="7792839006640933763">"Android TV beállításai"</string>
diff --git a/core/res/res/values-hy/strings.xml b/core/res/res/values-hy/strings.xml
index ad5ae22a0f38..1fb9a62025bb 100644
--- a/core/res/res/values-hy/strings.xml
+++ b/core/res/res/values-hy/strings.xml
@@ -202,10 +202,8 @@
<string name="printing_disabled_by" msgid="3517499806528864633">"Տպումն անջատված է <xliff:g id="OWNER_APP">%s</xliff:g> հավելվածի կողմից։"</string>
<string name="personal_apps_suspension_title" msgid="7561416677884286600">"Միացրեք աշխատանքային պորֆիլը"</string>
<string name="personal_apps_suspension_text" msgid="6115455688932935597">"Անձնական հավելվածներն արգելափակված կլինեն, մինչև չմիացնեք ձեր աշխատանքային պրոֆիլը"</string>
- <!-- no translation found for personal_apps_suspension_soon_text (8123898693479590) -->
- <skip />
- <!-- no translation found for personal_apps_suspended_turn_profile_on (2758012869627513689) -->
- <skip />
+ <string name="personal_apps_suspension_soon_text" msgid="8123898693479590">"Անձնական հավելվածները <xliff:g id="DATE">%1$s</xliff:g>-ին ժամը <xliff:g id="TIME">%2$s</xliff:g> կարգելափակվեն։ Ձեր ՏՏ ադմինիստրատորը չի թույլատրում, որ ձեր աշխատանքային պրոֆիլը <xliff:g id="NUMBER">%3$d</xliff:g> օրից ավել անջատված մնա։"</string>
+ <string name="personal_apps_suspended_turn_profile_on" msgid="2758012869627513689">"Միացնել"</string>
<string name="me" msgid="6207584824693813140">"Իմ"</string>
<string name="power_dialog" product="tablet" msgid="8333207765671417261">"Պլանշետի ընտրանքները"</string>
<string name="power_dialog" product="tv" msgid="7792839006640933763">"Android TV-ի կարգավորումներ"</string>
@@ -1131,7 +1129,7 @@
<string name="whichViewApplicationNamed" msgid="415164730629690105">"Բացել հավելվածով՝ %1$s"</string>
<string name="whichViewApplicationLabel" msgid="7367556735684742409">"Բացել"</string>
<string name="whichOpenHostLinksWith" msgid="7645631470199397485">"<xliff:g id="HOST">%1$s</xliff:g> տեսակի հղումները բացել…"</string>
- <string name="whichOpenLinksWith" msgid="1120936181362907258">"Հղումները բացել…"</string>
+ <string name="whichOpenLinksWith" msgid="1120936181362907258">"Հղումները բացել այս հավելվածով…"</string>
<string name="whichOpenLinksWithApp" msgid="6917864367861910086">"Հղումները բացել <xliff:g id="APPLICATION">%1$s</xliff:g> դիտարկիչում"</string>
<string name="whichOpenHostLinksWithApp" msgid="2401668560768463004">"<xliff:g id="HOST">%1$s</xliff:g> տեսակի հղումները բացել <xliff:g id="APPLICATION">%2$s</xliff:g> դիտարկիչում"</string>
<string name="whichGiveAccessToApplicationLabel" msgid="7805857277166106236">"Թույլատրել"</string>
diff --git a/core/res/res/values-in/strings.xml b/core/res/res/values-in/strings.xml
index f031ed8e5ea2..9fbd73ea1269 100644
--- a/core/res/res/values-in/strings.xml
+++ b/core/res/res/values-in/strings.xml
@@ -202,10 +202,8 @@
<string name="printing_disabled_by" msgid="3517499806528864633">"Fitur pencetakan dinonaktifkan oleh <xliff:g id="OWNER_APP">%s</xliff:g>."</string>
<string name="personal_apps_suspension_title" msgid="7561416677884286600">"Aktifkan profil kerja Anda"</string>
<string name="personal_apps_suspension_text" msgid="6115455688932935597">"Aplikasi pribadi Anda diblokir hingga Anda mengaktifkan profil kerja Anda"</string>
- <!-- no translation found for personal_apps_suspension_soon_text (8123898693479590) -->
- <skip />
- <!-- no translation found for personal_apps_suspended_turn_profile_on (2758012869627513689) -->
- <skip />
+ <string name="personal_apps_suspension_soon_text" msgid="8123898693479590">"Aplikasi pribadi akan diblokir pada tanggal <xliff:g id="DATE">%1$s</xliff:g> pukul <xliff:g id="TIME">%2$s</xliff:g>. Admin IT tidak mengizinkan profil kerja Anda nonaktif selama lebih dari <xliff:g id="NUMBER">%3$d</xliff:g> hari."</string>
+ <string name="personal_apps_suspended_turn_profile_on" msgid="2758012869627513689">"Aktifkan"</string>
<string name="me" msgid="6207584824693813140">"Saya"</string>
<string name="power_dialog" product="tablet" msgid="8333207765671417261">"Opsi tablet"</string>
<string name="power_dialog" product="tv" msgid="7792839006640933763">"Opsi Android TV"</string>
@@ -1901,7 +1899,7 @@
<string name="profile_encrypted_title" msgid="9001208667521266472">"Beberapa fitur tidak dapat digunakan"</string>
<string name="profile_encrypted_detail" msgid="5279730442756849055">"Profil kerja terkunci"</string>
<string name="profile_encrypted_message" msgid="1128512616293157802">"Ketuk untuk membuka kunci profil kerja"</string>
- <string name="usb_mtp_launch_notification_title" msgid="774319638256707227">"Tersambung ke <xliff:g id="PRODUCT_NAME">%1$s</xliff:g>"</string>
+ <string name="usb_mtp_launch_notification_title" msgid="774319638256707227">"Terhubung ke <xliff:g id="PRODUCT_NAME">%1$s</xliff:g>"</string>
<string name="usb_mtp_launch_notification_description" msgid="6942535713629852684">"Ketuk untuk melihat file"</string>
<string name="pin_target" msgid="8036028973110156895">"Pasang pin"</string>
<string name="pin_specific_target" msgid="7824671240625957415">"Pasang pin <xliff:g id="LABEL">%1$s</xliff:g>"</string>
diff --git a/core/res/res/values-is/strings.xml b/core/res/res/values-is/strings.xml
index c16e1d11608d..82d6206ab625 100644
--- a/core/res/res/values-is/strings.xml
+++ b/core/res/res/values-is/strings.xml
@@ -202,10 +202,8 @@
<string name="printing_disabled_by" msgid="3517499806528864633">"<xliff:g id="OWNER_APP">%s</xliff:g> lokaði á prentun."</string>
<string name="personal_apps_suspension_title" msgid="7561416677884286600">"Kveiktu á vinnusniði"</string>
<string name="personal_apps_suspension_text" msgid="6115455688932935597">"Lokað er á forrit til einkanota þar til þú kveikir á vinnusniði"</string>
- <!-- no translation found for personal_apps_suspension_soon_text (8123898693479590) -->
- <skip />
- <!-- no translation found for personal_apps_suspended_turn_profile_on (2758012869627513689) -->
- <skip />
+ <string name="personal_apps_suspension_soon_text" msgid="8123898693479590">"Lokað verður á forrit til einkanota <xliff:g id="DATE">%1$s</xliff:g> kl. <xliff:g id="TIME">%2$s</xliff:g>. Kerfisstjórinn þinn leyfir ekki að slökkt sé á vinnusniðinu í meira en <xliff:g id="NUMBER">%3$d</xliff:g> daga."</string>
+ <string name="personal_apps_suspended_turn_profile_on" msgid="2758012869627513689">"Kveikja"</string>
<string name="me" msgid="6207584824693813140">"Ég"</string>
<string name="power_dialog" product="tablet" msgid="8333207765671417261">"Valkostir spjaldtölvu"</string>
<string name="power_dialog" product="tv" msgid="7792839006640933763">"Valkostir Android TV"</string>
@@ -2032,7 +2030,7 @@
<item quantity="one"><xliff:g id="FILE_NAME_2">%s</xliff:g> + <xliff:g id="COUNT_3">%d</xliff:g> skrá</item>
<item quantity="other"><xliff:g id="FILE_NAME_2">%s</xliff:g> + <xliff:g id="COUNT_3">%d</xliff:g> skrá</item>
</plurals>
- <string name="chooser_no_direct_share_targets" msgid="1511722103987329028">"Engar tillögur um einstaklinga til að deila með"</string>
+ <string name="chooser_no_direct_share_targets" msgid="1511722103987329028">"Engar tillögur um fólk til að deila með"</string>
<string name="chooser_all_apps_button_label" msgid="3230427756238666328">"Forritalisti"</string>
<string name="usb_device_resolve_prompt_warn" msgid="325871329788064199">"Þetta forrit hefur ekki fengið heimild fyrir upptöku en gæti tekið upp hljóð í gegnum þetta USB-tæki."</string>
<string name="accessibility_system_action_home_label" msgid="3234748160850301870">"Heim"</string>
diff --git a/core/res/res/values-it/strings.xml b/core/res/res/values-it/strings.xml
index 61983db358c3..b6a850d10fef 100644
--- a/core/res/res/values-it/strings.xml
+++ b/core/res/res/values-it/strings.xml
@@ -202,10 +202,8 @@
<string name="printing_disabled_by" msgid="3517499806528864633">"Stampa disattivata da <xliff:g id="OWNER_APP">%s</xliff:g>."</string>
<string name="personal_apps_suspension_title" msgid="7561416677884286600">"Attiva il profilo di lavoro"</string>
<string name="personal_apps_suspension_text" msgid="6115455688932935597">"Le tue app personali sono bloccate fino all\'attivazione del tuo profilo di lavoro"</string>
- <!-- no translation found for personal_apps_suspension_soon_text (8123898693479590) -->
- <skip />
- <!-- no translation found for personal_apps_suspended_turn_profile_on (2758012869627513689) -->
- <skip />
+ <string name="personal_apps_suspension_soon_text" msgid="8123898693479590">"Le app personali verranno bloccate il giorno <xliff:g id="DATE">%1$s</xliff:g> alle ore <xliff:g id="TIME">%2$s</xliff:g>. L\'amministratore IT non consente di mantenere disattivato il profilo di lavoro per più di <xliff:g id="NUMBER">%3$d</xliff:g> giorni."</string>
+ <string name="personal_apps_suspended_turn_profile_on" msgid="2758012869627513689">"Attiva"</string>
<string name="me" msgid="6207584824693813140">"Io"</string>
<string name="power_dialog" product="tablet" msgid="8333207765671417261">"Opzioni tablet"</string>
<string name="power_dialog" product="tv" msgid="7792839006640933763">"Opzioni Android TV"</string>
@@ -2057,10 +2055,10 @@
<string name="resolver_work_tab" msgid="2690019516263167035">"Lavoro"</string>
<string name="resolver_personal_tab_accessibility" msgid="5739524949153091224">"Visualizzazione personale"</string>
<string name="resolver_work_tab_accessibility" msgid="4753168230363802734">"Visualizzazione di lavoro"</string>
- <string name="resolver_cant_share_with_work_apps" msgid="637686613606502219">"Impossibile condividere questi contenuti con app di lavoro"</string>
- <string name="resolver_cant_share_with_work_apps_explanation" msgid="3332302070341130545">"L\'amministratore IT non ti consente di condividere questi contenuti con app nel tuo profilo di lavoro"</string>
- <string name="resolver_cant_access_work_apps" msgid="2455757966397563223">"Impossibile aprire questi contenuti con app di lavoro"</string>
- <string name="resolver_cant_access_work_apps_explanation" msgid="3626983885525445790">"L\'amministratore IT non ti consente di aprire questi contenuti con app nel tuo profilo di lavoro"</string>
+ <string name="resolver_cant_share_with_work_apps" msgid="637686613606502219">"Impossibile condividere questi contenuti con le app di lavoro"</string>
+ <string name="resolver_cant_share_with_work_apps_explanation" msgid="3332302070341130545">"L\'amministratore IT non ti consente di condividere questi contenuti con le app nel tuo profilo di lavoro"</string>
+ <string name="resolver_cant_access_work_apps" msgid="2455757966397563223">"Impossibile aprire questi contenuti con le app di lavoro"</string>
+ <string name="resolver_cant_access_work_apps_explanation" msgid="3626983885525445790">"L\'amministratore IT non ti consente di aprire questi contenuti con le app nel tuo profilo di lavoro"</string>
<string name="resolver_cant_share_with_personal_apps" msgid="3079139799233316203">"Impossibile condividere questi contenuti con app personali"</string>
<string name="resolver_cant_share_with_personal_apps_explanation" msgid="2959282422751315171">"L\'amministratore IT non ti consente di condividere questi contenuti con app nel tuo profilo personale"</string>
<string name="resolver_cant_access_personal_apps" msgid="648291604475669395">"Impossibile aprire questi contenuti con app personali"</string>
diff --git a/core/res/res/values-iw/strings.xml b/core/res/res/values-iw/strings.xml
index 92bde45559d8..10d3f4383069 100644
--- a/core/res/res/values-iw/strings.xml
+++ b/core/res/res/values-iw/strings.xml
@@ -206,10 +206,8 @@
<string name="printing_disabled_by" msgid="3517499806528864633">"ההדפסה הושבתה על ידי <xliff:g id="OWNER_APP">%s</xliff:g>."</string>
<string name="personal_apps_suspension_title" msgid="7561416677884286600">"הפעלה של פרופיל העבודה שלך"</string>
<string name="personal_apps_suspension_text" msgid="6115455688932935597">"האפליקציות שלך לשימוש אישי יהיו חסומות עד להפעלת פרופיל העבודה"</string>
- <!-- no translation found for personal_apps_suspension_soon_text (8123898693479590) -->
- <skip />
- <!-- no translation found for personal_apps_suspended_turn_profile_on (2758012869627513689) -->
- <skip />
+ <string name="personal_apps_suspension_soon_text" msgid="8123898693479590">"‏אפליקציות לשימוש אישי ייחסמו ב-<xliff:g id="DATE">%1$s</xliff:g> בשעה <xliff:g id="TIME">%2$s</xliff:g>. מנהל ה-IT לא מתיר השבתה של יותר מ-<xliff:g id="NUMBER">%3$d</xliff:g> ימים של פרופיל העבודה."</string>
+ <string name="personal_apps_suspended_turn_profile_on" msgid="2758012869627513689">"הפעלה"</string>
<string name="me" msgid="6207584824693813140">"אני"</string>
<string name="power_dialog" product="tablet" msgid="8333207765671417261">"אפשרויות טאבלט"</string>
<string name="power_dialog" product="tv" msgid="7792839006640933763">"‏אפשרויות Android TV"</string>
diff --git a/core/res/res/values-ja/strings.xml b/core/res/res/values-ja/strings.xml
index 540f01f5e1b1..7f27e648b4d7 100644
--- a/core/res/res/values-ja/strings.xml
+++ b/core/res/res/values-ja/strings.xml
@@ -202,10 +202,8 @@
<string name="printing_disabled_by" msgid="3517499806528864633">"「<xliff:g id="OWNER_APP">%s</xliff:g>」により印刷は無効にされています。"</string>
<string name="personal_apps_suspension_title" msgid="7561416677884286600">"仕事用プロファイルを ON にする"</string>
<string name="personal_apps_suspension_text" msgid="6115455688932935597">"個人用アプリは、仕事用プロファイルを ON にしない限りブロックされます"</string>
- <!-- no translation found for personal_apps_suspension_soon_text (8123898693479590) -->
- <skip />
- <!-- no translation found for personal_apps_suspended_turn_profile_on (2758012869627513689) -->
- <skip />
+ <string name="personal_apps_suspension_soon_text" msgid="8123898693479590">"個人用アプリは、<xliff:g id="DATE">%1$s</xliff:g> <xliff:g id="TIME">%2$s</xliff:g> にブロックされます。仕事用プロファイルを <xliff:g id="NUMBER">%3$d</xliff:g> 日を超えて OFF にすることは、IT 管理者から許可されていません。"</string>
+ <string name="personal_apps_suspended_turn_profile_on" msgid="2758012869627513689">"ON にする"</string>
<string name="me" msgid="6207584824693813140">"自分"</string>
<string name="power_dialog" product="tablet" msgid="8333207765671417261">"タブレットオプション"</string>
<string name="power_dialog" product="tv" msgid="7792839006640933763">"Android TV のオプション"</string>
@@ -1550,7 +1548,7 @@
<string name="launchBrowserDefault" msgid="6328349989932924119">"ブラウザを起動しますか?"</string>
<string name="SetupCallDefault" msgid="5581740063237175247">"通話を受けますか?"</string>
<string name="activity_resolver_use_always" msgid="5575222334666843269">"常時"</string>
- <string name="activity_resolver_use_once" msgid="948462794469672658">"1回のみ"</string>
+ <string name="activity_resolver_use_once" msgid="948462794469672658">"1 回のみ"</string>
<string name="activity_resolver_work_profiles_support" msgid="4071345609235361269">"%1$sは仕事用プロファイルをサポートしていません"</string>
<string name="default_audio_route_name" product="tablet" msgid="367936735632195517">"タブレット"</string>
<string name="default_audio_route_name" product="tv" msgid="4908971385068087367">"テレビ"</string>
diff --git a/core/res/res/values-ka/strings.xml b/core/res/res/values-ka/strings.xml
index 41d42e7733b5..ed31a1cd3bed 100644
--- a/core/res/res/values-ka/strings.xml
+++ b/core/res/res/values-ka/strings.xml
@@ -202,10 +202,8 @@
<string name="printing_disabled_by" msgid="3517499806528864633">"ბეჭდვა გათიშულია <xliff:g id="OWNER_APP">%s</xliff:g>-ის მიერ."</string>
<string name="personal_apps_suspension_title" msgid="7561416677884286600">"ჩართეთ სამსახურის პროფილი"</string>
<string name="personal_apps_suspension_text" msgid="6115455688932935597">"თქვენი პირადი აპები დაბლოკილი იქნება, სანამ სამსახურის პროფილს არ ჩართავთ"</string>
- <!-- no translation found for personal_apps_suspension_soon_text (8123898693479590) -->
- <skip />
- <!-- no translation found for personal_apps_suspended_turn_profile_on (2758012869627513689) -->
- <skip />
+ <string name="personal_apps_suspension_soon_text" msgid="8123898693479590">"პირადი აპები დაიბლოკება: <xliff:g id="DATE">%1$s</xliff:g>, <xliff:g id="TIME">%2$s</xliff:g>. თქვენი IT ადმინისტრატორი თქვენს სამსახურის პროფილს არ აძლევს უფლებას, გამორთული იყოს <xliff:g id="NUMBER">%3$d</xliff:g> დღეზე მეტ ხანს."</string>
+ <string name="personal_apps_suspended_turn_profile_on" msgid="2758012869627513689">"ჩართვა"</string>
<string name="me" msgid="6207584824693813140">"მე"</string>
<string name="power_dialog" product="tablet" msgid="8333207765671417261">"ტაბლეტის პარამეტრები"</string>
<string name="power_dialog" product="tv" msgid="7792839006640933763">"Android TV ვარიანტები"</string>
diff --git a/core/res/res/values-kk/strings.xml b/core/res/res/values-kk/strings.xml
index 7cee31ab6ea7..07579ad0ae0f 100644
--- a/core/res/res/values-kk/strings.xml
+++ b/core/res/res/values-kk/strings.xml
@@ -202,10 +202,8 @@
<string name="printing_disabled_by" msgid="3517499806528864633">"Басып шығаруды <xliff:g id="OWNER_APP">%s</xliff:g> өшірді."</string>
<string name="personal_apps_suspension_title" msgid="7561416677884286600">"Жұмыс профиліңізді қосыңыз"</string>
<string name="personal_apps_suspension_text" msgid="6115455688932935597">"Жұмыс профиліңізді қоспайынша, жеке қолданбалар бөгеледі."</string>
- <!-- no translation found for personal_apps_suspension_soon_text (8123898693479590) -->
- <skip />
- <!-- no translation found for personal_apps_suspended_turn_profile_on (2758012869627513689) -->
- <skip />
+ <string name="personal_apps_suspension_soon_text" msgid="8123898693479590">"Жеке қолданбалардың бөгелетін уақыты: <xliff:g id="DATE">%1$s</xliff:g>, сағат <xliff:g id="TIME">%2$s</xliff:g>. Әкімші жұмыс профилін <xliff:g id="NUMBER">%3$d</xliff:g> күннен аса мерзімге өшіруге рұқсат бермейді."</string>
+ <string name="personal_apps_suspended_turn_profile_on" msgid="2758012869627513689">"Қосу"</string>
<string name="me" msgid="6207584824693813140">"Мен"</string>
<string name="power_dialog" product="tablet" msgid="8333207765671417261">"Планшет опциялары"</string>
<string name="power_dialog" product="tv" msgid="7792839006640933763">"Android TV опциялары"</string>
diff --git a/core/res/res/values-km/strings.xml b/core/res/res/values-km/strings.xml
index 3fe076695642..4fd0338b1f63 100644
--- a/core/res/res/values-km/strings.xml
+++ b/core/res/res/values-km/strings.xml
@@ -202,10 +202,8 @@
<string name="printing_disabled_by" msgid="3517499806528864633">"ការបោះពុម្ព​ត្រូវបាន​បិទ​ដោយ <xliff:g id="OWNER_APP">%s</xliff:g> ។"</string>
<string name="personal_apps_suspension_title" msgid="7561416677884286600">"បើកកម្រងព័ត៌មានការងាររបស់អ្នក"</string>
<string name="personal_apps_suspension_text" msgid="6115455688932935597">"កម្មវិធីផ្ទាល់ខ្លួន​របស់អ្នកត្រូវ​បានទប់ស្កាត់ រហូតទាល់តែ​អ្នកបើក​កម្រងព័ត៌មាន​ការងាររបស់អ្នក"</string>
- <!-- no translation found for personal_apps_suspension_soon_text (8123898693479590) -->
- <skip />
- <!-- no translation found for personal_apps_suspended_turn_profile_on (2758012869627513689) -->
- <skip />
+ <string name="personal_apps_suspension_soon_text" msgid="8123898693479590">"កម្មវិធីផ្ទាល់ខ្លួន​នឹងត្រូវបាន​ទប់ស្កាត់​នៅថ្ងៃទី <xliff:g id="DATE">%1$s</xliff:g> នៅម៉ោង <xliff:g id="TIME">%2$s</xliff:g>។ អ្នកគ្រប់គ្រង​ផ្នែកព័ត៌មានវិទ្យា​របស់អ្នក​មិនអនុញ្ញាតឱ្យ​បន្តបិទ​កម្រងព័ត៌មាន​ការងារ​របស់អ្នក​លើសពី <xliff:g id="NUMBER">%3$d</xliff:g> ថ្ងៃ​ទេ។"</string>
+ <string name="personal_apps_suspended_turn_profile_on" msgid="2758012869627513689">"បើក"</string>
<string name="me" msgid="6207584824693813140">"ខ្ញុំ"</string>
<string name="power_dialog" product="tablet" msgid="8333207765671417261">"ជម្រើស​កុំព្យូទ័រ​បន្ទះ"</string>
<string name="power_dialog" product="tv" msgid="7792839006640933763">"ជម្រើស Android TV"</string>
@@ -1132,10 +1130,10 @@
<string name="whichViewApplication" msgid="5733194231473132945">"បើក​ជា​មួយ"</string>
<string name="whichViewApplicationNamed" msgid="415164730629690105">"បើក​ជាមួយ %1$s"</string>
<string name="whichViewApplicationLabel" msgid="7367556735684742409">"បើក"</string>
- <string name="whichOpenHostLinksWith" msgid="7645631470199397485">"បើក​តំណ <xliff:g id="HOST">%1$s</xliff:g> ជាមួយ"</string>
- <string name="whichOpenLinksWith" msgid="1120936181362907258">"បើកតំណជាមួយ"</string>
- <string name="whichOpenLinksWithApp" msgid="6917864367861910086">"បើក​តំណជាមួយ <xliff:g id="APPLICATION">%1$s</xliff:g>"</string>
- <string name="whichOpenHostLinksWithApp" msgid="2401668560768463004">"បើក​តំណ <xliff:g id="HOST">%1$s</xliff:g> ជាមួយ <xliff:g id="APPLICATION">%2$s</xliff:g>"</string>
+ <string name="whichOpenHostLinksWith" msgid="7645631470199397485">"បើក​តំណ <xliff:g id="HOST">%1$s</xliff:g> ដោយប្រើ"</string>
+ <string name="whichOpenLinksWith" msgid="1120936181362907258">"បើកតំណដោយប្រើ"</string>
+ <string name="whichOpenLinksWithApp" msgid="6917864367861910086">"បើក​តំណដោយប្រើ <xliff:g id="APPLICATION">%1$s</xliff:g>"</string>
+ <string name="whichOpenHostLinksWithApp" msgid="2401668560768463004">"បើក​តំណ <xliff:g id="HOST">%1$s</xliff:g> ដោយប្រើ <xliff:g id="APPLICATION">%2$s</xliff:g>"</string>
<string name="whichGiveAccessToApplicationLabel" msgid="7805857277166106236">"ផ្តល់​សិទ្ធិ​ចូល​ប្រើ"</string>
<string name="whichEditApplication" msgid="6191568491456092812">"កែសម្រួល​ជាមួយ"</string>
<string name="whichEditApplicationNamed" msgid="8096494987978521514">"កែសម្រួល​ជាមួយ​ %1$s"</string>
@@ -1230,7 +1228,7 @@
<string name="volume_unknown" msgid="4041914008166576293">"កម្រិត​សំឡេង"</string>
<string name="volume_icon_description_bluetooth" msgid="7540388479345558400">"កម្រិត​សំឡេង​ប៊្លូធូស"</string>
<string name="volume_icon_description_ringer" msgid="2187800636867423459">"កម្រិត​សំឡេង​រោទ៍"</string>
- <string name="volume_icon_description_incall" msgid="4491255105381227919">"កម្រិត​សំឡេង​ហៅ"</string>
+ <string name="volume_icon_description_incall" msgid="4491255105381227919">"កម្រិត​សំឡេង​ហៅទូរសព្ទ"</string>
<string name="volume_icon_description_media" msgid="4997633254078171233">"កម្រិត​សំឡេង​មេឌៀ"</string>
<string name="volume_icon_description_notification" msgid="579091344110747279">"កម្រិត​សំឡេង​ការ​ជូន​ដំណឹង"</string>
<string name="ringtone_default" msgid="9118299121288174597">"សំឡេង​រោទ៍​លំនាំដើម"</string>
diff --git a/core/res/res/values-kn/strings.xml b/core/res/res/values-kn/strings.xml
index bc896d61a43b..a1060808172a 100644
--- a/core/res/res/values-kn/strings.xml
+++ b/core/res/res/values-kn/strings.xml
@@ -202,10 +202,8 @@
<string name="printing_disabled_by" msgid="3517499806528864633">"<xliff:g id="OWNER_APP">%s</xliff:g> ಮೂಲಕ ಪ್ರಿಂಟಿಂಗ್ ಅನ್ನು ನಿಷ್ಕ್ರಿಯಗೊಳಿಸಲಾಗಿದೆ."</string>
<string name="personal_apps_suspension_title" msgid="7561416677884286600">"ಉದ್ಯೋಗ ಪ್ರೊಫೈಲ್ ಸಕ್ರಿಯಗೊಳಿಸಿ"</string>
<string name="personal_apps_suspension_text" msgid="6115455688932935597">"ನಿಮ್ಮ ಉದ್ಯೋಗದ ಪ್ರೊಫೈಲ್ ಅನ್ನು ಸಕ್ರಿಯಗೊಳಿಸುವವರೆಗೆ ನಿಮ್ಮ ವೈಯಕ್ತಿಕ ಆ್ಯಪ್‌ಗಳನ್ನು ನಿರ್ಬಂಧಿಸಲಾಗುತ್ತದೆ"</string>
- <!-- no translation found for personal_apps_suspension_soon_text (8123898693479590) -->
- <skip />
- <!-- no translation found for personal_apps_suspended_turn_profile_on (2758012869627513689) -->
- <skip />
+ <string name="personal_apps_suspension_soon_text" msgid="8123898693479590">"ವೈಯಕ್ತಿಕ ಆ್ಯಪ್‌ಗಳನ್ನು <xliff:g id="DATE">%1$s</xliff:g> ರಂದು <xliff:g id="TIME">%2$s</xliff:g> ಸಮಯಕ್ಕೆ ನಿರ್ಬಂಧಿಸಲಾಗುತ್ತದೆ. ನಿಮ್ಮ ಐಟಿ ನಿರ್ವಾಹಕರು ನಿಮ್ಮ ಕೆಲಸದ ಪ್ರೊಫೈಲ್ ಅನ್ನು <xliff:g id="NUMBER">%3$d</xliff:g> ದಿನಗಳಿಗಿಂತ ಹೆಚ್ಚು ಕಾಲ ಉಳಿಯಲು ಅನುಮತಿಸುವುದಿಲ್ಲ."</string>
+ <string name="personal_apps_suspended_turn_profile_on" msgid="2758012869627513689">"ಆನ್"</string>
<string name="me" msgid="6207584824693813140">"ನಾನು"</string>
<string name="power_dialog" product="tablet" msgid="8333207765671417261">"ಟ್ಯಾಬ್ಲೆಟ್ ಆಯ್ಕೆಗಳು"</string>
<string name="power_dialog" product="tv" msgid="7792839006640933763">"Android TV ಆಯ್ಕೆಗಳು"</string>
@@ -1308,7 +1306,7 @@
<string name="usb_power_notification_message" msgid="7284765627437897702">"ಸಂಪರ್ಕಗೊಂಡಿರುವ ಸಾಧನವನ್ನು ಚಾರ್ಜ್ ಮಾಡಲಾಗುತ್ತಿದೆ. ಹೆಚ್ಚಿನ ಆಯ್ಕೆಗಳಿಗಾಗಿ ಟ್ಯಾಪ್ ಮಾಡಿ."</string>
<string name="usb_unsupported_audio_accessory_title" msgid="2335775548086533065">"ಅನ್‌ಲಾಗ್ ಆಡಿಯೋ ಪರಿಕರ ಪತ್ತೆಯಾಗಿದೆ"</string>
<string name="usb_unsupported_audio_accessory_message" msgid="1300168007129796621">"ಲಗತ್ತಿಸಲಾದ ಸಾಧನವು ಈ ಫೋನಿನೊಂದಿಗೆ ಹೊಂದಿಕೆಯಾಗುವುದಿಲ್ಲ. ಇನ್ನಷ್ಟು ತಿಳಿಯಲು ಟ್ಯಾಪ್ ಮಾಡಿ."</string>
- <string name="adb_active_notification_title" msgid="408390247354560331">"USB ಡೀಬಗಿಂಗ್‌‌ ಸಂಪರ್ಕಗೊಂಡಿದೆ"</string>
+ <string name="adb_active_notification_title" msgid="408390247354560331">"USB ಡೀಬಗ್‌ ಮಾಡುವಿಕೆ ಸಂಪರ್ಕಗೊಂಡಿದೆ"</string>
<string name="adb_active_notification_message" msgid="5617264033476778211">"USB ಡೀಬಗ್‌ ಮಾಡುವಿಕೆಯನ್ನು ಆಫ್‌ ಮಾಡಲು ಟ್ಯಾಪ್‌ ಮಾಡಿ"</string>
<string name="adb_active_notification_message" product="tv" msgid="6624498401272780855">"USB ಡೀಬಗ್‌ ಮಾಡುವಿಕೆಯನ್ನು ನಿಷ್ಕ್ರಿಯಗೊಳಿಸಲು ಆಯ್ಕೆ ಮಾಡಿ."</string>
<string name="adbwifi_active_notification_title" msgid="6147343659168302473">"ವೈರ್‌ಲೆಸ್ ಡೀಬಗ್‌ ಮಾಡುವಿಕೆಯನ್ನು ಕನೆಕ್ಟ್ ಮಾಡಲಾಗಿದೆ"</string>
@@ -2032,7 +2030,7 @@
<item quantity="one"><xliff:g id="FILE_NAME_2">%s</xliff:g> + <xliff:g id="COUNT_3">%d</xliff:g> ಫೈಲ್‌ಗಳು</item>
<item quantity="other"><xliff:g id="FILE_NAME_2">%s</xliff:g> + <xliff:g id="COUNT_3">%d</xliff:g> ಫೈಲ್‌ಗಳು</item>
</plurals>
- <string name="chooser_no_direct_share_targets" msgid="1511722103987329028">"ಹಂಚಿಕೊಳ್ಳಲು, ಯಾವುದೇ ಶಿಫಾರಸು ಮಾಡಲಾದ ಜನರಿಲ್ಲ"</string>
+ <string name="chooser_no_direct_share_targets" msgid="1511722103987329028">"ಹಂಚಿಕೊಳ್ಳಲು ಶಿಫಾರಸು ಮಾಡಲಾದವರು ಯಾರೂ ಇಲ್ಲ"</string>
<string name="chooser_all_apps_button_label" msgid="3230427756238666328">"ಆ್ಯಪ್‌ಗಳ ಪಟ್ಟಿ"</string>
<string name="usb_device_resolve_prompt_warn" msgid="325871329788064199">"ಈ ಆ್ಯಪ್‌ಗೆ ರೆಕಾರ್ಡ್ ಅನುಮತಿಯನ್ನು ನೀಡಲಾಗಿಲ್ಲ, ಆದರೆ ಈ USB ಸಾಧನದ ಮೂಲಕ ಆಡಿಯೊವನ್ನು ಸೆರೆಹಿಡಿಯಬಲ್ಲದು."</string>
<string name="accessibility_system_action_home_label" msgid="3234748160850301870">"ಹೋಮ್"</string>
diff --git a/core/res/res/values-ko/strings.xml b/core/res/res/values-ko/strings.xml
index 87ed01943aa8..0fe5925e3e25 100644
--- a/core/res/res/values-ko/strings.xml
+++ b/core/res/res/values-ko/strings.xml
@@ -202,10 +202,8 @@
<string name="printing_disabled_by" msgid="3517499806528864633">"<xliff:g id="OWNER_APP">%s</xliff:g>에 의해 사용 중지되었습니다."</string>
<string name="personal_apps_suspension_title" msgid="7561416677884286600">"직장 프로필 사용 설정"</string>
<string name="personal_apps_suspension_text" msgid="6115455688932935597">"직장 프로필을 사용 설정할 때까지 개인 앱이 차단됩니다."</string>
- <!-- no translation found for personal_apps_suspension_soon_text (8123898693479590) -->
- <skip />
- <!-- no translation found for personal_apps_suspended_turn_profile_on (2758012869627513689) -->
- <skip />
+ <string name="personal_apps_suspension_soon_text" msgid="8123898693479590">"개인 앱이 <xliff:g id="DATE">%1$s</xliff:g> <xliff:g id="TIME">%2$s</xliff:g>에 차단됩니다. IT 관리자가 <xliff:g id="NUMBER">%3$d</xliff:g>일 넘게 직장 프로필을 중지하도록 허용하지 않습니다."</string>
+ <string name="personal_apps_suspended_turn_profile_on" msgid="2758012869627513689">"사용 설정"</string>
<string name="me" msgid="6207584824693813140">"나"</string>
<string name="power_dialog" product="tablet" msgid="8333207765671417261">"태블릿 옵션"</string>
<string name="power_dialog" product="tv" msgid="7792839006640933763">"Android TV 옵션"</string>
@@ -2057,10 +2055,10 @@
<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_cant_share_with_work_apps" msgid="637686613606502219">"직장 앱과 공유할 수 없는 콘텐츠"</string>
- <string name="resolver_cant_share_with_work_apps_explanation" msgid="3332302070341130545">"IT 관리자가 직장 프로필의 앱에서 이 콘텐츠를 공유하도록 허용하지 않습니다."</string>
- <string name="resolver_cant_access_work_apps" msgid="2455757966397563223">"직장 앱으로 열 수 없는 콘텐츠"</string>
- <string name="resolver_cant_access_work_apps_explanation" msgid="3626983885525445790">"IT 관리자가 직장 프로필의 앱에서 이 콘텐츠를 열도록 허용하지 않습니다."</string>
+ <string name="resolver_cant_share_with_work_apps" msgid="637686613606502219">"직장 앱과 공유할 수 없음"</string>
+ <string name="resolver_cant_share_with_work_apps_explanation" msgid="3332302070341130545">"IT 관리자가 이 콘텐츠를 직장 프로필의 앱과 공유할 수 있도록 허용하지 않았습니다."</string>
+ <string name="resolver_cant_access_work_apps" msgid="2455757966397563223">"직장 앱으로 열 수 없음"</string>
+ <string name="resolver_cant_access_work_apps_explanation" msgid="3626983885525445790">"IT 관리자가 이 콘텐츠를 직장 프로필의 앱에서 열 수 있도록 허용하지 않았습니다."</string>
<string name="resolver_cant_share_with_personal_apps" msgid="3079139799233316203">"개인 앱과 공유할 수 없는 콘텐츠"</string>
<string name="resolver_cant_share_with_personal_apps_explanation" msgid="2959282422751315171">"IT 관리자가 개인 프로필의 앱에서 이 콘텐츠를 공유하도록 허용하지 않습니다."</string>
<string name="resolver_cant_access_personal_apps" msgid="648291604475669395">"개인 앱으로 열 수 없는 콘텐츠"</string>
diff --git a/core/res/res/values-ky/strings.xml b/core/res/res/values-ky/strings.xml
index e3cdec901b26..dbbc14f706c0 100644
--- a/core/res/res/values-ky/strings.xml
+++ b/core/res/res/values-ky/strings.xml
@@ -202,10 +202,8 @@
<string name="printing_disabled_by" msgid="3517499806528864633">"Басып чыгаруу <xliff:g id="OWNER_APP">%s</xliff:g> тарабынан өчүрүлдү."</string>
<string name="personal_apps_suspension_title" msgid="7561416677884286600">"Жумуш профилиңизди күйгүзүңүз"</string>
<string name="personal_apps_suspension_text" msgid="6115455688932935597">"Жумуш профилиңизди күйгүзмөйүнчө жеке колдонмолоруңуз бөгөттөлгөн боюнча калат"</string>
- <!-- no translation found for personal_apps_suspension_soon_text (8123898693479590) -->
- <skip />
- <!-- no translation found for personal_apps_suspended_turn_profile_on (2758012869627513689) -->
- <skip />
+ <string name="personal_apps_suspension_soon_text" msgid="8123898693479590">"Жеке колдонмолор <xliff:g id="DATE">%1$s</xliff:g> саат <xliff:g id="TIME">%2$s</xliff:g> бөгөттөлөт. IT администраторуңуз жумуш профилиңизди <xliff:g id="NUMBER">%3$d</xliff:g> күндөн ашык убакытка өчүрүүгө уруксат бербейт."</string>
+ <string name="personal_apps_suspended_turn_profile_on" msgid="2758012869627513689">"Күйгүзүү"</string>
<string name="me" msgid="6207584824693813140">"Мен"</string>
<string name="power_dialog" product="tablet" msgid="8333207765671417261">"Планшет мүмкүнчүлүктөрү"</string>
<string name="power_dialog" product="tv" msgid="7792839006640933763">"Android TV параметрлери"</string>
@@ -2057,18 +2055,18 @@
<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_cant_share_with_work_apps" msgid="637686613606502219">"Бул мазмунду жумуш колдонмолору аркылуу бөлүшүүгө болбойт"</string>
- <string name="resolver_cant_share_with_work_apps_explanation" msgid="3332302070341130545">"IT администраторуңуз бул мазмунду жумуш профилиңиздеги колдонмолор аркылуу бөлүшүүгө тыюу салды"</string>
+ <string name="resolver_cant_share_with_work_apps" msgid="637686613606502219">"Бул нерсени жумуш колдонмолору аркылуу бөлүшүүгө болбойт"</string>
+ <string name="resolver_cant_share_with_work_apps_explanation" msgid="3332302070341130545">"IT администраторуңуз бул нерсени жумуш профилиңиздеги колдонмолор аркылуу бөлүшүүгө тыюу салды"</string>
<string name="resolver_cant_access_work_apps" msgid="2455757966397563223">"Жумуш колдонмолору менен ачууга болбойт"</string>
- <string name="resolver_cant_access_work_apps_explanation" msgid="3626983885525445790">"IT администраторуңуз бул мазмунду жумуш профилиңиздеги колдонмолор менен ачууга тыюу салды"</string>
+ <string name="resolver_cant_access_work_apps_explanation" msgid="3626983885525445790">"IT администраторуңуз бул нерсени жумуш профилиңиздеги колдонмолор менен ачууга тыюу салды"</string>
<string name="resolver_cant_share_with_personal_apps" msgid="3079139799233316203">"Бул мазмунду жеке колдонмолор аркылуу бөлүшүүгө болбойт"</string>
- <string name="resolver_cant_share_with_personal_apps_explanation" msgid="2959282422751315171">"IT администраторуңуз бул мазмунду жеке профилиңиздеги колдонмолор аркылуу бөлүшүүгө тыюу салды"</string>
+ <string name="resolver_cant_share_with_personal_apps_explanation" msgid="2959282422751315171">"IT администраторуңуз бул нерсени жеке профилиңиздеги колдонмолор аркылуу бөлүшүүгө тыюу салды"</string>
<string name="resolver_cant_access_personal_apps" msgid="648291604475669395">"Жеке колдонмолор менен ачууга болбойт"</string>
- <string name="resolver_cant_access_personal_apps_explanation" msgid="2298773629302296519">"IT администраторуңуз бул мазмунду жеке профилиңиздеги колдонмолор менен ачууга тыюу салды"</string>
+ <string name="resolver_cant_access_personal_apps_explanation" msgid="2298773629302296519">"IT администраторуңуз бул нерсени жеке профилиңиздеги колдонмолор менен ачууга тыюу салды"</string>
<string name="resolver_turn_on_work_apps" msgid="884910835250037247">"Жумуш профили тындырылган"</string>
<string name="resolver_switch_on_work" msgid="2873009160846966379">"Күйгүзүү"</string>
- <string name="resolver_no_work_apps_available_share" msgid="7933949011797699505">"Жумуш колдонмолору бул мазмунду колдоого алышпайт"</string>
- <string name="resolver_no_work_apps_available_resolve" msgid="1244844292366099399">"Жумуш колдонмолору бул мазмунду ача алышпайт"</string>
+ <string name="resolver_no_work_apps_available_share" msgid="7933949011797699505">"Бул нерсени колдоого ала турган жумуш колдонмолору жок"</string>
+ <string name="resolver_no_work_apps_available_resolve" msgid="1244844292366099399">"Бул нерсени ача турган жумуш колдонмолору жок"</string>
<string name="resolver_no_personal_apps_available_share" msgid="5639102815174748732">"Жеке колдонмолор бул мазмунду колдоого алышпайт"</string>
<string name="resolver_no_personal_apps_available_resolve" msgid="5120671970531446978">"Жеке колдонмолор бул мазмунду ача алышпайт"</string>
<string name="PERSOSUBSTATE_SIM_NETWORK_ENTRY" msgid="8050953231914637819">"SIM карта тармагынын кулпусун ачуучу PIN код"</string>
diff --git a/core/res/res/values-lo/strings.xml b/core/res/res/values-lo/strings.xml
index 521c1b175a22..278237954a53 100644
--- a/core/res/res/values-lo/strings.xml
+++ b/core/res/res/values-lo/strings.xml
@@ -202,10 +202,8 @@
<string name="printing_disabled_by" msgid="3517499806528864633">"ການພິມຖືກປິດໄວ້ໂດຍ <xliff:g id="OWNER_APP">%s</xliff:g>."</string>
<string name="personal_apps_suspension_title" msgid="7561416677884286600">"ເປີດໃຊ້​ໂປຣ​ໄຟລ໌​ບ່ອນ​ເຮັດ​ວຽກ"</string>
<string name="personal_apps_suspension_text" msgid="6115455688932935597">"ແອັບສ່ວນຕົວຂອງທ່ານຈະຖືກບລັອກໄວ້ຈົນກວ່າທ່ານຈະເປີດໃຊ້​ໂປຣ​ໄຟລ໌​ບ່ອນ​ເຮັດ​ວຽກຂອງທ່ານ"</string>
- <!-- no translation found for personal_apps_suspension_soon_text (8123898693479590) -->
- <skip />
- <!-- no translation found for personal_apps_suspended_turn_profile_on (2758012869627513689) -->
- <skip />
+ <string name="personal_apps_suspension_soon_text" msgid="8123898693479590">"ແອັບສ່ວນຕົວຈະຖືກບລັອກໃນວັນທີ <xliff:g id="DATE">%1$s</xliff:g> ເວລາ <xliff:g id="TIME">%2$s</xliff:g>. ຜູ້ເບິ່ງແຍງລະບົບໄອທີຂອງທ່ານບໍ່ອະນຸຍາດໃຫ້ປິດໂປຣໄຟລ໌ບ່ອນເຮັດວຽກຂອງທ່ານເກີນ <xliff:g id="NUMBER">%3$d</xliff:g> ມື້."</string>
+ <string name="personal_apps_suspended_turn_profile_on" msgid="2758012869627513689">"ເປີດໃຊ້"</string>
<string name="me" msgid="6207584824693813140">"ຂ້າພະເຈົ້າ"</string>
<string name="power_dialog" product="tablet" msgid="8333207765671417261">"ໂຕເລືອກແທັບເລັດ"</string>
<string name="power_dialog" product="tv" msgid="7792839006640933763">"ຕົວເລືອກ Android TV"</string>
diff --git a/core/res/res/values-lt/strings.xml b/core/res/res/values-lt/strings.xml
index c9c7b54489fd..a0137c165a4b 100644
--- a/core/res/res/values-lt/strings.xml
+++ b/core/res/res/values-lt/strings.xml
@@ -206,10 +206,8 @@
<string name="printing_disabled_by" msgid="3517499806528864633">"Neleidžiama spausdinti (<xliff:g id="OWNER_APP">%s</xliff:g>)."</string>
<string name="personal_apps_suspension_title" msgid="7561416677884286600">"Įjunkite darbo profilį"</string>
<string name="personal_apps_suspension_text" msgid="6115455688932935597">"Asmeninės programos bus užblokuotos, kol įjungsite darbo profilį"</string>
- <!-- no translation found for personal_apps_suspension_soon_text (8123898693479590) -->
- <skip />
- <!-- no translation found for personal_apps_suspended_turn_profile_on (2758012869627513689) -->
- <skip />
+ <string name="personal_apps_suspension_soon_text" msgid="8123898693479590">"Asmeninės programos bus užblokuotos <xliff:g id="DATE">%1$s</xliff:g>, <xliff:g id="TIME">%2$s</xliff:g>. IT administratorius neleidžia palikti darbo profilio išjungto ilgiau nei <xliff:g id="NUMBER">%3$d</xliff:g> d."</string>
+ <string name="personal_apps_suspended_turn_profile_on" msgid="2758012869627513689">"Įjungti"</string>
<string name="me" msgid="6207584824693813140">"Aš"</string>
<string name="power_dialog" product="tablet" msgid="8333207765671417261">"Planšetinio kompiuterio parinktys"</string>
<string name="power_dialog" product="tv" msgid="7792839006640933763">"„Android TV“ parinktys"</string>
diff --git a/core/res/res/values-lv/strings.xml b/core/res/res/values-lv/strings.xml
index b34538d6a18c..09942a99be37 100644
--- a/core/res/res/values-lv/strings.xml
+++ b/core/res/res/values-lv/strings.xml
@@ -204,10 +204,8 @@
<string name="printing_disabled_by" msgid="3517499806528864633">"Drukāšanu atspējoja <xliff:g id="OWNER_APP">%s</xliff:g>."</string>
<string name="personal_apps_suspension_title" msgid="7561416677884286600">"Darba profila ieslēgšana"</string>
<string name="personal_apps_suspension_text" msgid="6115455688932935597">"Jūsu personīgās lietotnes būs bloķētas, līdz ieslēgsiet savu darba profilu."</string>
- <!-- no translation found for personal_apps_suspension_soon_text (8123898693479590) -->
- <skip />
- <!-- no translation found for personal_apps_suspended_turn_profile_on (2758012869627513689) -->
- <skip />
+ <string name="personal_apps_suspension_soon_text" msgid="8123898693479590">"Personīgās lietotnes tiks bloķētas šādā datumā: <xliff:g id="DATE">%1$s</xliff:g>, plkst. <xliff:g id="TIME">%2$s</xliff:g>. Jūsu IT administrators neatļauj atspējot darba profilu ilgāk par <xliff:g id="NUMBER">%3$d</xliff:g> dienām."</string>
+ <string name="personal_apps_suspended_turn_profile_on" msgid="2758012869627513689">"Ieslēgt"</string>
<string name="me" msgid="6207584824693813140">"Man"</string>
<string name="power_dialog" product="tablet" msgid="8333207765671417261">"Planšetdatora opcijas"</string>
<string name="power_dialog" product="tv" msgid="7792839006640933763">"Android TV opcijas"</string>
diff --git a/core/res/res/values-mk/strings.xml b/core/res/res/values-mk/strings.xml
index 45e86e1fe928..bfad9e964b93 100644
--- a/core/res/res/values-mk/strings.xml
+++ b/core/res/res/values-mk/strings.xml
@@ -202,10 +202,8 @@
<string name="printing_disabled_by" msgid="3517499806528864633">"Печатењето е оневозможено од <xliff:g id="OWNER_APP">%s</xliff:g>."</string>
<string name="personal_apps_suspension_title" msgid="7561416677884286600">"Вклучете го работниот профил"</string>
<string name="personal_apps_suspension_text" msgid="6115455688932935597">"Вашите лични апликации се блокирани додека да го вклучите работниот профил"</string>
- <!-- no translation found for personal_apps_suspension_soon_text (8123898693479590) -->
- <skip />
- <!-- no translation found for personal_apps_suspended_turn_profile_on (2758012869627513689) -->
- <skip />
+ <string name="personal_apps_suspension_soon_text" msgid="8123898693479590">"Личните апликации ќе се блокираат на <xliff:g id="DATE">%1$s</xliff:g> во <xliff:g id="TIME">%2$s</xliff:g>. Вашиот IT администратор не дозволува вашиот работен профил да биде исклучен повеќе од <xliff:g id="NUMBER">%3$d</xliff:g> денови."</string>
+ <string name="personal_apps_suspended_turn_profile_on" msgid="2758012869627513689">"Вклучи"</string>
<string name="me" msgid="6207584824693813140">"Јас"</string>
<string name="power_dialog" product="tablet" msgid="8333207765671417261">"Опции на таблет"</string>
<string name="power_dialog" product="tv" msgid="7792839006640933763">"Опции на Android TV"</string>
@@ -1130,10 +1128,10 @@
<string name="whichViewApplication" msgid="5733194231473132945">"Отвори со"</string>
<string name="whichViewApplicationNamed" msgid="415164730629690105">"Отвори со %1$s"</string>
<string name="whichViewApplicationLabel" msgid="7367556735684742409">"Отвори"</string>
- <string name="whichOpenHostLinksWith" msgid="7645631470199397485">"Отворајте врски на <xliff:g id="HOST">%1$s</xliff:g> со"</string>
- <string name="whichOpenLinksWith" msgid="1120936181362907258">"Отворајте врски со"</string>
- <string name="whichOpenLinksWithApp" msgid="6917864367861910086">"Отворајте врски со <xliff:g id="APPLICATION">%1$s</xliff:g>"</string>
- <string name="whichOpenHostLinksWithApp" msgid="2401668560768463004">"Отворајте врски на <xliff:g id="HOST">%1$s</xliff:g> со <xliff:g id="APPLICATION">%2$s</xliff:g>"</string>
+ <string name="whichOpenHostLinksWith" msgid="7645631470199397485">"Отворајте линкови на <xliff:g id="HOST">%1$s</xliff:g> со"</string>
+ <string name="whichOpenLinksWith" msgid="1120936181362907258">"Отворајте линкови со"</string>
+ <string name="whichOpenLinksWithApp" msgid="6917864367861910086">"Отворајте линкови со <xliff:g id="APPLICATION">%1$s</xliff:g>"</string>
+ <string name="whichOpenHostLinksWithApp" msgid="2401668560768463004">"Отворајте линкови на <xliff:g id="HOST">%1$s</xliff:g> со <xliff:g id="APPLICATION">%2$s</xliff:g>"</string>
<string name="whichGiveAccessToApplicationLabel" msgid="7805857277166106236">"Дозволи пристап"</string>
<string name="whichEditApplication" msgid="6191568491456092812">"Измени со"</string>
<string name="whichEditApplicationNamed" msgid="8096494987978521514">"Измени со %1$s"</string>
diff --git a/core/res/res/values-ml/strings.xml b/core/res/res/values-ml/strings.xml
index 4b6ce39f46ab..ac32b3cb378d 100644
--- a/core/res/res/values-ml/strings.xml
+++ b/core/res/res/values-ml/strings.xml
@@ -202,10 +202,8 @@
<string name="printing_disabled_by" msgid="3517499806528864633">"<xliff:g id="OWNER_APP">%s</xliff:g> പ്രിന്റിംഗ് പ്രവർത്തനരഹിതമാക്കി."</string>
<string name="personal_apps_suspension_title" msgid="7561416677884286600">"ഔദ്യോഗിക പ്രൊഫൈൽ ഓണാക്കുക"</string>
<string name="personal_apps_suspension_text" msgid="6115455688932935597">"നിങ്ങളുടെ ഔദ്യോഗിക പ്രൊഫൈൽ ഓണാക്കുന്നത് വരെ നിങ്ങളുടെ വ്യക്തിപരമായ ആപ്പുകൾ ബ്ലോക്കായിരിക്കും"</string>
- <!-- no translation found for personal_apps_suspension_soon_text (8123898693479590) -->
- <skip />
- <!-- no translation found for personal_apps_suspended_turn_profile_on (2758012869627513689) -->
- <skip />
+ <string name="personal_apps_suspension_soon_text" msgid="8123898693479590">"വ്യക്തിപര ആപ്പുകൾ <xliff:g id="DATE">%1$s</xliff:g>, <xliff:g id="TIME">%2$s</xliff:g>-ന് ബ്ലോക്ക് ചെയ്യപ്പെടും. നിങ്ങളുടെ ഔദ്യോഗിക പ്രൊഫൈൽ <xliff:g id="NUMBER">%3$d</xliff:g> ദിവസത്തിൽ കൂടുതൽ ഓഫായ നിലയിൽ തുടരാൻ നിങ്ങളുടെ ഐടി അഡ്‌മിൻ അനുവദിക്കുന്നില്ല."</string>
+ <string name="personal_apps_suspended_turn_profile_on" msgid="2758012869627513689">"ഓണാക്കുക"</string>
<string name="me" msgid="6207584824693813140">"ഞാന്‍"</string>
<string name="power_dialog" product="tablet" msgid="8333207765671417261">"ടാബ്‌ലെറ്റ് ഓപ്‌ഷനുകൾ"</string>
<string name="power_dialog" product="tv" msgid="7792839006640933763">"Android ടിവി ഓപ്‌ഷനുകൾ"</string>
diff --git a/core/res/res/values-mn/strings.xml b/core/res/res/values-mn/strings.xml
index 40a57be65804..11683ae46138 100644
--- a/core/res/res/values-mn/strings.xml
+++ b/core/res/res/values-mn/strings.xml
@@ -202,10 +202,8 @@
<string name="printing_disabled_by" msgid="3517499806528864633">"<xliff:g id="OWNER_APP">%s</xliff:g> хэвлэх үйлдлийг идэвхгүй болгосон."</string>
<string name="personal_apps_suspension_title" msgid="7561416677884286600">"Ажлын профайлаа асаах"</string>
<string name="personal_apps_suspension_text" msgid="6115455688932935597">"Та ажлын профайлыг асаах хүртэл таны хувийн аппуудыг хориглосон"</string>
- <!-- no translation found for personal_apps_suspension_soon_text (8123898693479590) -->
- <skip />
- <!-- no translation found for personal_apps_suspended_turn_profile_on (2758012869627513689) -->
- <skip />
+ <string name="personal_apps_suspension_soon_text" msgid="8123898693479590">"Хувийн аппуудыг <xliff:g id="DATE">%1$s</xliff:g>-н <xliff:g id="TIME">%2$s</xliff:g>-д блоклоно. Таны IT админ таны ажлын профайлыг <xliff:g id="NUMBER">%3$d</xliff:g>-с олон хоног унтраалттай байхыг зөвшөөрдөггүй."</string>
+ <string name="personal_apps_suspended_turn_profile_on" msgid="2758012869627513689">"Асаах"</string>
<string name="me" msgid="6207584824693813140">"Би"</string>
<string name="power_dialog" product="tablet" msgid="8333207765671417261">"Таблетын сонголтууд"</string>
<string name="power_dialog" product="tv" msgid="7792839006640933763">"Android ТВ-н сонголт"</string>
@@ -1788,7 +1786,7 @@
<string name="managed_profile_label_badge" msgid="6762559569999499495">"Ажлын <xliff:g id="LABEL">%1$s</xliff:g>"</string>
<string name="managed_profile_label_badge_2" msgid="5673187309555352550">"2 дахь ажил <xliff:g id="LABEL">%1$s</xliff:g>"</string>
<string name="managed_profile_label_badge_3" msgid="6882151970556391957">"3 дахь ажил <xliff:g id="LABEL">%1$s</xliff:g>"</string>
- <string name="lock_to_app_unlock_pin" msgid="3890940811866290782">"Тогтоосныг суллахаас өмнө PIN асуух"</string>
+ <string name="lock_to_app_unlock_pin" msgid="3890940811866290782">"Бэхэлснийг болиулахаасаа өмнө PIN асуух"</string>
<string name="lock_to_app_unlock_pattern" msgid="2694204070499712503">"Тогтоосныг суллахаас өмнө түгжээ тайлах хээ асуух"</string>
<string name="lock_to_app_unlock_password" msgid="9126722403506560473">"Тогтоосныг суллахаас өмнө нууц үг асуух"</string>
<string name="package_installed_device_owner" msgid="7035926868974878525">"Таны админ суулгасан"</string>
@@ -1843,7 +1841,7 @@
<string name="zen_mode_default_weeknights_name" msgid="7902108149994062847">"Ажлын өдрийн шөнө"</string>
<string name="zen_mode_default_weekends_name" msgid="4707200272709377930">"Амралтын өдөр"</string>
<string name="zen_mode_default_events_name" msgid="2280682960128512257">"Үйл явдал"</string>
- <string name="zen_mode_default_every_night_name" msgid="1467765312174275823">"Идэвхгүй"</string>
+ <string name="zen_mode_default_every_night_name" msgid="1467765312174275823">"Унтлагын цаг"</string>
<string name="muted_by" msgid="91464083490094950">"<xliff:g id="THIRD_PARTY">%1$s</xliff:g> зарим дууны дууг хааж байна"</string>
<string name="system_error_wipe_data" msgid="5910572292172208493">"Таны төхөөрөмжид дотоод алдаа байна.Та төхөөрөмжөө үйлдвэрээс гарсан төлөвт шилжүүлэх хүртэл таны төхөөрөмж чинь тогтворгүй байж болох юм."</string>
<string name="system_error_manufacturer" msgid="703545241070116315">"Таны төхөөрөмжид дотоод алдаа байна. Дэлгэрэнгүй мэдээлэл авахыг хүсвэл үйлдвэрлэгчтэйгээ холбоо барина уу."</string>
diff --git a/core/res/res/values-mr/strings.xml b/core/res/res/values-mr/strings.xml
index a7e6f99ba8fd..f2bec3160830 100644
--- a/core/res/res/values-mr/strings.xml
+++ b/core/res/res/values-mr/strings.xml
@@ -202,10 +202,8 @@
<string name="printing_disabled_by" msgid="3517499806528864633">"<xliff:g id="OWNER_APP">%s</xliff:g> नी प्रिंट करणे बंद केले आहे."</string>
<string name="personal_apps_suspension_title" msgid="7561416677884286600">"तुमची कार्य प्रोफाइल सुरू करा"</string>
<string name="personal_apps_suspension_text" msgid="6115455688932935597">"तुम्ही तुमची कार्य प्रोफाइल सुरू करेपर्यंत तुमची वैयक्तिक ॲप्स ब्लॉक केली आहेत"</string>
- <!-- no translation found for personal_apps_suspension_soon_text (8123898693479590) -->
- <skip />
- <!-- no translation found for personal_apps_suspended_turn_profile_on (2758012869627513689) -->
- <skip />
+ <string name="personal_apps_suspension_soon_text" msgid="8123898693479590">"वैयक्तिक ॲप्स <xliff:g id="DATE">%1$s</xliff:g> रोजी <xliff:g id="TIME">%2$s</xliff:g> वाजता ब्लॉक केली जातील. तुमचा आयटी अ‍ॅडमिन तुमची कार्य प्रोफाइल <xliff:g id="NUMBER">%3$d</xliff:g> पेक्षा जास्त दिवसांसाठी बंद ठेवण्याची अनुमती देत नाही."</string>
+ <string name="personal_apps_suspended_turn_profile_on" msgid="2758012869627513689">"सुरू करा"</string>
<string name="me" msgid="6207584824693813140">"मी"</string>
<string name="power_dialog" product="tablet" msgid="8333207765671417261">"टॅबलेट पर्याय"</string>
<string name="power_dialog" product="tv" msgid="7792839006640933763">"Android TV पर्याय"</string>
@@ -1131,7 +1129,7 @@
<string name="whichViewApplicationNamed" msgid="415164730629690105">"%1$s सह उघडा"</string>
<string name="whichViewApplicationLabel" msgid="7367556735684742409">"उघडा"</string>
<string name="whichOpenHostLinksWith" msgid="7645631470199397485">"वापरून <xliff:g id="HOST">%1$s</xliff:g> लिंक उघडा"</string>
- <string name="whichOpenLinksWith" msgid="1120936181362907258">"वापरून लिंक उघडा"</string>
+ <string name="whichOpenLinksWith" msgid="1120936181362907258">"हे वापरून लिंक उघडा"</string>
<string name="whichOpenLinksWithApp" msgid="6917864367861910086">"<xliff:g id="APPLICATION">%1$s</xliff:g> वापरून लिंक उघडा"</string>
<string name="whichOpenHostLinksWithApp" msgid="2401668560768463004">"<xliff:g id="APPLICATION">%2$s</xliff:g> वापरून <xliff:g id="HOST">%1$s</xliff:g> लिंक उघडा"</string>
<string name="whichGiveAccessToApplicationLabel" msgid="7805857277166106236">"अ‍ॅक्सेस द्या"</string>
@@ -2032,7 +2030,7 @@
<item quantity="other"><xliff:g id="FILE_NAME_2">%s</xliff:g> + <xliff:g id="COUNT_3">%d</xliff:g> फाइल</item>
<item quantity="one"><xliff:g id="FILE_NAME_0">%s</xliff:g> + <xliff:g id="COUNT_1">%d</xliff:g> फाइल</item>
</plurals>
- <string name="chooser_no_direct_share_targets" msgid="1511722103987329028">"शेअर करण्यासाठी कोणतीही शिफारस केलेले लोक नाहीत"</string>
+ <string name="chooser_no_direct_share_targets" msgid="1511722103987329028">"शेअर करण्यासाठी शिफारस केलेल्या कोणत्याही व्यक्ती नाहीत"</string>
<string name="chooser_all_apps_button_label" msgid="3230427756238666328">"अ‍ॅप्स सूची"</string>
<string name="usb_device_resolve_prompt_warn" msgid="325871329788064199">"या अ‍ॅपला रेकॉर्ड करण्याची परवानगी दिली गेली नाही पण हे USB डिव्हाइस वापरून ऑडिओ कॅप्चर केला जाऊ शकतो."</string>
<string name="accessibility_system_action_home_label" msgid="3234748160850301870">"होम"</string>
@@ -2054,21 +2052,21 @@
<string name="conversation_title_fallback_group_chat" msgid="456073374993104303">"गट संभाषण"</string>
<string name="unread_convo_overflow" msgid="920517615597353833">"<xliff:g id="MAX_UNREAD_COUNT">%1$d</xliff:g>+"</string>
<string name="resolver_personal_tab" msgid="2051260504014442073">"वैयक्तिक"</string>
- <string name="resolver_work_tab" msgid="2690019516263167035">"ऑफिस"</string>
+ <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_cant_share_with_work_apps" msgid="637686613606502219">"हे ऑफिस ॲप्ससोबत शेअर करू शकत नाही"</string>
+ <string name="resolver_cant_share_with_work_apps" msgid="637686613606502219">"हे कार्य ॲप्ससोबत शेअर करू शकत नाही"</string>
<string name="resolver_cant_share_with_work_apps_explanation" msgid="3332302070341130545">"तुमचा IT अ‍ॅडमिन तुम्हाला हा आशय तुमच्या ऑफिस प्रोफाइलमधील अ‍ॅप्ससोबत शेअर करू देत नाही"</string>
<string name="resolver_cant_access_work_apps" msgid="2455757966397563223">"हे ऑफिस अ‍ॅप्ससोबत उघडू शकत नाही"</string>
- <string name="resolver_cant_access_work_apps_explanation" msgid="3626983885525445790">"तुमचा IT अ‍ॅडमिन तुम्हाला हा आशय तुमच्या ऑफिस प्रोफाइलमधील अ‍ॅप्ससोबत उघडू देत नाही"</string>
+ <string name="resolver_cant_access_work_apps_explanation" msgid="3626983885525445790">"तुमचा IT अ‍ॅडमिन तुम्हाला हा आशय तुमच्या कार्य प्रोफाइलमधील अ‍ॅप्सनी उघडू देत नाही"</string>
<string name="resolver_cant_share_with_personal_apps" msgid="3079139799233316203">"हे वैयक्तिक अ‍ॅप्ससोबत शेअर करू शकत नाही"</string>
<string name="resolver_cant_share_with_personal_apps_explanation" msgid="2959282422751315171">"तुमचा IT अ‍ॅडमिन तुम्हाला हा आशय तुमच्या वैयक्तिक प्रोफाइलमधील अ‍ॅप्ससोबत शेअर करू देत नाही"</string>
<string name="resolver_cant_access_personal_apps" msgid="648291604475669395">"हे वैयक्तिक अ‍ॅप्ससोबत उघडू शकत नाही"</string>
<string name="resolver_cant_access_personal_apps_explanation" msgid="2298773629302296519">"तुमचा IT अ‍ॅडमिन तुम्हाला हा आशय तुमच्या वैयक्तिक प्रोफाइलमधील अ‍ॅप्ससोबत उघडू देत नाही"</string>
- <string name="resolver_turn_on_work_apps" msgid="884910835250037247">"ऑफिस प्रोफाइल थांबवली आहे"</string>
+ <string name="resolver_turn_on_work_apps" msgid="884910835250037247">"कार्य प्रोफाइल थांबवली आहे"</string>
<string name="resolver_switch_on_work" msgid="2873009160846966379">"सुरू करा"</string>
- <string name="resolver_no_work_apps_available_share" msgid="7933949011797699505">"ऑफिस अ‍ॅप्स या आशयाला सपोर्ट करू शकत नाही"</string>
- <string name="resolver_no_work_apps_available_resolve" msgid="1244844292366099399">"ऑफिस अ‍ॅप्स हा आशय उघडू शकत नाही"</string>
+ <string name="resolver_no_work_apps_available_share" msgid="7933949011797699505">"कार्य अ‍ॅप्स या आशयाला सपोर्ट करू शकत नाही"</string>
+ <string name="resolver_no_work_apps_available_resolve" msgid="1244844292366099399">"कार्य अ‍ॅप्स हा आशय उघडू शकत नाही"</string>
<string name="resolver_no_personal_apps_available_share" msgid="5639102815174748732">"वैयक्तिक अ‍ॅप्स या आशयाला सपोर्ट करू शकत नाही"</string>
<string name="resolver_no_personal_apps_available_resolve" msgid="5120671970531446978">"वैयक्तिक अ‍ॅप्स हा आशय उघडू शकत नाही"</string>
<string name="PERSOSUBSTATE_SIM_NETWORK_ENTRY" msgid="8050953231914637819">"सिम नेटवर्क अनलॉक पिन"</string>
diff --git a/core/res/res/values-ms/strings.xml b/core/res/res/values-ms/strings.xml
index 5d075fa82487..fd6025ec0879 100644
--- a/core/res/res/values-ms/strings.xml
+++ b/core/res/res/values-ms/strings.xml
@@ -202,10 +202,8 @@
<string name="printing_disabled_by" msgid="3517499806528864633">"Pencetakan dilumpuhkan oleh <xliff:g id="OWNER_APP">%s</xliff:g>."</string>
<string name="personal_apps_suspension_title" msgid="7561416677884286600">"Hidupkan profil kerja anda"</string>
<string name="personal_apps_suspension_text" msgid="6115455688932935597">"Apl peribadi anda disekat sehingga anda menghidupkan profil kerja"</string>
- <!-- no translation found for personal_apps_suspension_soon_text (8123898693479590) -->
- <skip />
- <!-- no translation found for personal_apps_suspended_turn_profile_on (2758012869627513689) -->
- <skip />
+ <string name="personal_apps_suspension_soon_text" msgid="8123898693479590">"Apl peribadi akan disekat pada <xliff:g id="DATE">%1$s</xliff:g> pukul <xliff:g id="TIME">%2$s</xliff:g>. Pentadbir IT anda tidak membenarkan profil kerja anda dimatikan melebihi <xliff:g id="NUMBER">%3$d</xliff:g> hari."</string>
+ <string name="personal_apps_suspended_turn_profile_on" msgid="2758012869627513689">"Hidupkan"</string>
<string name="me" msgid="6207584824693813140">"Saya"</string>
<string name="power_dialog" product="tablet" msgid="8333207765671417261">"Pilihan tablet"</string>
<string name="power_dialog" product="tv" msgid="7792839006640933763">"Pilihan Android TV"</string>
diff --git a/core/res/res/values-my/strings.xml b/core/res/res/values-my/strings.xml
index 87eb087f83d4..d910fc03e165 100644
--- a/core/res/res/values-my/strings.xml
+++ b/core/res/res/values-my/strings.xml
@@ -202,10 +202,8 @@
<string name="printing_disabled_by" msgid="3517499806528864633">"<xliff:g id="OWNER_APP">%s</xliff:g> က ပုံနှိပ်ထုတ်ယူခြင်းကို ပိတ်ထားသည်။"</string>
<string name="personal_apps_suspension_title" msgid="7561416677884286600">"သင့်အလုပ်ပရိုဖိုင် ဖွင့်ခြင်း"</string>
<string name="personal_apps_suspension_text" msgid="6115455688932935597">"သင့်အလုပ်ပရိုဖိုင် ဖွင့်သည်အထိ ကိုယ်ပိုင်အက်ပ်များကို ပိတ်ထားသည်"</string>
- <!-- no translation found for personal_apps_suspension_soon_text (8123898693479590) -->
- <skip />
- <!-- no translation found for personal_apps_suspended_turn_profile_on (2758012869627513689) -->
- <skip />
+ <string name="personal_apps_suspension_soon_text" msgid="8123898693479590">"ကိုယ်ပိုင်အက်ပ်များကို <xliff:g id="DATE">%1$s</xliff:g> <xliff:g id="TIME">%2$s</xliff:g> တွင် ပိတ်ပါမည်။ သင့်အလုပ်ပရိုဖိုင် <xliff:g id="NUMBER">%3$d</xliff:g> ရက်ထက်ပိုပြီး ပိတ်ထားခြင်းကို သင်၏ IT စီမံခန့်ခွဲသူက ခွင့်မပြုပါ။"</string>
+ <string name="personal_apps_suspended_turn_profile_on" msgid="2758012869627513689">"ဖွင့်ရန်"</string>
<string name="me" msgid="6207584824693813140">"ကျွန်ုပ်"</string>
<string name="power_dialog" product="tablet" msgid="8333207765671417261">"Tabletဆိုင်ရာရွေးချယ်မှုများ"</string>
<string name="power_dialog" product="tv" msgid="7792839006640933763">"Android TV ရွေးချယ်စရာများ"</string>
@@ -1092,7 +1090,7 @@
<string name="elapsed_time_short_format_mm_ss" msgid="8689459651807876423">"<xliff:g id="MINUTES">%1$02d</xliff:g>:<xliff:g id="SECONDS">%2$02d</xliff:g>"</string>
<string name="elapsed_time_short_format_h_mm_ss" msgid="2302144714803345056">"<xliff:g id="HOURS">%1$d</xliff:g>:<xliff:g id="MINUTES">%2$02d</xliff:g>:<xliff:g id="SECONDS">%3$02d</xliff:g>"</string>
<string name="selectAll" msgid="1532369154488982046">"အားလုံးရွေးရန်"</string>
- <string name="cut" msgid="2561199725874745819">"ဖြတ်ခြင်း"</string>
+ <string name="cut" msgid="2561199725874745819">"ဖြတ်ရန်"</string>
<string name="copy" msgid="5472512047143665218">"ကူးရန်"</string>
<string name="failed_to_copy_to_clipboard" msgid="725919885138539875">"ကလစ်ဘုတ်သို့ မိတ္တူကူးခြင်း မအောင်မြင်ပါ"</string>
<string name="paste" msgid="461843306215520225">"Paste"</string>
@@ -1553,7 +1551,7 @@
<string name="activity_resolver_use_once" msgid="948462794469672658">"တစ်ခါတည်း"</string>
<string name="activity_resolver_work_profiles_support" msgid="4071345609235361269">"%1$s က အလုပ်ပရိုဖိုင်ကို မပံ့ပိုးပါ။"</string>
<string name="default_audio_route_name" product="tablet" msgid="367936735632195517">"တက်ဘလက်"</string>
- <string name="default_audio_route_name" product="tv" msgid="4908971385068087367">"တီဗွီ"</string>
+ <string name="default_audio_route_name" product="tv" msgid="4908971385068087367">"TV"</string>
<string name="default_audio_route_name" product="default" msgid="9213546147739983977">"ဖုန်း"</string>
<string name="default_audio_route_name_dock_speakers" msgid="1551166029093995289">"အထိုင်ရှိသော စပီကာများ"</string>
<string name="default_audio_route_name_hdmi" msgid="5474470558160717850">"HDMI"</string>
diff --git a/core/res/res/values-nb/strings.xml b/core/res/res/values-nb/strings.xml
index f61150a7f607..949c7f23e6e7 100644
--- a/core/res/res/values-nb/strings.xml
+++ b/core/res/res/values-nb/strings.xml
@@ -202,10 +202,8 @@
<string name="printing_disabled_by" msgid="3517499806528864633">"<xliff:g id="OWNER_APP">%s</xliff:g> har slått av utskrift."</string>
<string name="personal_apps_suspension_title" msgid="7561416677884286600">"Slå på jobbprofilen din"</string>
<string name="personal_apps_suspension_text" msgid="6115455688932935597">"De personlige appene dine er blokkert til du slår på jobbprofilen din"</string>
- <!-- no translation found for personal_apps_suspension_soon_text (8123898693479590) -->
- <skip />
- <!-- no translation found for personal_apps_suspended_turn_profile_on (2758012869627513689) -->
- <skip />
+ <string name="personal_apps_suspension_soon_text" msgid="8123898693479590">"Personlige apper blir blokkert <xliff:g id="DATE">%1$s</xliff:g> klokken <xliff:g id="TIME">%2$s</xliff:g>. IT-administratoren din tillater ikke at jobbprofilen din er slått av i mer enn <xliff:g id="NUMBER">%3$d</xliff:g> dager."</string>
+ <string name="personal_apps_suspended_turn_profile_on" msgid="2758012869627513689">"Slå på"</string>
<string name="me" msgid="6207584824693813140">"Meg"</string>
<string name="power_dialog" product="tablet" msgid="8333207765671417261">"Innstillinger for nettbrettet"</string>
<string name="power_dialog" product="tv" msgid="7792839006640933763">"Android TV-alternativer"</string>
diff --git a/core/res/res/values-ne/strings.xml b/core/res/res/values-ne/strings.xml
index dd27aaaaa50d..25cc45b9e964 100644
--- a/core/res/res/values-ne/strings.xml
+++ b/core/res/res/values-ne/strings.xml
@@ -202,10 +202,8 @@
<string name="printing_disabled_by" msgid="3517499806528864633">"<xliff:g id="OWNER_APP">%s</xliff:g> ले छाप्ने कार्यलाई असक्षम पार्यो।"</string>
<string name="personal_apps_suspension_title" msgid="7561416677884286600">"आफ्नो कार्य प्रोफाइल सक्रिय गर्नुहोस्"</string>
<string name="personal_apps_suspension_text" msgid="6115455688932935597">"तपाईंले आफ्नो कार्य प्रोफाइल सक्रिय नगरुन्जेल तपाईंका व्यक्तिगत अनुप्रयोगहरूलाई रोक लगाइन्छ"</string>
- <!-- no translation found for personal_apps_suspension_soon_text (8123898693479590) -->
- <skip />
- <!-- no translation found for personal_apps_suspended_turn_profile_on (2758012869627513689) -->
- <skip />
+ <string name="personal_apps_suspension_soon_text" msgid="8123898693479590">"मिति <xliff:g id="DATE">%1$s</xliff:g> <xliff:g id="TIME">%2$s</xliff:g> बजे व्यक्तिगत एपहरूलाई रोक लगाइने छ। तपाईंका IT एडमिन तपाईंलाई आफ्नो कार्य प्रोफाइल <xliff:g id="NUMBER">%3$d</xliff:g> भन्दा धेरै दिन निष्क्रिय राख्ने अनुमति दिनुहुन्न।"</string>
+ <string name="personal_apps_suspended_turn_profile_on" msgid="2758012869627513689">"सक्रिय गर्नुहोस्"</string>
<string name="me" msgid="6207584824693813140">"मलाई"</string>
<string name="power_dialog" product="tablet" msgid="8333207765671417261">"ट्याब्लेट विकल्पहरू"</string>
<string name="power_dialog" product="tv" msgid="7792839006640933763">"Android TV सम्बन्धी विकल्पहरू"</string>
diff --git a/core/res/res/values-nl/strings.xml b/core/res/res/values-nl/strings.xml
index cc8137cc244c..b1c4fbbf0b09 100644
--- a/core/res/res/values-nl/strings.xml
+++ b/core/res/res/values-nl/strings.xml
@@ -202,10 +202,8 @@
<string name="printing_disabled_by" msgid="3517499806528864633">"Afdrukken uitgeschakeld door <xliff:g id="OWNER_APP">%s</xliff:g>."</string>
<string name="personal_apps_suspension_title" msgid="7561416677884286600">"Schakel je werkprofiel in"</string>
<string name="personal_apps_suspension_text" msgid="6115455688932935597">"Je persoonlijke apps zijn geblokkeerd totdat je je werkprofiel inschakelt"</string>
- <!-- no translation found for personal_apps_suspension_soon_text (8123898693479590) -->
- <skip />
- <!-- no translation found for personal_apps_suspended_turn_profile_on (2758012869627513689) -->
- <skip />
+ <string name="personal_apps_suspension_soon_text" msgid="8123898693479590">"Apps die worden gebruikt voor persoonlijke doeleinden, worden geblokkeerd op <xliff:g id="DATE">%1$s</xliff:g> om <xliff:g id="TIME">%2$s</xliff:g>. Je IT-beheerder staat niet toe dat je werkprofiel langer dan <xliff:g id="NUMBER">%3$d</xliff:g> dagen is uitgeschakeld."</string>
+ <string name="personal_apps_suspended_turn_profile_on" msgid="2758012869627513689">"Inschakelen"</string>
<string name="me" msgid="6207584824693813140">"Ik"</string>
<string name="power_dialog" product="tablet" msgid="8333207765671417261">"Tabletopties"</string>
<string name="power_dialog" product="tv" msgid="7792839006640933763">"Opties voor Android TV"</string>
@@ -953,11 +951,11 @@
<string name="autofill_area" msgid="8289022370678448983">"Gebied"</string>
<string name="autofill_emirate" msgid="2544082046790551168">"Emiraat"</string>
<string name="permlab_readHistoryBookmarks" msgid="9102293913842539697">"je webbladwijzers en -geschiedenis lezen"</string>
- <string name="permdesc_readHistoryBookmarks" msgid="2323799501008967852">"Hiermee kan de app de geschiedenis lezen van alle URL\'s die in de systeemeigen browser zijn bezocht, en alle bladwijzers in de systeemeigen browser. Let op: deze toestemming kan niet worden geforceerd door andere browsers of andere apps met internetmogelijkheden."</string>
+ <string name="permdesc_readHistoryBookmarks" msgid="2323799501008967852">"Hiermee kan de app de geschiedenis lezen van alle URL\'s die in de systeemeigen browser zijn bezocht, en alle bookmarks in de systeemeigen browser. Let op: deze toestemming kan niet worden geforceerd door andere browsers of andere apps met internetmogelijkheden."</string>
<string name="permlab_writeHistoryBookmarks" msgid="6090259925187986937">"webbladwijzers en -geschiedenis schrijven"</string>
- <string name="permdesc_writeHistoryBookmarks" product="tablet" msgid="573341025292489065">"Hiermee kan de app de webgeschiedenis wijzigen in de systeemeigen browser en de bladwijzers die zijn opgeslagen op je tablet. Deze toestemming kan niet worden geforceerd door andere browsers of andere apps met internetmogelijkheden.."</string>
- <string name="permdesc_writeHistoryBookmarks" product="tv" msgid="88642768580408561">"Hiermee kan de app de browsergeschiedenis of opgeslagen bladwijzers bewerken op je Android TV-apparaat. Hierdoor kan de app mogelijk browsergegevens wissen of aanpassen. Opmerking: Dit recht kan niet worden afgedwongen door andere browsers of andere apps met internetmogelijkheden."</string>
- <string name="permdesc_writeHistoryBookmarks" product="default" msgid="2245203087160913652">"Hiermee kan de app de webgeschiedenis wijzigen in de systeemeigen browser en de bladwijzers die zijn opgeslagen op je telefoon. Deze toestemming kan niet worden geforceerd door andere browsers of andere apps met internetmogelijkheden."</string>
+ <string name="permdesc_writeHistoryBookmarks" product="tablet" msgid="573341025292489065">"Hiermee kan de app de webgeschiedenis wijzigen in de systeemeigen browser en de bookmarks die zijn opgeslagen op je tablet. Deze toestemming kan niet worden geforceerd door andere browsers of andere apps met internetmogelijkheden.."</string>
+ <string name="permdesc_writeHistoryBookmarks" product="tv" msgid="88642768580408561">"Hiermee kan de app de browsergeschiedenis of opgeslagen bookmarks bewerken op je Android TV-apparaat. Hierdoor kan de app mogelijk browsergegevens wissen of aanpassen. Opmerking: Dit recht kan niet worden afgedwongen door andere browsers of andere apps met internetmogelijkheden."</string>
+ <string name="permdesc_writeHistoryBookmarks" product="default" msgid="2245203087160913652">"Hiermee kan de app de webgeschiedenis wijzigen in de systeemeigen browser en de bookmarks die zijn opgeslagen op je telefoon. Deze toestemming kan niet worden geforceerd door andere browsers of andere apps met internetmogelijkheden."</string>
<string name="permlab_setAlarm" msgid="1158001610254173567">"een wekker instellen"</string>
<string name="permdesc_setAlarm" msgid="2185033720060109640">"Hiermee kan de app een wekker instellen in een geïnstalleerde wekker-app. Deze functie wordt door sommige wekker-apps niet geïmplementeerd."</string>
<string name="permlab_addVoicemail" msgid="4770245808840814471">"voicemail toevoegen"</string>
@@ -1550,7 +1548,7 @@
<string name="launchBrowserDefault" msgid="6328349989932924119">"Browser starten?"</string>
<string name="SetupCallDefault" msgid="5581740063237175247">"Gesprek accepteren?"</string>
<string name="activity_resolver_use_always" msgid="5575222334666843269">"Altijd"</string>
- <string name="activity_resolver_use_once" msgid="948462794469672658">"Één keer"</string>
+ <string name="activity_resolver_use_once" msgid="948462794469672658">"Eén keer"</string>
<string name="activity_resolver_work_profiles_support" msgid="4071345609235361269">"%1$s ondersteunt werkprofielen niet"</string>
<string name="default_audio_route_name" product="tablet" msgid="367936735632195517">"Tablet"</string>
<string name="default_audio_route_name" product="tv" msgid="4908971385068087367">"Tv"</string>
@@ -1912,7 +1910,7 @@
<string name="demo_starting_message" msgid="6577581216125805905">"Demo starten…"</string>
<string name="demo_restarting_message" msgid="1160053183701746766">"Apparaat resetten…"</string>
<string name="suspended_widget_accessibility" msgid="6331451091851326101">"<xliff:g id="LABEL">%1$s</xliff:g> uitgeschakeld"</string>
- <string name="conference_call" msgid="5731633152336490471">"Telefonische vergadering"</string>
+ <string name="conference_call" msgid="5731633152336490471">"Conferencecall"</string>
<string name="tooltip_popup_title" msgid="7863719020269945722">"Knopinfo"</string>
<string name="app_category_game" msgid="4534216074910244790">"Games"</string>
<string name="app_category_audio" msgid="8296029904794676222">"Muziek en audio"</string>
diff --git a/core/res/res/values-or/strings.xml b/core/res/res/values-or/strings.xml
index f803f02e92bc..5986e7652fa3 100644
--- a/core/res/res/values-or/strings.xml
+++ b/core/res/res/values-or/strings.xml
@@ -60,7 +60,7 @@
<string name="ClirMmi" msgid="4702929460236547156">"ଆଉଟଗୋଇଙ୍ଗ୍ କଲର୍ ଆଇଡି"</string>
<string name="ColpMmi" msgid="4736462893284419302">"ସଂଯୁକ୍ତ ଲାଇନ୍ ID"</string>
<string name="ColrMmi" msgid="5889782479745764278">"ସଂଯୁକ୍ତ ଲାଇନ୍ ID କଟକଣା"</string>
- <string name="CfMmi" msgid="8390012691099787178">"କଲ୍‌ ଫରୱାର୍ଡିଙ୍ଗ"</string>
+ <string name="CfMmi" msgid="8390012691099787178">"କଲ୍‌ ଫରୱାର୍ଡିଂ"</string>
<string name="CwMmi" msgid="3164609577675404761">"କଲ୍‌ ଅପେକ୍ଷାରତ"</string>
<string name="BaMmi" msgid="7205614070543372167">"କଲ୍‌ ବ୍ୟାରିଙ୍ଗ୍"</string>
<string name="PwdMmi" msgid="3360991257288638281">"ପାସ୍‌ୱର୍ଡ ପରିବର୍ତ୍ତନ"</string>
@@ -88,7 +88,7 @@
<string name="EmergencyCallWarningTitle" msgid="1615688002899152860">"ଜରୁରୀକାଳୀନ କଲ୍ ଉପଲବ୍ଧ ନାହିଁ"</string>
<string name="EmergencyCallWarningSummary" msgid="1194185880092805497">"ୱାଇ-ଫାଇ ସାହାଯ୍ୟରେ ଜରୁରୀକାଳୀନ କଲ୍ କରାଯାଇପାରିବ ନାହିଁ"</string>
<string name="notification_channel_network_alert" msgid="4788053066033851841">"ଆଲର୍ଟ"</string>
- <string name="notification_channel_call_forward" msgid="8230490317314272406">"କଲ୍‌ ଫରୱାର୍ଡିଙ୍ଗ"</string>
+ <string name="notification_channel_call_forward" msgid="8230490317314272406">"କଲ୍‌ ଫରୱାର୍ଡିଂ"</string>
<string name="notification_channel_emergency_callback" msgid="54074839059123159">"ଜରୁରୀକାଳୀନ କଲବ୍ୟାକ୍‍ ମୋଡ୍‍"</string>
<string name="notification_channel_mobile_data_status" msgid="1941911162076442474">"ମୋବାଇଲ୍‍ ଡାଟା ଷ୍ଟାଟସ୍‌"</string>
<string name="notification_channel_sms" msgid="1243384981025535724">"SMS ମେସେଜ୍‌"</string>
@@ -202,10 +202,8 @@
<string name="printing_disabled_by" msgid="3517499806528864633">"<xliff:g id="OWNER_APP">%s</xliff:g> ଦ୍ଵାରା ପ୍ରିଣ୍ଟିଙ୍ଗ ଅକ୍ଷମ କରାଯାଇଛି"</string>
<string name="personal_apps_suspension_title" msgid="7561416677884286600">"ୱାର୍କ ପ୍ରୋଫାଇଲ୍ ଚାଲୁ କରନ୍ତୁ"</string>
<string name="personal_apps_suspension_text" msgid="6115455688932935597">"ଆପଣ ଆପଣଙ୍କ ୱାର୍କ ପ୍ରୋଫାଇଲ୍ ଚାଲୁ ନକରିବା ପର୍ଯ୍ୟନ୍ତ ଆପଣଙ୍କର ବ୍ୟକ୍ତିଗତ ଆପ୍ସ ବ୍ଲକ୍ କରାଯାଇଛି"</string>
- <!-- no translation found for personal_apps_suspension_soon_text (8123898693479590) -->
- <skip />
- <!-- no translation found for personal_apps_suspended_turn_profile_on (2758012869627513689) -->
- <skip />
+ <string name="personal_apps_suspension_soon_text" msgid="8123898693479590">"<xliff:g id="DATE">%1$s</xliff:g> <xliff:g id="TIME">%2$s</xliff:g>ରେ ଆପଣଙ୍କ ବ୍ୟକ୍ତିଗତ ଆପ୍ସକୁ ବ୍ଲକ୍ କରାଯିବ। ଆପଣଙ୍କ IT ଆଡମିନ୍ ଆପଣଙ୍କ ୱାର୍କ ପ୍ରୋଫାଇଲକୁ <xliff:g id="NUMBER">%3$d</xliff:g>ରୁ ଅଧିକ ଦିନ ପାଇଁ ବନ୍ଦ କରିବାକୁ ଅନୁମତି ଦିଅନ୍ତି ନାହିଁ।"</string>
+ <string name="personal_apps_suspended_turn_profile_on" msgid="2758012869627513689">"ଚାଲୁ କରନ୍ତୁ"</string>
<string name="me" msgid="6207584824693813140">"ମୁଁ"</string>
<string name="power_dialog" product="tablet" msgid="8333207765671417261">"ଟାବଲେଟ୍‌ର ବିକଳ୍ପ"</string>
<string name="power_dialog" product="tv" msgid="7792839006640933763">"Android ଟିଭିର ବିକଳ୍ପଗୁଡ଼ିକ"</string>
@@ -789,7 +787,7 @@
<string name="imProtocolYahoo" msgid="5373338758093392231">"Yahoo"</string>
<string name="imProtocolSkype" msgid="1486297589164830043">"Skype"</string>
<string name="imProtocolQq" msgid="7254708777029006592">"QQ"</string>
- <string name="imProtocolGoogleTalk" msgid="9194016024343166782">"ହ୍ୟାଙ୍ଗଆଉଟ୍ସ"</string>
+ <string name="imProtocolGoogleTalk" msgid="9194016024343166782">"Hangouts"</string>
<string name="imProtocolIcq" msgid="2410325380427389521">"ICQ"</string>
<string name="imProtocolJabber" msgid="7919269388889582015">"Jabber"</string>
<string name="imProtocolNetMeeting" msgid="4985002408136148256">"NetMeeting"</string>
diff --git a/core/res/res/values-pa/strings.xml b/core/res/res/values-pa/strings.xml
index fd3e638cb1b8..77341c677abe 100644
--- a/core/res/res/values-pa/strings.xml
+++ b/core/res/res/values-pa/strings.xml
@@ -202,10 +202,8 @@
<string name="printing_disabled_by" msgid="3517499806528864633">"<xliff:g id="OWNER_APP">%s</xliff:g> ਵੱਲੋਂ ਪ੍ਰਿੰਟ ਕਰਨਾ ਬੰਦ ਕੀਤਾ ਗਿਆ।"</string>
<string name="personal_apps_suspension_title" msgid="7561416677884286600">"ਆਪਣਾ ਕਾਰਜ ਪ੍ਰੋਫਾਈਲ ਚਾਲੂ ਕਰੋ"</string>
<string name="personal_apps_suspension_text" msgid="6115455688932935597">"ਜਦੋਂ ਤੱਕ ਤੁਸੀਂ ਆਪਣਾ ਕਾਰਜ ਪ੍ਰੋਫਾਈਲ ਚਾਲੂ ਨਹੀਂ ਕਰਦੇ ਤੁਹਾਡੀਆਂ ਨਿੱਜੀ ਐਪਾਂ ਬਲਾਕ ਰਹਿੰਦੀਆਂ ਹਨ"</string>
- <!-- no translation found for personal_apps_suspension_soon_text (8123898693479590) -->
- <skip />
- <!-- no translation found for personal_apps_suspended_turn_profile_on (2758012869627513689) -->
- <skip />
+ <string name="personal_apps_suspension_soon_text" msgid="8123898693479590">"<xliff:g id="DATE">%1$s</xliff:g> ਨੂੰ <xliff:g id="TIME">%2$s</xliff:g> ਵਜੇ ਨਿੱਜੀ ਐਪਾਂ ਨੂੰ ਬਲਾਕ ਕਰ ਦਿੱਤਾ ਜਾਵੇਗਾ। ਤੁਹਾਡਾ ਆਈ.ਟੀ. ਪ੍ਰਸ਼ਾਸਕ ਤੁਹਾਡੇ ਕਾਰਜ ਪ੍ਰੋਫਾਈਲ ਨੂੰ <xliff:g id="NUMBER">%3$d</xliff:g> ਦਿਨਾਂ ਤੋਂ ਵੱਧ ਸਮੇਂ ਤੱਕ ਬੰਦ ਰਹਿਣ ਦੀ ਇਜਾਜ਼ਤ ਨਹੀਂ ਦਿੰਦਾ।"</string>
+ <string name="personal_apps_suspended_turn_profile_on" msgid="2758012869627513689">"ਚਾਲੂ ਕਰੋ"</string>
<string name="me" msgid="6207584824693813140">"ਮੈਂ"</string>
<string name="power_dialog" product="tablet" msgid="8333207765671417261">"ਟੈਬਲੈੱਟ ਵਿਕਲਪ"</string>
<string name="power_dialog" product="tv" msgid="7792839006640933763">"Android TV ਦੇ ਵਿਕਲਪ"</string>
diff --git a/core/res/res/values-pl/strings.xml b/core/res/res/values-pl/strings.xml
index 33104c791190..f89189b3fa9e 100644
--- a/core/res/res/values-pl/strings.xml
+++ b/core/res/res/values-pl/strings.xml
@@ -206,10 +206,8 @@
<string name="printing_disabled_by" msgid="3517499806528864633">"Drukowanie wyłączone przez: <xliff:g id="OWNER_APP">%s</xliff:g>."</string>
<string name="personal_apps_suspension_title" msgid="7561416677884286600">"Włącz profil do pracy"</string>
<string name="personal_apps_suspension_text" msgid="6115455688932935597">"Zablokowano aplikacje osobiste do czasu włączenia profilu do pracy"</string>
- <!-- no translation found for personal_apps_suspension_soon_text (8123898693479590) -->
- <skip />
- <!-- no translation found for personal_apps_suspended_turn_profile_on (2758012869627513689) -->
- <skip />
+ <string name="personal_apps_suspension_soon_text" msgid="8123898693479590">"Aplikacje osobiste zostaną zablokowane <xliff:g id="DATE">%1$s</xliff:g> o <xliff:g id="TIME">%2$s</xliff:g>. Administrator IT nie pozwala na wyłączenie profilu służbowego na dłużej niż <xliff:g id="NUMBER">%3$d</xliff:g> dni."</string>
+ <string name="personal_apps_suspended_turn_profile_on" msgid="2758012869627513689">"Włącz"</string>
<string name="me" msgid="6207584824693813140">"Ja"</string>
<string name="power_dialog" product="tablet" msgid="8333207765671417261">"Opcje tabletu"</string>
<string name="power_dialog" product="tv" msgid="7792839006640933763">"Opcje Androida TV"</string>
@@ -1170,7 +1168,7 @@
<string name="whichViewApplication" msgid="5733194231473132945">"Otwórz w aplikacji"</string>
<string name="whichViewApplicationNamed" msgid="415164730629690105">"Otwórz w aplikacji %1$s"</string>
<string name="whichViewApplicationLabel" msgid="7367556735684742409">"Otwórz"</string>
- <string name="whichOpenHostLinksWith" msgid="7645631470199397485">"Otwieraj linki z: <xliff:g id="HOST">%1$s</xliff:g> w"</string>
+ <string name="whichOpenHostLinksWith" msgid="7645631470199397485">"Otwieraj linki z <xliff:g id="HOST">%1$s</xliff:g> w"</string>
<string name="whichOpenLinksWith" msgid="1120936181362907258">"Otwieraj linki w"</string>
<string name="whichOpenLinksWithApp" msgid="6917864367861910086">"Otwieraj linki w aplikacji <xliff:g id="APPLICATION">%1$s</xliff:g>"</string>
<string name="whichOpenHostLinksWithApp" msgid="2401668560768463004">"Otwieraj linki z: <xliff:g id="HOST">%1$s</xliff:g> w aplikacji <xliff:g id="APPLICATION">%2$s</xliff:g>"</string>
@@ -2125,18 +2123,18 @@
<string name="resolver_work_tab" msgid="2690019516263167035">"Służbowe"</string>
<string name="resolver_personal_tab_accessibility" msgid="5739524949153091224">"Widok osobisty"</string>
<string name="resolver_work_tab_accessibility" msgid="4753168230363802734">"Widok służbowy"</string>
- <string name="resolver_cant_share_with_work_apps" msgid="637686613606502219">"Nie można udostępnić aplikacjom do pracy"</string>
- <string name="resolver_cant_share_with_work_apps_explanation" msgid="3332302070341130545">"Administrator IT nie pozwala na udostępnianie tej zawartości w profilu do pracy"</string>
- <string name="resolver_cant_access_work_apps" msgid="2455757966397563223">"Nie można otworzyć w aplikacjach do pracy"</string>
- <string name="resolver_cant_access_work_apps_explanation" msgid="3626983885525445790">"Administrator IT nie pozwala na otwieranie tej zawartości w profilu do pracy"</string>
+ <string name="resolver_cant_share_with_work_apps" msgid="637686613606502219">"Nie można udostępnić aplikacjom służbowym"</string>
+ <string name="resolver_cant_share_with_work_apps_explanation" msgid="3332302070341130545">"Administrator IT nie pozwala na udostępnianie tej zawartości w profilu służbowym"</string>
+ <string name="resolver_cant_access_work_apps" msgid="2455757966397563223">"Nie można otworzyć w aplikacjach służbowych"</string>
+ <string name="resolver_cant_access_work_apps_explanation" msgid="3626983885525445790">"Administrator IT nie pozwala na otwieranie tej zawartości w profilu służbowym"</string>
<string name="resolver_cant_share_with_personal_apps" msgid="3079139799233316203">"Nie można udostępnić aplikacjom osobistym"</string>
<string name="resolver_cant_share_with_personal_apps_explanation" msgid="2959282422751315171">"Administrator IT nie pozwala na udostępnianie tej zawartości w profilu osobistym"</string>
<string name="resolver_cant_access_personal_apps" msgid="648291604475669395">"Nie można otworzyć w aplikacjach osobistych"</string>
<string name="resolver_cant_access_personal_apps_explanation" msgid="2298773629302296519">"Administrator IT nie pozwala na otwieranie tej zawartości w profilu osobistym"</string>
- <string name="resolver_turn_on_work_apps" msgid="884910835250037247">"Działanie profilu do pracy jest wstrzymane"</string>
+ <string name="resolver_turn_on_work_apps" msgid="884910835250037247">"Działanie profilu służbowego jest wstrzymane"</string>
<string name="resolver_switch_on_work" msgid="2873009160846966379">"Włącz"</string>
- <string name="resolver_no_work_apps_available_share" msgid="7933949011797699505">"Brak aplikacji do pracy, które obsługują tę zawartość"</string>
- <string name="resolver_no_work_apps_available_resolve" msgid="1244844292366099399">"Brak aplikacji do pracy, które mogą otworzyć tę zawartość"</string>
+ <string name="resolver_no_work_apps_available_share" msgid="7933949011797699505">"Brak aplikacji służbowych, które obsługują tę zawartość"</string>
+ <string name="resolver_no_work_apps_available_resolve" msgid="1244844292366099399">"Brak aplikacji służbowych, które mogą otworzyć tę zawartość"</string>
<string name="resolver_no_personal_apps_available_share" msgid="5639102815174748732">"Brak aplikacji osobistych, które obsługują tę zawartość"</string>
<string name="resolver_no_personal_apps_available_resolve" msgid="5120671970531446978">"Brak aplikacji osobistych, które mogą otworzyć tę zawartość"</string>
<string name="PERSOSUBSTATE_SIM_NETWORK_ENTRY" msgid="8050953231914637819">"Kod PIN do karty SIM odblokowujący sieć"</string>
diff --git a/core/res/res/values-pt-rBR/strings.xml b/core/res/res/values-pt-rBR/strings.xml
index 25f8633b44ad..4858b42d8acf 100644
--- a/core/res/res/values-pt-rBR/strings.xml
+++ b/core/res/res/values-pt-rBR/strings.xml
@@ -56,8 +56,8 @@
</plurals>
<string name="imei" msgid="2157082351232630390">"IMEI"</string>
<string name="meid" msgid="3291227361605924674">"MEID"</string>
- <string name="ClipMmi" msgid="4110549342447630629">"ID do chamador de entrada"</string>
- <string name="ClirMmi" msgid="4702929460236547156">"ID do chamador de saída"</string>
+ <string name="ClipMmi" msgid="4110549342447630629">"Identificador de chamadas recebidas"</string>
+ <string name="ClirMmi" msgid="4702929460236547156">"Identificador de chamadas realizadas"</string>
<string name="ColpMmi" msgid="4736462893284419302">"ID de linha conectada"</string>
<string name="ColrMmi" msgid="5889782479745764278">"Restrição de ID de linha conectada"</string>
<string name="CfMmi" msgid="8390012691099787178">"Encaminhamento de chamada"</string>
@@ -71,12 +71,12 @@
<string name="RuacMmi" msgid="1876047385848991110">"Rejeição das chamadas indesejadas"</string>
<string name="CndMmi" msgid="185136449405618437">"Chamando número de entrega"</string>
<string name="DndMmi" msgid="8797375819689129800">"Não perturbe"</string>
- <string name="CLIRDefaultOnNextCallOn" msgid="4511621022859867988">"O ID do chamador assume o padrão de restrito. Próxima chamada: Restrita"</string>
- <string name="CLIRDefaultOnNextCallOff" msgid="5036749051007098105">"O ID do chamador assume o padrão de restrito. Próxima chamada: Não restrita"</string>
- <string name="CLIRDefaultOffNextCallOn" msgid="1022781126694885017">"O ID do chamador assume o padrão de não restrito. Próxima chamada: Restrita"</string>
- <string name="CLIRDefaultOffNextCallOff" msgid="2491576172356463443">"O ID do chamador assume o padrão de não restrito. Próxima chamada: Não restrita"</string>
+ <string name="CLIRDefaultOnNextCallOn" msgid="4511621022859867988">"O identificador de chamadas assume o padrão de restrito. Próxima chamada: Restrita"</string>
+ <string name="CLIRDefaultOnNextCallOff" msgid="5036749051007098105">"O identificador de chamadas assume o padrão de restrito. Próxima chamada: Não restrita"</string>
+ <string name="CLIRDefaultOffNextCallOn" msgid="1022781126694885017">"O identificador de chamadas assume o padrão de não restrito. Próxima chamada: Restrita"</string>
+ <string name="CLIRDefaultOffNextCallOff" msgid="2491576172356463443">"O identificador de chamadas assume o padrão de não restrito. Próxima chamada: Não restrita"</string>
<string name="serviceNotProvisioned" msgid="8289333510236766193">"O serviço não foi habilitado."</string>
- <string name="CLIRPermanent" msgid="166443681876381118">"Não é possível alterar a configuração de identificação de chamadas."</string>
+ <string name="CLIRPermanent" msgid="166443681876381118">"Não é possível alterar a configuração do identificador de chamadas."</string>
<string name="RestrictedOnDataTitle" msgid="1500576417268169774">"Nenhum serviço móvel de dados"</string>
<string name="RestrictedOnEmergencyTitle" msgid="2852916906106191866">"Chamadas de emergência indisponíveis"</string>
<string name="RestrictedOnNormalTitle" msgid="7009474589746551737">"Sem serviço de voz"</string>
@@ -202,10 +202,8 @@
<string name="printing_disabled_by" msgid="3517499806528864633">"Impressão desativada por <xliff:g id="OWNER_APP">%s</xliff:g>."</string>
<string name="personal_apps_suspension_title" msgid="7561416677884286600">"Ativar perfil de trabalho"</string>
<string name="personal_apps_suspension_text" msgid="6115455688932935597">"Seus apps pessoais ficarão bloqueados até você ativar o perfil de trabalho"</string>
- <!-- no translation found for personal_apps_suspension_soon_text (8123898693479590) -->
- <skip />
- <!-- no translation found for personal_apps_suspended_turn_profile_on (2758012869627513689) -->
- <skip />
+ <string name="personal_apps_suspension_soon_text" msgid="8123898693479590">"Os apps pessoais serão bloqueados em <xliff:g id="DATE">%1$s</xliff:g>, <xliff:g id="TIME">%2$s</xliff:g>. Seu administrador de TI não permite que o perfil de trabalho fique desativado por mais de <xliff:g id="NUMBER">%3$d</xliff:g> dias."</string>
+ <string name="personal_apps_suspended_turn_profile_on" msgid="2758012869627513689">"Ativar"</string>
<string name="me" msgid="6207584824693813140">"Eu"</string>
<string name="power_dialog" product="tablet" msgid="8333207765671417261">"Opções do tablet"</string>
<string name="power_dialog" product="tv" msgid="7792839006640933763">"Opções do Android TV"</string>
@@ -1130,10 +1128,10 @@
<string name="whichViewApplication" msgid="5733194231473132945">"Abrir com"</string>
<string name="whichViewApplicationNamed" msgid="415164730629690105">"Abrir com %1$s"</string>
<string name="whichViewApplicationLabel" msgid="7367556735684742409">"Abrir"</string>
- <string name="whichOpenHostLinksWith" msgid="7645631470199397485">"Abrir links do domínio <xliff:g id="HOST">%1$s</xliff:g> com"</string>
+ <string name="whichOpenHostLinksWith" msgid="7645631470199397485">"Abrir links do domínio <xliff:g id="HOST">%1$s</xliff:g> usando"</string>
<string name="whichOpenLinksWith" msgid="1120936181362907258">"Abrir links com"</string>
<string name="whichOpenLinksWithApp" msgid="6917864367861910086">"Abrir links com <xliff:g id="APPLICATION">%1$s</xliff:g>"</string>
- <string name="whichOpenHostLinksWithApp" msgid="2401668560768463004">"Abrir links do domínio <xliff:g id="HOST">%1$s</xliff:g> com <xliff:g id="APPLICATION">%2$s</xliff:g>"</string>
+ <string name="whichOpenHostLinksWithApp" msgid="2401668560768463004">"Abrir links do domínio <xliff:g id="HOST">%1$s</xliff:g> usando <xliff:g id="APPLICATION">%2$s</xliff:g>"</string>
<string name="whichGiveAccessToApplicationLabel" msgid="7805857277166106236">"Conceder acesso"</string>
<string name="whichEditApplication" msgid="6191568491456092812">"Editar com"</string>
<string name="whichEditApplicationNamed" msgid="8096494987978521514">"Editar com %1$s"</string>
@@ -2059,12 +2057,12 @@
<string name="resolver_work_tab_accessibility" msgid="4753168230363802734">"Visualização de trabalho"</string>
<string name="resolver_cant_share_with_work_apps" msgid="637686613606502219">"Não é possível compartilhar este conteúdo com apps de trabalho"</string>
<string name="resolver_cant_share_with_work_apps_explanation" msgid="3332302070341130545">"Seu administrador de TI não permite que você compartilhe este conteúdo com apps no seu perfil de trabalho"</string>
- <string name="resolver_cant_access_work_apps" msgid="2455757966397563223">"Não é possível abrir com apps de trabalho"</string>
- <string name="resolver_cant_access_work_apps_explanation" msgid="3626983885525445790">"Seu administrador de TI não permite que você abra este conteúdo com apps no seu perfil de trabalho"</string>
+ <string name="resolver_cant_access_work_apps" msgid="2455757966397563223">"Não é possível abrir usando apps de trabalho"</string>
+ <string name="resolver_cant_access_work_apps_explanation" msgid="3626983885525445790">"Seu administrador de TI não permite que você abra este conteúdo usando apps do seu perfil de trabalho"</string>
<string name="resolver_cant_share_with_personal_apps" msgid="3079139799233316203">"Não é possível compartilhar este conteúdo com apps pessoais"</string>
<string name="resolver_cant_share_with_personal_apps_explanation" msgid="2959282422751315171">"Seu administrador de TI não permite que você compartilhe este conteúdo com apps no seu perfil pessoal"</string>
<string name="resolver_cant_access_personal_apps" msgid="648291604475669395">"Não é possível abrir este conteúdo com apps pessoais"</string>
- <string name="resolver_cant_access_personal_apps_explanation" msgid="2298773629302296519">"Seu administrador de TI não permite que você abra este conteúdo com apps no seu perfil pessoal"</string>
+ <string name="resolver_cant_access_personal_apps_explanation" msgid="2298773629302296519">"Seu administrador de TI não permite que você abra este conteúdo usando apps do seu perfil pessoal"</string>
<string name="resolver_turn_on_work_apps" msgid="884910835250037247">"O perfil de trabalho está pausado"</string>
<string name="resolver_switch_on_work" msgid="2873009160846966379">"Ativar"</string>
<string name="resolver_no_work_apps_available_share" msgid="7933949011797699505">"Apps de trabalho não são compatíveis com este conteúdo"</string>
diff --git a/core/res/res/values-pt-rPT/strings.xml b/core/res/res/values-pt-rPT/strings.xml
index 5bc4fbdaeda8..a13c2d28f986 100644
--- a/core/res/res/values-pt-rPT/strings.xml
+++ b/core/res/res/values-pt-rPT/strings.xml
@@ -202,10 +202,8 @@
<string name="printing_disabled_by" msgid="3517499806528864633">"Impressão desativada por <xliff:g id="OWNER_APP">%s</xliff:g>."</string>
<string name="personal_apps_suspension_title" msgid="7561416677884286600">"Ative o perfil de trabalho"</string>
<string name="personal_apps_suspension_text" msgid="6115455688932935597">"As suas apps pessoais estão bloqueadas até ativar o seu perfil de trabalho."</string>
- <!-- no translation found for personal_apps_suspension_soon_text (8123898693479590) -->
- <skip />
- <!-- no translation found for personal_apps_suspended_turn_profile_on (2758012869627513689) -->
- <skip />
+ <string name="personal_apps_suspension_soon_text" msgid="8123898693479590">"As apps pessoais serão bloqueadas a <xliff:g id="DATE">%1$s</xliff:g> à(s) <xliff:g id="TIME">%2$s</xliff:g>. O seu administrador de TI não permite que o seu perfil de trabalho fique desativado mais de <xliff:g id="NUMBER">%3$d</xliff:g> dias."</string>
+ <string name="personal_apps_suspended_turn_profile_on" msgid="2758012869627513689">"Ativar"</string>
<string name="me" msgid="6207584824693813140">"Eu"</string>
<string name="power_dialog" product="tablet" msgid="8333207765671417261">"Opções do tablet"</string>
<string name="power_dialog" product="tv" msgid="7792839006640933763">"Opções do Android TV"</string>
@@ -1131,7 +1129,7 @@
<string name="whichViewApplicationNamed" msgid="415164730629690105">"Abrir com %1$s"</string>
<string name="whichViewApplicationLabel" msgid="7367556735684742409">"Abrir"</string>
<string name="whichOpenHostLinksWith" msgid="7645631470199397485">"Abra os links de <xliff:g id="HOST">%1$s</xliff:g> com:"</string>
- <string name="whichOpenLinksWith" msgid="1120936181362907258">"Abra os links com:"</string>
+ <string name="whichOpenLinksWith" msgid="1120936181362907258">"Abrir os links com:"</string>
<string name="whichOpenLinksWithApp" msgid="6917864367861910086">"Abra os links com a app <xliff:g id="APPLICATION">%1$s</xliff:g>"</string>
<string name="whichOpenHostLinksWithApp" msgid="2401668560768463004">"Abra os links de <xliff:g id="HOST">%1$s</xliff:g> com a app <xliff:g id="APPLICATION">%2$s</xliff:g>"</string>
<string name="whichGiveAccessToApplicationLabel" msgid="7805857277166106236">"Conceder acesso"</string>
diff --git a/core/res/res/values-pt/strings.xml b/core/res/res/values-pt/strings.xml
index 25f8633b44ad..4858b42d8acf 100644
--- a/core/res/res/values-pt/strings.xml
+++ b/core/res/res/values-pt/strings.xml
@@ -56,8 +56,8 @@
</plurals>
<string name="imei" msgid="2157082351232630390">"IMEI"</string>
<string name="meid" msgid="3291227361605924674">"MEID"</string>
- <string name="ClipMmi" msgid="4110549342447630629">"ID do chamador de entrada"</string>
- <string name="ClirMmi" msgid="4702929460236547156">"ID do chamador de saída"</string>
+ <string name="ClipMmi" msgid="4110549342447630629">"Identificador de chamadas recebidas"</string>
+ <string name="ClirMmi" msgid="4702929460236547156">"Identificador de chamadas realizadas"</string>
<string name="ColpMmi" msgid="4736462893284419302">"ID de linha conectada"</string>
<string name="ColrMmi" msgid="5889782479745764278">"Restrição de ID de linha conectada"</string>
<string name="CfMmi" msgid="8390012691099787178">"Encaminhamento de chamada"</string>
@@ -71,12 +71,12 @@
<string name="RuacMmi" msgid="1876047385848991110">"Rejeição das chamadas indesejadas"</string>
<string name="CndMmi" msgid="185136449405618437">"Chamando número de entrega"</string>
<string name="DndMmi" msgid="8797375819689129800">"Não perturbe"</string>
- <string name="CLIRDefaultOnNextCallOn" msgid="4511621022859867988">"O ID do chamador assume o padrão de restrito. Próxima chamada: Restrita"</string>
- <string name="CLIRDefaultOnNextCallOff" msgid="5036749051007098105">"O ID do chamador assume o padrão de restrito. Próxima chamada: Não restrita"</string>
- <string name="CLIRDefaultOffNextCallOn" msgid="1022781126694885017">"O ID do chamador assume o padrão de não restrito. Próxima chamada: Restrita"</string>
- <string name="CLIRDefaultOffNextCallOff" msgid="2491576172356463443">"O ID do chamador assume o padrão de não restrito. Próxima chamada: Não restrita"</string>
+ <string name="CLIRDefaultOnNextCallOn" msgid="4511621022859867988">"O identificador de chamadas assume o padrão de restrito. Próxima chamada: Restrita"</string>
+ <string name="CLIRDefaultOnNextCallOff" msgid="5036749051007098105">"O identificador de chamadas assume o padrão de restrito. Próxima chamada: Não restrita"</string>
+ <string name="CLIRDefaultOffNextCallOn" msgid="1022781126694885017">"O identificador de chamadas assume o padrão de não restrito. Próxima chamada: Restrita"</string>
+ <string name="CLIRDefaultOffNextCallOff" msgid="2491576172356463443">"O identificador de chamadas assume o padrão de não restrito. Próxima chamada: Não restrita"</string>
<string name="serviceNotProvisioned" msgid="8289333510236766193">"O serviço não foi habilitado."</string>
- <string name="CLIRPermanent" msgid="166443681876381118">"Não é possível alterar a configuração de identificação de chamadas."</string>
+ <string name="CLIRPermanent" msgid="166443681876381118">"Não é possível alterar a configuração do identificador de chamadas."</string>
<string name="RestrictedOnDataTitle" msgid="1500576417268169774">"Nenhum serviço móvel de dados"</string>
<string name="RestrictedOnEmergencyTitle" msgid="2852916906106191866">"Chamadas de emergência indisponíveis"</string>
<string name="RestrictedOnNormalTitle" msgid="7009474589746551737">"Sem serviço de voz"</string>
@@ -202,10 +202,8 @@
<string name="printing_disabled_by" msgid="3517499806528864633">"Impressão desativada por <xliff:g id="OWNER_APP">%s</xliff:g>."</string>
<string name="personal_apps_suspension_title" msgid="7561416677884286600">"Ativar perfil de trabalho"</string>
<string name="personal_apps_suspension_text" msgid="6115455688932935597">"Seus apps pessoais ficarão bloqueados até você ativar o perfil de trabalho"</string>
- <!-- no translation found for personal_apps_suspension_soon_text (8123898693479590) -->
- <skip />
- <!-- no translation found for personal_apps_suspended_turn_profile_on (2758012869627513689) -->
- <skip />
+ <string name="personal_apps_suspension_soon_text" msgid="8123898693479590">"Os apps pessoais serão bloqueados em <xliff:g id="DATE">%1$s</xliff:g>, <xliff:g id="TIME">%2$s</xliff:g>. Seu administrador de TI não permite que o perfil de trabalho fique desativado por mais de <xliff:g id="NUMBER">%3$d</xliff:g> dias."</string>
+ <string name="personal_apps_suspended_turn_profile_on" msgid="2758012869627513689">"Ativar"</string>
<string name="me" msgid="6207584824693813140">"Eu"</string>
<string name="power_dialog" product="tablet" msgid="8333207765671417261">"Opções do tablet"</string>
<string name="power_dialog" product="tv" msgid="7792839006640933763">"Opções do Android TV"</string>
@@ -1130,10 +1128,10 @@
<string name="whichViewApplication" msgid="5733194231473132945">"Abrir com"</string>
<string name="whichViewApplicationNamed" msgid="415164730629690105">"Abrir com %1$s"</string>
<string name="whichViewApplicationLabel" msgid="7367556735684742409">"Abrir"</string>
- <string name="whichOpenHostLinksWith" msgid="7645631470199397485">"Abrir links do domínio <xliff:g id="HOST">%1$s</xliff:g> com"</string>
+ <string name="whichOpenHostLinksWith" msgid="7645631470199397485">"Abrir links do domínio <xliff:g id="HOST">%1$s</xliff:g> usando"</string>
<string name="whichOpenLinksWith" msgid="1120936181362907258">"Abrir links com"</string>
<string name="whichOpenLinksWithApp" msgid="6917864367861910086">"Abrir links com <xliff:g id="APPLICATION">%1$s</xliff:g>"</string>
- <string name="whichOpenHostLinksWithApp" msgid="2401668560768463004">"Abrir links do domínio <xliff:g id="HOST">%1$s</xliff:g> com <xliff:g id="APPLICATION">%2$s</xliff:g>"</string>
+ <string name="whichOpenHostLinksWithApp" msgid="2401668560768463004">"Abrir links do domínio <xliff:g id="HOST">%1$s</xliff:g> usando <xliff:g id="APPLICATION">%2$s</xliff:g>"</string>
<string name="whichGiveAccessToApplicationLabel" msgid="7805857277166106236">"Conceder acesso"</string>
<string name="whichEditApplication" msgid="6191568491456092812">"Editar com"</string>
<string name="whichEditApplicationNamed" msgid="8096494987978521514">"Editar com %1$s"</string>
@@ -2059,12 +2057,12 @@
<string name="resolver_work_tab_accessibility" msgid="4753168230363802734">"Visualização de trabalho"</string>
<string name="resolver_cant_share_with_work_apps" msgid="637686613606502219">"Não é possível compartilhar este conteúdo com apps de trabalho"</string>
<string name="resolver_cant_share_with_work_apps_explanation" msgid="3332302070341130545">"Seu administrador de TI não permite que você compartilhe este conteúdo com apps no seu perfil de trabalho"</string>
- <string name="resolver_cant_access_work_apps" msgid="2455757966397563223">"Não é possível abrir com apps de trabalho"</string>
- <string name="resolver_cant_access_work_apps_explanation" msgid="3626983885525445790">"Seu administrador de TI não permite que você abra este conteúdo com apps no seu perfil de trabalho"</string>
+ <string name="resolver_cant_access_work_apps" msgid="2455757966397563223">"Não é possível abrir usando apps de trabalho"</string>
+ <string name="resolver_cant_access_work_apps_explanation" msgid="3626983885525445790">"Seu administrador de TI não permite que você abra este conteúdo usando apps do seu perfil de trabalho"</string>
<string name="resolver_cant_share_with_personal_apps" msgid="3079139799233316203">"Não é possível compartilhar este conteúdo com apps pessoais"</string>
<string name="resolver_cant_share_with_personal_apps_explanation" msgid="2959282422751315171">"Seu administrador de TI não permite que você compartilhe este conteúdo com apps no seu perfil pessoal"</string>
<string name="resolver_cant_access_personal_apps" msgid="648291604475669395">"Não é possível abrir este conteúdo com apps pessoais"</string>
- <string name="resolver_cant_access_personal_apps_explanation" msgid="2298773629302296519">"Seu administrador de TI não permite que você abra este conteúdo com apps no seu perfil pessoal"</string>
+ <string name="resolver_cant_access_personal_apps_explanation" msgid="2298773629302296519">"Seu administrador de TI não permite que você abra este conteúdo usando apps do seu perfil pessoal"</string>
<string name="resolver_turn_on_work_apps" msgid="884910835250037247">"O perfil de trabalho está pausado"</string>
<string name="resolver_switch_on_work" msgid="2873009160846966379">"Ativar"</string>
<string name="resolver_no_work_apps_available_share" msgid="7933949011797699505">"Apps de trabalho não são compatíveis com este conteúdo"</string>
diff --git a/core/res/res/values-ro/strings.xml b/core/res/res/values-ro/strings.xml
index 891c6eda1c23..aeaceca65c65 100644
--- a/core/res/res/values-ro/strings.xml
+++ b/core/res/res/values-ro/strings.xml
@@ -204,10 +204,8 @@
<string name="printing_disabled_by" msgid="3517499806528864633">"Printare dezactivată de <xliff:g id="OWNER_APP">%s</xliff:g>."</string>
<string name="personal_apps_suspension_title" msgid="7561416677884286600">"Activați profilul de serviciu"</string>
<string name="personal_apps_suspension_text" msgid="6115455688932935597">"Aplicațiile personale sunt blocate până când activați profilul de serviciu"</string>
- <!-- no translation found for personal_apps_suspension_soon_text (8123898693479590) -->
- <skip />
- <!-- no translation found for personal_apps_suspended_turn_profile_on (2758012869627513689) -->
- <skip />
+ <string name="personal_apps_suspension_soon_text" msgid="8123898693479590">"Aplicațiile personale vor fi blocate pe <xliff:g id="DATE">%1$s</xliff:g>, la <xliff:g id="TIME">%2$s</xliff:g>. Administratorul IT nu permite ca profilul de serviciu să fie dezactivat mai mult de <xliff:g id="NUMBER">%3$d</xliff:g> zile."</string>
+ <string name="personal_apps_suspended_turn_profile_on" msgid="2758012869627513689">"Activați"</string>
<string name="me" msgid="6207584824693813140">"Eu"</string>
<string name="power_dialog" product="tablet" msgid="8333207765671417261">"Opțiuni tablet PC"</string>
<string name="power_dialog" product="tv" msgid="7792839006640933763">"Opțiuni pentru Android TV"</string>
@@ -2092,7 +2090,7 @@
<string name="resolver_personal_tab_accessibility" msgid="5739524949153091224">"Afișarea conținutului personal"</string>
<string name="resolver_work_tab_accessibility" msgid="4753168230363802734">"Afișarea conținutului de lucru"</string>
<string name="resolver_cant_share_with_work_apps" msgid="637686613606502219">"Nu se poate trimite către aplicații pentru lucru"</string>
- <string name="resolver_cant_share_with_work_apps_explanation" msgid="3332302070341130545">"Administratorul IT nu vă permite să trimiteți acest conținut cu aplicațiile din profilul de serviciu"</string>
+ <string name="resolver_cant_share_with_work_apps_explanation" msgid="3332302070341130545">"Administratorul IT nu vă permite să trimiteți acest conținut către aplicațiile din profilul de serviciu"</string>
<string name="resolver_cant_access_work_apps" msgid="2455757966397563223">"Nu se poate deschide cu aplicații pentru lucru"</string>
<string name="resolver_cant_access_work_apps_explanation" msgid="3626983885525445790">"Administratorul IT nu vă permite să deschideți acest conținut cu aplicațiile din profilul de serviciu"</string>
<string name="resolver_cant_share_with_personal_apps" msgid="3079139799233316203">"Nu se poate trimite către aplicații personale"</string>
diff --git a/core/res/res/values-ru/strings.xml b/core/res/res/values-ru/strings.xml
index 58806e99d567..83dd3e23c702 100644
--- a/core/res/res/values-ru/strings.xml
+++ b/core/res/res/values-ru/strings.xml
@@ -63,7 +63,7 @@
<string name="ColpMmi" msgid="4736462893284419302">"Идентификатор подключенной линии"</string>
<string name="ColrMmi" msgid="5889782479745764278">"Ограничение идентификатора подключенной линии"</string>
<string name="CfMmi" msgid="8390012691099787178">"Переадресация вызовов"</string>
- <string name="CwMmi" msgid="3164609577675404761">"Параллельный вызов"</string>
+ <string name="CwMmi" msgid="3164609577675404761">"Ожидание вызова"</string>
<string name="BaMmi" msgid="7205614070543372167">"Запрет вызовов"</string>
<string name="PwdMmi" msgid="3360991257288638281">"Смена пароля"</string>
<string name="PinMmi" msgid="7133542099618330959">"Смена PIN"</string>
@@ -206,10 +206,8 @@
<string name="printing_disabled_by" msgid="3517499806528864633">"Функция печати отключена приложением \"<xliff:g id="OWNER_APP">%s</xliff:g>\""</string>
<string name="personal_apps_suspension_title" msgid="7561416677884286600">"Включите рабочий профиль"</string>
<string name="personal_apps_suspension_text" msgid="6115455688932935597">"Личные приложения будут заблокированы, пока вы не включите рабочий профиль."</string>
- <!-- no translation found for personal_apps_suspension_soon_text (8123898693479590) -->
- <skip />
- <!-- no translation found for personal_apps_suspended_turn_profile_on (2758012869627513689) -->
- <skip />
+ <string name="personal_apps_suspension_soon_text" msgid="8123898693479590">"Личные приложения будут заблокированы <xliff:g id="DATE">%1$s</xliff:g> в <xliff:g id="TIME">%2$s</xliff:g>. Системный администратор запретил отключать рабочий профиль более чем на <xliff:g id="NUMBER">%3$d</xliff:g> дн."</string>
+ <string name="personal_apps_suspended_turn_profile_on" msgid="2758012869627513689">"Включить"</string>
<string name="me" msgid="6207584824693813140">"Я"</string>
<string name="power_dialog" product="tablet" msgid="8333207765671417261">"Настройки планшетного ПК"</string>
<string name="power_dialog" product="tv" msgid="7792839006640933763">"Настройки Android TV"</string>
@@ -2133,7 +2131,7 @@
<string name="resolver_cant_share_with_personal_apps_explanation" msgid="2959282422751315171">"Системный администратор запретил делиться этим контентом с приложениями из личного профиля."</string>
<string name="resolver_cant_access_personal_apps" msgid="648291604475669395">"Этот контент нельзя открывать в личных приложениях"</string>
<string name="resolver_cant_access_personal_apps_explanation" msgid="2298773629302296519">"Системный администратор запретил открывать этот контент, используя приложения из личного профиля."</string>
- <string name="resolver_turn_on_work_apps" msgid="884910835250037247">"Рабочий профиль приостановлен."</string>
+ <string name="resolver_turn_on_work_apps" msgid="884910835250037247">"Действие рабочего профиля приостановлено."</string>
<string name="resolver_switch_on_work" msgid="2873009160846966379">"Включить"</string>
<string name="resolver_no_work_apps_available_share" msgid="7933949011797699505">"Нет рабочих приложений, поддерживающих этот контент."</string>
<string name="resolver_no_work_apps_available_resolve" msgid="1244844292366099399">"Нет рабочих приложений, с помощью которых можно открыть этот контент."</string>
diff --git a/core/res/res/values-si/strings.xml b/core/res/res/values-si/strings.xml
index fecfa1e784df..e61b4e8696a3 100644
--- a/core/res/res/values-si/strings.xml
+++ b/core/res/res/values-si/strings.xml
@@ -202,10 +202,8 @@
<string name="printing_disabled_by" msgid="3517499806528864633">"<xliff:g id="OWNER_APP">%s</xliff:g> විසින් මුද්‍රණය කිරීම අබල කර ඇත."</string>
<string name="personal_apps_suspension_title" msgid="7561416677884286600">"ඔබේ කාර්යාල පැතිකඩ ඔන් කරන්න"</string>
<string name="personal_apps_suspension_text" msgid="6115455688932935597">"ඔබ ඔබගේ කාර්යාල පැතිකඩ ක්‍රියාත්මක කරන තෙක් ඔබගේ පෞද්ගලික යෙදුම් අවහිර කර ඇත"</string>
- <!-- no translation found for personal_apps_suspension_soon_text (8123898693479590) -->
- <skip />
- <!-- no translation found for personal_apps_suspended_turn_profile_on (2758012869627513689) -->
- <skip />
+ <string name="personal_apps_suspension_soon_text" msgid="8123898693479590">"පෞද්ගලික යෙදුම් <xliff:g id="DATE">%1$s</xliff:g> දින <xliff:g id="TIME">%2$s</xliff:g>ට අවහිර වනු ඇත. ඔබේ IT පරිපාලක ඔබේ කාර්යාල පැතිකඩ දින <xliff:g id="NUMBER">%3$d</xliff:g>කට වඩා ඉවත් කර තැබීමට ඉඩ නොදේ."</string>
+ <string name="personal_apps_suspended_turn_profile_on" msgid="2758012869627513689">"ක්‍රියාත්මක කරන්න"</string>
<string name="me" msgid="6207584824693813140">"මම"</string>
<string name="power_dialog" product="tablet" msgid="8333207765671417261">"ටැබ්ලට විකල්ප"</string>
<string name="power_dialog" product="tv" msgid="7792839006640933763">"Android TV විකල්ප"</string>
diff --git a/core/res/res/values-sk/strings.xml b/core/res/res/values-sk/strings.xml
index c218f28133d9..be1d8c1fef18 100644
--- a/core/res/res/values-sk/strings.xml
+++ b/core/res/res/values-sk/strings.xml
@@ -206,10 +206,8 @@
<string name="printing_disabled_by" msgid="3517499806528864633">"Tlač zakázala aplikácia <xliff:g id="OWNER_APP">%s</xliff:g>."</string>
<string name="personal_apps_suspension_title" msgid="7561416677884286600">"Zapnite svoj pracovný profil"</string>
<string name="personal_apps_suspension_text" msgid="6115455688932935597">"Vaše osobné aplikácie sú zablokované, dokým nezapnete svoj pracovný profil"</string>
- <!-- no translation found for personal_apps_suspension_soon_text (8123898693479590) -->
- <skip />
- <!-- no translation found for personal_apps_suspended_turn_profile_on (2758012869627513689) -->
- <skip />
+ <string name="personal_apps_suspension_soon_text" msgid="8123898693479590">"Osobné aplikácie budú <xliff:g id="DATE">%1$s</xliff:g> o <xliff:g id="TIME">%2$s</xliff:g> zablokované. Váš správca IT nepovoľuje, aby váš pracovný profil bol vypnutý viac ako <xliff:g id="NUMBER">%3$d</xliff:g> d."</string>
+ <string name="personal_apps_suspended_turn_profile_on" msgid="2758012869627513689">"Zapnúť"</string>
<string name="me" msgid="6207584824693813140">"Ja"</string>
<string name="power_dialog" product="tablet" msgid="8333207765671417261">"Možnosti tabletu"</string>
<string name="power_dialog" product="tv" msgid="7792839006640933763">"Možnosti zariadenia Android TV"</string>
@@ -245,7 +243,7 @@
<string name="global_action_power_off" msgid="4404936470711393203">"Vypnúť"</string>
<string name="global_action_power_options" msgid="1185286119330160073">"Vypnutie"</string>
<string name="global_action_restart" msgid="4678451019561687074">"Reštartovať"</string>
- <string name="global_action_emergency" msgid="1387617624177105088">"Tiesňový režim"</string>
+ <string name="global_action_emergency" msgid="1387617624177105088">"Tieseň"</string>
<string name="global_action_bug_report" msgid="5127867163044170003">"Hlásenie o chybách"</string>
<string name="global_action_logout" msgid="6093581310002476511">"Ukončiť reláciu"</string>
<string name="global_action_screenshot" msgid="2610053466156478564">"Snímka obrazovky"</string>
@@ -1170,10 +1168,10 @@
<string name="whichViewApplication" msgid="5733194231473132945">"Otvoriť v aplikácii"</string>
<string name="whichViewApplicationNamed" msgid="415164730629690105">"Otvoriť v aplikácii %1$s"</string>
<string name="whichViewApplicationLabel" msgid="7367556735684742409">"Otvoriť"</string>
- <string name="whichOpenHostLinksWith" msgid="7645631470199397485">"Otvárajte odkazy z webu <xliff:g id="HOST">%1$s</xliff:g> v prehliadači alebo aplikácii"</string>
- <string name="whichOpenLinksWith" msgid="1120936181362907258">"Otvárajte odkazy v prehliadači"</string>
- <string name="whichOpenLinksWithApp" msgid="6917864367861910086">"Otvárajte odkazy v prehliadači <xliff:g id="APPLICATION">%1$s</xliff:g>"</string>
- <string name="whichOpenHostLinksWithApp" msgid="2401668560768463004">"Otvárajte odkazy z webu <xliff:g id="HOST">%1$s</xliff:g> v prehliadači <xliff:g id="APPLICATION">%2$s</xliff:g>"</string>
+ <string name="whichOpenHostLinksWith" msgid="7645631470199397485">"Otvárať odkazy <xliff:g id="HOST">%1$s</xliff:g> v aplikácii"</string>
+ <string name="whichOpenLinksWith" msgid="1120936181362907258">"Otvárať odkazy v aplikácii"</string>
+ <string name="whichOpenLinksWithApp" msgid="6917864367861910086">"Otvárať odkazy v aplikácii <xliff:g id="APPLICATION">%1$s</xliff:g>"</string>
+ <string name="whichOpenHostLinksWithApp" msgid="2401668560768463004">"Otvárať odkazy <xliff:g id="HOST">%1$s</xliff:g> v aplikácii <xliff:g id="APPLICATION">%2$s</xliff:g>"</string>
<string name="whichGiveAccessToApplicationLabel" msgid="7805857277166106236">"Udeliť prístup"</string>
<string name="whichEditApplication" msgid="6191568491456092812">"Upraviť pomocou"</string>
<string name="whichEditApplicationNamed" msgid="8096494987978521514">"Upraviť v aplikácii %1$s"</string>
@@ -2126,13 +2124,13 @@
<string name="resolver_personal_tab_accessibility" msgid="5739524949153091224">"Osobné zobrazenie"</string>
<string name="resolver_work_tab_accessibility" msgid="4753168230363802734">"Pracovné zobrazenie"</string>
<string name="resolver_cant_share_with_work_apps" msgid="637686613606502219">"Nedá sa zdieľať s pracovnými aplikáciami"</string>
- <string name="resolver_cant_share_with_work_apps_explanation" msgid="3332302070341130545">"Správca IT vám zakázal zdieľať tento obsah pomocou aplikácií v pracovnom profile"</string>
+ <string name="resolver_cant_share_with_work_apps_explanation" msgid="3332302070341130545">"Váš správca IT vám zakázal zdieľať tento obsah pomocou aplikácií v pracovnom profile"</string>
<string name="resolver_cant_access_work_apps" msgid="2455757966397563223">"Nedá sa otvoriť pomocou pracovných aplikácií"</string>
- <string name="resolver_cant_access_work_apps_explanation" msgid="3626983885525445790">"Správca IT vám zakázal otvoriť tento obsah pomocou aplikácií v pracovnom profile"</string>
+ <string name="resolver_cant_access_work_apps_explanation" msgid="3626983885525445790">"Váš správca IT vám zakázal otvárať tento obsah pomocou aplikácií v pracovnom profile"</string>
<string name="resolver_cant_share_with_personal_apps" msgid="3079139799233316203">"Nedá sa zdieľať pomocou osobných aplikácií"</string>
- <string name="resolver_cant_share_with_personal_apps_explanation" msgid="2959282422751315171">"Správca IT vám zakázal zdieľať tento obsah pomocou aplikácií v osobnom profile"</string>
+ <string name="resolver_cant_share_with_personal_apps_explanation" msgid="2959282422751315171">"Váš správca IT vám zakázal zdieľať tento obsah pomocou aplikácií v osobnom profile"</string>
<string name="resolver_cant_access_personal_apps" msgid="648291604475669395">"Nedá sa otvoriť pomocou osobných aplikácií"</string>
- <string name="resolver_cant_access_personal_apps_explanation" msgid="2298773629302296519">"Správca IT vám zakázal otvoriť tento obsah pomocou aplikácií v osobnom profile"</string>
+ <string name="resolver_cant_access_personal_apps_explanation" msgid="2298773629302296519">"Váš správca IT vám zakázal otvárať tento obsah pomocou aplikácií v osobnom profile"</string>
<string name="resolver_turn_on_work_apps" msgid="884910835250037247">"Pracovný profil je pozastavený"</string>
<string name="resolver_switch_on_work" msgid="2873009160846966379">"Zapnúť"</string>
<string name="resolver_no_work_apps_available_share" msgid="7933949011797699505">"Tento obsah nepodporujú žiadne pracovné aplikácie"</string>
diff --git a/core/res/res/values-sl/strings.xml b/core/res/res/values-sl/strings.xml
index 1bb856ee16e0..ec8bf51890a0 100644
--- a/core/res/res/values-sl/strings.xml
+++ b/core/res/res/values-sl/strings.xml
@@ -206,10 +206,8 @@
<string name="printing_disabled_by" msgid="3517499806528864633">"Tiskanje je onemogočil pravilnik <xliff:g id="OWNER_APP">%s</xliff:g>."</string>
<string name="personal_apps_suspension_title" msgid="7561416677884286600">"Vklopite delovni profil"</string>
<string name="personal_apps_suspension_text" msgid="6115455688932935597">"Osebne aplikacije so blokirane, dokler ne vklopite delovnega profila"</string>
- <!-- no translation found for personal_apps_suspension_soon_text (8123898693479590) -->
- <skip />
- <!-- no translation found for personal_apps_suspended_turn_profile_on (2758012869627513689) -->
- <skip />
+ <string name="personal_apps_suspension_soon_text" msgid="8123898693479590">"Osebne aplikacije bodo blokirane <xliff:g id="DATE">%1$s</xliff:g> ob <xliff:g id="TIME">%2$s</xliff:g>. Skrbnik za IT ne dovoli, da bi bil delovni profil izklopljen več kot toliko dni: <xliff:g id="NUMBER">%3$d</xliff:g>."</string>
+ <string name="personal_apps_suspended_turn_profile_on" msgid="2758012869627513689">"Vklopi"</string>
<string name="me" msgid="6207584824693813140">"Jaz"</string>
<string name="power_dialog" product="tablet" msgid="8333207765671417261">"Možnosti tabličnega računalnika"</string>
<string name="power_dialog" product="tv" msgid="7792839006640933763">"Možnosti naprave Android TV"</string>
diff --git a/core/res/res/values-sq/strings.xml b/core/res/res/values-sq/strings.xml
index bea3b724591d..16d7a7bb110c 100644
--- a/core/res/res/values-sq/strings.xml
+++ b/core/res/res/values-sq/strings.xml
@@ -202,10 +202,8 @@
<string name="printing_disabled_by" msgid="3517499806528864633">"Printimi është çaktivizuar nga <xliff:g id="OWNER_APP">%s</xliff:g>."</string>
<string name="personal_apps_suspension_title" msgid="7561416677884286600">"Aktivizo profilin e punës"</string>
<string name="personal_apps_suspension_text" msgid="6115455688932935597">"Aplikacionet e tua personale janë bllokuar derisa të aktivizosh profilin tënd të punës"</string>
- <!-- no translation found for personal_apps_suspension_soon_text (8123898693479590) -->
- <skip />
- <!-- no translation found for personal_apps_suspended_turn_profile_on (2758012869627513689) -->
- <skip />
+ <string name="personal_apps_suspension_soon_text" msgid="8123898693479590">"Aplikacionet personale do të bllokohen më <xliff:g id="DATE">%1$s</xliff:g> në <xliff:g id="TIME">%2$s</xliff:g>. Administratori yt i teknologjisë së informacionit nuk lejon që profili yt i punës të qëndrojë joaktiv për më shumë se <xliff:g id="NUMBER">%3$d</xliff:g> ditë."</string>
+ <string name="personal_apps_suspended_turn_profile_on" msgid="2758012869627513689">"Aktivizo"</string>
<string name="me" msgid="6207584824693813140">"Unë"</string>
<string name="power_dialog" product="tablet" msgid="8333207765671417261">"Opsionet e tabletit"</string>
<string name="power_dialog" product="tv" msgid="7792839006640933763">"Opsionet e Android TV"</string>
@@ -1161,7 +1159,7 @@
<string name="aerr_application_repeated" msgid="7804378743218496566">"<xliff:g id="APPLICATION">%1$s</xliff:g> vazhdon të ndalojë"</string>
<string name="aerr_process_repeated" msgid="1153152413537954974">"<xliff:g id="PROCESS">%1$s</xliff:g> vazhdon të ndalojë"</string>
<string name="aerr_restart" msgid="2789618625210505419">"Hap përsëri aplikacionin"</string>
- <string name="aerr_report" msgid="3095644466849299308">"Dërgo koment"</string>
+ <string name="aerr_report" msgid="3095644466849299308">"Dërgo reagim"</string>
<string name="aerr_close" msgid="3398336821267021852">"Mbyll"</string>
<string name="aerr_mute" msgid="2304972923480211376">"Vendose në heshtje deri kur të riniset pajisja"</string>
<string name="aerr_wait" msgid="3198677780474548217">"Prit!"</string>
diff --git a/core/res/res/values-sr/strings.xml b/core/res/res/values-sr/strings.xml
index 46b2b6c0129a..269755a8cf76 100644
--- a/core/res/res/values-sr/strings.xml
+++ b/core/res/res/values-sr/strings.xml
@@ -204,10 +204,8 @@
<string name="printing_disabled_by" msgid="3517499806528864633">"Штампање је онемогућила апликација <xliff:g id="OWNER_APP">%s</xliff:g>."</string>
<string name="personal_apps_suspension_title" msgid="7561416677884286600">"Укључите пословни профил"</string>
<string name="personal_apps_suspension_text" msgid="6115455688932935597">"Личне апликације су блокиране док не укључите пословни профил"</string>
- <!-- no translation found for personal_apps_suspension_soon_text (8123898693479590) -->
- <skip />
- <!-- no translation found for personal_apps_suspended_turn_profile_on (2758012869627513689) -->
- <skip />
+ <string name="personal_apps_suspension_soon_text" msgid="8123898693479590">"Личне апликације ће бити блокиране: <xliff:g id="DATE">%1$s</xliff:g> у <xliff:g id="TIME">%2$s</xliff:g>. ИТ администратор не дозвољава да пословни профил буде искључен дуже од <xliff:g id="NUMBER">%3$d</xliff:g> дана."</string>
+ <string name="personal_apps_suspended_turn_profile_on" msgid="2758012869627513689">"Укључи"</string>
<string name="me" msgid="6207584824693813140">"Ја"</string>
<string name="power_dialog" product="tablet" msgid="8333207765671417261">"Опције за таблет"</string>
<string name="power_dialog" product="tv" msgid="7792839006640933763">"Опције Android TV-а"</string>
@@ -1151,7 +1149,7 @@
<string name="whichViewApplicationNamed" msgid="415164730629690105">"Отворите помоћу апликације %1$s"</string>
<string name="whichViewApplicationLabel" msgid="7367556735684742409">"Отвори"</string>
<string name="whichOpenHostLinksWith" msgid="7645631470199397485">"Отварајте <xliff:g id="HOST">%1$s</xliff:g> линкове помоћу"</string>
- <string name="whichOpenLinksWith" msgid="1120936181362907258">"Отваратеј линкове помоћу"</string>
+ <string name="whichOpenLinksWith" msgid="1120936181362907258">"Отварај линкове помоћу"</string>
<string name="whichOpenLinksWithApp" msgid="6917864367861910086">"Отварајте линкове помоћу апликације <xliff:g id="APPLICATION">%1$s</xliff:g>"</string>
<string name="whichOpenHostLinksWithApp" msgid="2401668560768463004">"Отварајте <xliff:g id="HOST">%1$s</xliff:g> линкове помоћу апликације <xliff:g id="APPLICATION">%2$s</xliff:g>"</string>
<string name="whichGiveAccessToApplicationLabel" msgid="7805857277166106236">"Дозволи приступ"</string>
@@ -2101,7 +2099,7 @@
<string name="resolver_cant_access_personal_apps_explanation" msgid="2298773629302296519">"ИТ администратор вам не дозвољава да отворите овај садржај помоћу апликација на личном профилу"</string>
<string name="resolver_turn_on_work_apps" msgid="884910835250037247">"Пословни профил је паузиран"</string>
<string name="resolver_switch_on_work" msgid="2873009160846966379">"Укључи"</string>
- <string name="resolver_no_work_apps_available_share" msgid="7933949011797699505">"Ниједна апликација за посао не може да подржава овај садржај"</string>
+ <string name="resolver_no_work_apps_available_share" msgid="7933949011797699505">"Ниједна апликација за посао не подржава овај садржај"</string>
<string name="resolver_no_work_apps_available_resolve" msgid="1244844292366099399">"Ниједна апликација за посао не може да отвори овај садржај"</string>
<string name="resolver_no_personal_apps_available_share" msgid="5639102815174748732">"Ниједна лична апликација не може да подржава овај садржај"</string>
<string name="resolver_no_personal_apps_available_resolve" msgid="5120671970531446978">"Ниједна лична апликација не може да отвори овај садржај"</string>
diff --git a/core/res/res/values-sv/strings.xml b/core/res/res/values-sv/strings.xml
index d9ee54e202b8..566d85f24c08 100644
--- a/core/res/res/values-sv/strings.xml
+++ b/core/res/res/values-sv/strings.xml
@@ -202,10 +202,8 @@
<string name="printing_disabled_by" msgid="3517499806528864633">"Utskrift har inaktiverats av <xliff:g id="OWNER_APP">%s</xliff:g>."</string>
<string name="personal_apps_suspension_title" msgid="7561416677884286600">"Aktivera jobbprofilen"</string>
<string name="personal_apps_suspension_text" msgid="6115455688932935597">"Privata appar blockeras tills du aktiverar jobbprofilen"</string>
- <!-- no translation found for personal_apps_suspension_soon_text (8123898693479590) -->
- <skip />
- <!-- no translation found for personal_apps_suspended_turn_profile_on (2758012869627513689) -->
- <skip />
+ <string name="personal_apps_suspension_soon_text" msgid="8123898693479590">"Privata appar blockeras den <xliff:g id="DATE">%1$s</xliff:g> kl. <xliff:g id="TIME">%2$s</xliff:g>. IT-administratören tillåter inte att din jobbprofil är inaktiverad i mer än <xliff:g id="NUMBER">%3$d</xliff:g> dagar."</string>
+ <string name="personal_apps_suspended_turn_profile_on" msgid="2758012869627513689">"Aktivera"</string>
<string name="me" msgid="6207584824693813140">"Jag"</string>
<string name="power_dialog" product="tablet" msgid="8333207765671417261">"Alternativ för surfplattan"</string>
<string name="power_dialog" product="tv" msgid="7792839006640933763">"Alternativ för Android TV"</string>
diff --git a/core/res/res/values-sw/strings.xml b/core/res/res/values-sw/strings.xml
index 2f3361794dda..f4745c6c9bfd 100644
--- a/core/res/res/values-sw/strings.xml
+++ b/core/res/res/values-sw/strings.xml
@@ -202,10 +202,8 @@
<string name="printing_disabled_by" msgid="3517499806528864633">"Kipengele cha kuchapisha kimezimwa na <xliff:g id="OWNER_APP">%s</xliff:g>."</string>
<string name="personal_apps_suspension_title" msgid="7561416677884286600">"Washa wasifu wako wa kazini"</string>
<string name="personal_apps_suspension_text" msgid="6115455688932935597">"Programu zako za binafsi zimezuiwa hadi uwashe wasifu wako wa kazini"</string>
- <!-- no translation found for personal_apps_suspension_soon_text (8123898693479590) -->
- <skip />
- <!-- no translation found for personal_apps_suspended_turn_profile_on (2758012869627513689) -->
- <skip />
+ <string name="personal_apps_suspension_soon_text" msgid="8123898693479590">"Programu za binafsi zitazuiwa tarehe <xliff:g id="DATE">%1$s</xliff:g> saa <xliff:g id="TIME">%2$s</xliff:g>. Msimamizi wako wa TEHAMA haruhusu wasifu wako wa kazini kuzimwa kwa zaidi ya siku <xliff:g id="NUMBER">%3$d</xliff:g>."</string>
+ <string name="personal_apps_suspended_turn_profile_on" msgid="2758012869627513689">"Washa"</string>
<string name="me" msgid="6207584824693813140">"Mimi"</string>
<string name="power_dialog" product="tablet" msgid="8333207765671417261">"Chaguo za kompyuta ndogo"</string>
<string name="power_dialog" product="tv" msgid="7792839006640933763">"Chaguo za Android TV"</string>
@@ -2057,11 +2055,11 @@
<string name="resolver_work_tab" msgid="2690019516263167035">"Kazini"</string>
<string name="resolver_personal_tab_accessibility" msgid="5739524949153091224">"Mwonekano wa binafsi"</string>
<string name="resolver_work_tab_accessibility" msgid="4753168230363802734">"Mwonekano wa kazini"</string>
- <string name="resolver_cant_share_with_work_apps" msgid="637686613606502219">"Imeshindwa kushiriki maudhui haya na programu za kazini"</string>
+ <string name="resolver_cant_share_with_work_apps" msgid="637686613606502219">"Huwezi kushiriki maudhui haya na programu za kazini"</string>
<string name="resolver_cant_share_with_work_apps_explanation" msgid="3332302070341130545">"Msimamizi wako wa TEHAMA hakuruhusu ushiriki maudhui haya ukitumia programu zilizo kwenye wasifu wako wa kazini"</string>
<string name="resolver_cant_access_work_apps" msgid="2455757966397563223">"Huwezi kufungua maudhui haya ukitumia programu za kazini"</string>
<string name="resolver_cant_access_work_apps_explanation" msgid="3626983885525445790">"Msimamizi wako wa TEHAMA hakuruhusu ufungue maudhui haya ukitumia programu zilizo kwenye wasifu wako wa kazini"</string>
- <string name="resolver_cant_share_with_personal_apps" msgid="3079139799233316203">"Imeshindwa kushiriki maudhui haya na programu za binafsi"</string>
+ <string name="resolver_cant_share_with_personal_apps" msgid="3079139799233316203">"Huwezi kushiriki maudhui haya na programu za binafsi"</string>
<string name="resolver_cant_share_with_personal_apps_explanation" msgid="2959282422751315171">"Msimamizi wako wa TEHAMA hakuruhusu ushiriki maudhui haya ukitumia programu zilizo kwenye wasifu wako wa binafsi"</string>
<string name="resolver_cant_access_personal_apps" msgid="648291604475669395">"Huwezi kufungua maudhui haya ukitumia programu za binafsi"</string>
<string name="resolver_cant_access_personal_apps_explanation" msgid="2298773629302296519">"Msimamizi wako wa TEHAMA hakuruhusu ufungue maudhui haya ukitumia programu zilizo kwenye wasifu wako wa binafsi"</string>
diff --git a/core/res/res/values-ta/strings.xml b/core/res/res/values-ta/strings.xml
index cc698c51fafd..2eb8c87e68e1 100644
--- a/core/res/res/values-ta/strings.xml
+++ b/core/res/res/values-ta/strings.xml
@@ -202,10 +202,8 @@
<string name="printing_disabled_by" msgid="3517499806528864633">"பிரிண்ட் செய்வதை <xliff:g id="OWNER_APP">%s</xliff:g> தடுத்துள்ளது."</string>
<string name="personal_apps_suspension_title" msgid="7561416677884286600">"பணிக் கணக்கை ஆன் செய்யுங்கள்"</string>
<string name="personal_apps_suspension_text" msgid="6115455688932935597">"பணிக் கணக்கை ஆன் செய்யும் வரை உங்கள் தனிப்பட்ட ஆப்ஸ் தடுக்கப்பட்டிருக்கும்"</string>
- <!-- no translation found for personal_apps_suspension_soon_text (8123898693479590) -->
- <skip />
- <!-- no translation found for personal_apps_suspended_turn_profile_on (2758012869627513689) -->
- <skip />
+ <string name="personal_apps_suspension_soon_text" msgid="8123898693479590">"<xliff:g id="DATE">%1$s</xliff:g> அன்று <xliff:g id="TIME">%2$s</xliff:g> நேரத்தில் தனிப்பட்ட ஆப்ஸ் தடுக்கப்படும். பணிக் கணக்கை <xliff:g id="NUMBER">%3$d</xliff:g> நாட்களுக்கு மேல் ஆஃப் செய்து வைத்திருப்பதை உங்கள் IT நிர்வாகி அனுமதிக்கவில்லை."</string>
+ <string name="personal_apps_suspended_turn_profile_on" msgid="2758012869627513689">"ஆன் செய்"</string>
<string name="me" msgid="6207584824693813140">"நான்"</string>
<string name="power_dialog" product="tablet" msgid="8333207765671417261">"டேப்லெட் விருப்பங்கள்"</string>
<string name="power_dialog" product="tv" msgid="7792839006640933763">"Android TV விருப்பத்தேர்வுகள்"</string>
diff --git a/core/res/res/values-te/strings.xml b/core/res/res/values-te/strings.xml
index b6de1ac49866..0251d721492a 100644
--- a/core/res/res/values-te/strings.xml
+++ b/core/res/res/values-te/strings.xml
@@ -202,10 +202,8 @@
<string name="printing_disabled_by" msgid="3517499806528864633">"ముద్రణ <xliff:g id="OWNER_APP">%s</xliff:g> ద్వారా నిలిపివేయబడింది."</string>
<string name="personal_apps_suspension_title" msgid="7561416677884286600">"మీ పని ప్రొఫైల్‌ను‌ ఆన్ చేయి"</string>
<string name="personal_apps_suspension_text" msgid="6115455688932935597">"మీరు మీ కార్యాలయ ప్రొఫైల్‌ను ప్రారంభించే వరకు, మీ వ్యక్తిగత యాప్‌లు బ్లాక్ చేయబడతాయి"</string>
- <!-- no translation found for personal_apps_suspension_soon_text (8123898693479590) -->
- <skip />
- <!-- no translation found for personal_apps_suspended_turn_profile_on (2758012869627513689) -->
- <skip />
+ <string name="personal_apps_suspension_soon_text" msgid="8123898693479590">"<xliff:g id="DATE">%1$s</xliff:g> తేదీన <xliff:g id="TIME">%2$s</xliff:g>కు వ్యక్తిగత యాప్‌లు బ్లాక్ చేయబడతాయి. <xliff:g id="NUMBER">%3$d</xliff:g> రోజులకు మించి మీ కార్యాలయ ప్రొఫైల్‌ను ఆఫ్‌లో ఉంచటానికి మీ IT అడ్మిన్ అనుమతించరు."</string>
+ <string name="personal_apps_suspended_turn_profile_on" msgid="2758012869627513689">"ఆన్ చేయి"</string>
<string name="me" msgid="6207584824693813140">"నేను"</string>
<string name="power_dialog" product="tablet" msgid="8333207765671417261">"టాబ్లెట్ ఎంపికలు"</string>
<string name="power_dialog" product="tv" msgid="7792839006640933763">"Android TV ఎంపికలు"</string>
@@ -2032,7 +2030,7 @@
<item quantity="other"><xliff:g id="FILE_NAME_2">%s</xliff:g> + <xliff:g id="COUNT_3">%d</xliff:g> ఫైల్‌లు</item>
<item quantity="one"><xliff:g id="FILE_NAME_0">%s</xliff:g> + <xliff:g id="COUNT_1">%d</xliff:g> ఫైల్</item>
</plurals>
- <string name="chooser_no_direct_share_targets" msgid="1511722103987329028">"ఎవరికి షేర్ చేయాలనేదానికి సంబంధించి సిఫార్సులేవీ లేవు"</string>
+ <string name="chooser_no_direct_share_targets" msgid="1511722103987329028">"ఎవరికి షేర్ చేయాలనే దానికి సంబంధించి సిఫార్సులేవీ లేవు"</string>
<string name="chooser_all_apps_button_label" msgid="3230427756238666328">"యాప్‌ల జాబితా"</string>
<string name="usb_device_resolve_prompt_warn" msgid="325871329788064199">"ఈ యాప్‌కు రికార్డ్ చేసే అనుమతి మంజూరు కాలేదు, అయినా ఈ USB పరికరం ద్వారా ఆడియోను క్యాప్చర్ చేయగలదు."</string>
<string name="accessibility_system_action_home_label" msgid="3234748160850301870">"హోమ్"</string>
@@ -2060,7 +2058,7 @@
<string name="resolver_cant_share_with_work_apps" msgid="637686613606502219">"వర్క్ యాప్‌లతో దీనిని షేర్ చేయడం సాధ్యపడదు"</string>
<string name="resolver_cant_share_with_work_apps_explanation" msgid="3332302070341130545">"మీ కార్యాలయ ప్రొఫైల్‌లోని యాప్‌లతో ఈ కంటెంట్‌ను మీరు షేర్ చేయడానికి మీ IT అడ్మిన్ అనుమతించరు"</string>
<string name="resolver_cant_access_work_apps" msgid="2455757966397563223">"వర్క్ యాప్‌లతో తెరవడం సాధ్యపడదు"</string>
- <string name="resolver_cant_access_work_apps_explanation" msgid="3626983885525445790">"మీ కార్యాలయ ప్రొఫైల్‌లోని యాప్‌లతో ఈ కంటెంట్‌ను మీరు తెరవడానికి మీ IT అడ్మిన్ అనుమతించరు"</string>
+ <string name="resolver_cant_access_work_apps_explanation" msgid="3626983885525445790">"కార్యాలయ ప్రొఫైల్‌లోని యాప్‌లతో ఈ కంటెంట్‌ను మీరు తెరవడానికి మీ IT అడ్మిన్ అనుమతించరు"</string>
<string name="resolver_cant_share_with_personal_apps" msgid="3079139799233316203">"వ్యక్తిగత యాప్‌లతో దీనిని షేర్ చేయడం సాధ్యపడదు"</string>
<string name="resolver_cant_share_with_personal_apps_explanation" msgid="2959282422751315171">"మీ వ్యక్తిగత ప్రొఫైల్‌లోని యాప్‌లతో ఈ కంటెంట్‌ను మీరు షేర్ చేయడానికి మీ IT అడ్మిన్ అనుమతించరు"</string>
<string name="resolver_cant_access_personal_apps" msgid="648291604475669395">"దీనిని, వ్యక్తిగత యాప్‌లతో తెరవడం సాధ్యపడదు"</string>
diff --git a/core/res/res/values-television/themes_device_defaults.xml b/core/res/res/values-television/themes_device_defaults.xml
index cb3d32815ea9..d6bdeee00a9f 100644
--- a/core/res/res/values-television/themes_device_defaults.xml
+++ b/core/res/res/values-television/themes_device_defaults.xml
@@ -33,5 +33,6 @@
<style name="Theme.DeviceDefault.Autofill.Light" parent="Theme.DeviceDefault.Autofill"/>
<style name="Theme.DeviceDefault.Light.Autofill.Save" parent="Theme.DeviceDefault.Autofill.Save"/>
- <style name="Theme.DeviceDefault.Resolver" parent="Theme.Leanback.Resolver" />
+ <style name="Theme.DeviceDefault.ResolverCommon" parent="Theme.Leanback.Resolver" />
+ <style name="Theme.DeviceDefault.Resolver" parent="Theme.DeviceDefault.ResolverCommon" />
</resources>
diff --git a/core/res/res/values-th/strings.xml b/core/res/res/values-th/strings.xml
index 84ca15ad2edf..683b22fa7396 100644
--- a/core/res/res/values-th/strings.xml
+++ b/core/res/res/values-th/strings.xml
@@ -202,10 +202,8 @@
<string name="printing_disabled_by" msgid="3517499806528864633">"<xliff:g id="OWNER_APP">%s</xliff:g> ปิดใช้การพิมพ์แล้ว"</string>
<string name="personal_apps_suspension_title" msgid="7561416677884286600">"เปิดโปรไฟล์งาน"</string>
<string name="personal_apps_suspension_text" msgid="6115455688932935597">"แอปส่วนตัวจะถูกบล็อกไว้จนกว่าคุณจะเปิดโปรไฟล์งาน"</string>
- <!-- no translation found for personal_apps_suspension_soon_text (8123898693479590) -->
- <skip />
- <!-- no translation found for personal_apps_suspended_turn_profile_on (2758012869627513689) -->
- <skip />
+ <string name="personal_apps_suspension_soon_text" msgid="8123898693479590">"แอปส่วนตัวจะถูกบล็อกในวันที่ <xliff:g id="DATE">%1$s</xliff:g> เวลา <xliff:g id="TIME">%2$s</xliff:g> ผู้ดูแลระบบไอทีไม่อนุญาตให้หยุดใช้โปรไฟล์งานเกิน <xliff:g id="NUMBER">%3$d</xliff:g> วัน"</string>
+ <string name="personal_apps_suspended_turn_profile_on" msgid="2758012869627513689">"เปิด"</string>
<string name="me" msgid="6207584824693813140">"ฉัน"</string>
<string name="power_dialog" product="tablet" msgid="8333207765671417261">"ตัวเลือกของแท็บเล็ต"</string>
<string name="power_dialog" product="tv" msgid="7792839006640933763">"ตัวเลือกของ Android TV"</string>
diff --git a/core/res/res/values-tl/strings.xml b/core/res/res/values-tl/strings.xml
index 395020d2ffc3..45c8e349e5f0 100644
--- a/core/res/res/values-tl/strings.xml
+++ b/core/res/res/values-tl/strings.xml
@@ -202,10 +202,8 @@
<string name="printing_disabled_by" msgid="3517499806528864633">"Na-disable ng <xliff:g id="OWNER_APP">%s</xliff:g> ang pag-print."</string>
<string name="personal_apps_suspension_title" msgid="7561416677884286600">"I-on ang profile sa trabaho"</string>
<string name="personal_apps_suspension_text" msgid="6115455688932935597">"Naka-block ang iyong mga personal na app hangga\'t hindi mo ino-on ang profile sa trabaho mo"</string>
- <!-- no translation found for personal_apps_suspension_soon_text (8123898693479590) -->
- <skip />
- <!-- no translation found for personal_apps_suspended_turn_profile_on (2758012869627513689) -->
- <skip />
+ <string name="personal_apps_suspension_soon_text" msgid="8123898693479590">"Iba-block ang mga personal na app sa <xliff:g id="DATE">%1$s</xliff:g> nang <xliff:g id="TIME">%2$s</xliff:g>. Hindi pinapayagan ng iyong IT admin na manatiling naka-off ang profile mo sa trabaho nang mahigit <xliff:g id="NUMBER">%3$d</xliff:g> (na) araw."</string>
+ <string name="personal_apps_suspended_turn_profile_on" msgid="2758012869627513689">"I-on"</string>
<string name="me" msgid="6207584824693813140">"Ako"</string>
<string name="power_dialog" product="tablet" msgid="8333207765671417261">"Mga pagpipilian sa tablet"</string>
<string name="power_dialog" product="tv" msgid="7792839006640933763">"Mga opsyon sa Android TV"</string>
diff --git a/core/res/res/values-tr/strings.xml b/core/res/res/values-tr/strings.xml
index c4da27c6de62..bb9ffc066917 100644
--- a/core/res/res/values-tr/strings.xml
+++ b/core/res/res/values-tr/strings.xml
@@ -202,10 +202,8 @@
<string name="printing_disabled_by" msgid="3517499806528864633">"Yazdırma işlemi <xliff:g id="OWNER_APP">%s</xliff:g> tarafından devre dışı bırakıldı."</string>
<string name="personal_apps_suspension_title" msgid="7561416677884286600">"İş profilinizi açın"</string>
<string name="personal_apps_suspension_text" msgid="6115455688932935597">"İş profilinizi açana kadar kişisel uygulamalarınız engellendi"</string>
- <!-- no translation found for personal_apps_suspension_soon_text (8123898693479590) -->
- <skip />
- <!-- no translation found for personal_apps_suspended_turn_profile_on (2758012869627513689) -->
- <skip />
+ <string name="personal_apps_suspension_soon_text" msgid="8123898693479590">"Kişisel uygulamalar <xliff:g id="DATE">%1$s</xliff:g> tarihinde saat <xliff:g id="TIME">%2$s</xliff:g> itibarıyla engellenecektir. BT yöneticiniz, iş profilinizin <xliff:g id="NUMBER">%3$d</xliff:g> günden fazla kapalı kalmasına izin vermiyor."</string>
+ <string name="personal_apps_suspended_turn_profile_on" msgid="2758012869627513689">"Aç"</string>
<string name="me" msgid="6207584824693813140">"Ben"</string>
<string name="power_dialog" product="tablet" msgid="8333207765671417261">"Tablet seçenekleri"</string>
<string name="power_dialog" product="tv" msgid="7792839006640933763">"Android TV seçenekleri"</string>
diff --git a/core/res/res/values-uk/strings.xml b/core/res/res/values-uk/strings.xml
index 46f9fc954e11..6b24d83e7038 100644
--- a/core/res/res/values-uk/strings.xml
+++ b/core/res/res/values-uk/strings.xml
@@ -206,10 +206,8 @@
<string name="printing_disabled_by" msgid="3517499806528864633">"Додаток <xliff:g id="OWNER_APP">%s</xliff:g> вимкнув друк."</string>
<string name="personal_apps_suspension_title" msgid="7561416677884286600">"Увімкніть робочий профіль"</string>
<string name="personal_apps_suspension_text" msgid="6115455688932935597">"Особисті додатки заблоковано, доки ви не ввімкнете робочий профіль"</string>
- <!-- no translation found for personal_apps_suspension_soon_text (8123898693479590) -->
- <skip />
- <!-- no translation found for personal_apps_suspended_turn_profile_on (2758012869627513689) -->
- <skip />
+ <string name="personal_apps_suspension_soon_text" msgid="8123898693479590">"Особисті додатки буде заблоковано <xliff:g id="DATE">%1$s</xliff:g> о <xliff:g id="TIME">%2$s</xliff:g>. Ваш ІТ-адміністратор не дозволяє, щоб робочий профіль був неактивний більше ніж <xliff:g id="NUMBER">%3$d</xliff:g> дн."</string>
+ <string name="personal_apps_suspended_turn_profile_on" msgid="2758012869627513689">"Увімкнути"</string>
<string name="me" msgid="6207584824693813140">"Я"</string>
<string name="power_dialog" product="tablet" msgid="8333207765671417261">"Парам. пристрою"</string>
<string name="power_dialog" product="tv" msgid="7792839006640933763">"Опції Android TV"</string>
@@ -2135,8 +2133,8 @@
<string name="resolver_cant_access_personal_apps_explanation" msgid="2298773629302296519">"Ваш ІТ-адміністратор не дозволяє відкривати цей контент у додатках в особистому профілі"</string>
<string name="resolver_turn_on_work_apps" msgid="884910835250037247">"Робочий профіль призупинено"</string>
<string name="resolver_switch_on_work" msgid="2873009160846966379">"Увімкнути"</string>
- <string name="resolver_no_work_apps_available_share" msgid="7933949011797699505">"Робочі додатки не можуть підтримувати цей контент"</string>
- <string name="resolver_no_work_apps_available_resolve" msgid="1244844292366099399">"Робочі додатки не можуть відкривати цей контент"</string>
+ <string name="resolver_no_work_apps_available_share" msgid="7933949011797699505">"Немає робочих додатків для цього контенту"</string>
+ <string name="resolver_no_work_apps_available_resolve" msgid="1244844292366099399">"Немає робочих додатків, щоб відкрити цей контент"</string>
<string name="resolver_no_personal_apps_available_share" msgid="5639102815174748732">"Особисті додатки не можуть підтримувати цей контент"</string>
<string name="resolver_no_personal_apps_available_resolve" msgid="5120671970531446978">"Особисті додатки не можуть відкривати цей контент"</string>
<string name="PERSOSUBSTATE_SIM_NETWORK_ENTRY" msgid="8050953231914637819">"PIN-код розблокування мережі SIM-карти"</string>
diff --git a/core/res/res/values-ur/strings.xml b/core/res/res/values-ur/strings.xml
index 3ec36bb9f7b0..b432f80fce0e 100644
--- a/core/res/res/values-ur/strings.xml
+++ b/core/res/res/values-ur/strings.xml
@@ -202,10 +202,8 @@
<string name="printing_disabled_by" msgid="3517499806528864633">"<xliff:g id="OWNER_APP">%s</xliff:g> نے پرنٹنگ کو غیر فعال کر دیا ہے۔"</string>
<string name="personal_apps_suspension_title" msgid="7561416677884286600">"اپنی دفتری پروفائل آن کریں"</string>
<string name="personal_apps_suspension_text" msgid="6115455688932935597">"آپ کے ذاتی ایپس کو اس وقت تک بلاک کر دیا جاتا ہے جب تک کہ آپ اپنے ورک پروفایل کو آن نہیں کرتے"</string>
- <!-- no translation found for personal_apps_suspension_soon_text (8123898693479590) -->
- <skip />
- <!-- no translation found for personal_apps_suspended_turn_profile_on (2758012869627513689) -->
- <skip />
+ <string name="personal_apps_suspension_soon_text" msgid="8123898693479590">"‏‫<xliff:g id="DATE">%1$s</xliff:g> کو <xliff:g id="TIME">%2$s</xliff:g> بجے ذاتی ایپس کو مسدود کر دیا جائے گا۔ آپ کا IT منتظم آپ کی دفتری پروفائل کو <xliff:g id="NUMBER">%3$d</xliff:g> دن سے زیادہ بند رکھنے کی اجازت نہیں دیتا ہے۔"</string>
+ <string name="personal_apps_suspended_turn_profile_on" msgid="2758012869627513689">"آن کریں"</string>
<string name="me" msgid="6207584824693813140">"میں"</string>
<string name="power_dialog" product="tablet" msgid="8333207765671417261">"ٹیبلیٹ کے اختیارات"</string>
<string name="power_dialog" product="tv" msgid="7792839006640933763">"‏Android TV اختیارات"</string>
@@ -1130,8 +1128,8 @@
<string name="whichViewApplication" msgid="5733194231473132945">"اس کے ساتھ کھولیں"</string>
<string name="whichViewApplicationNamed" msgid="415164730629690105">"‏%1$s کے ساتھ کھولیں"</string>
<string name="whichViewApplicationLabel" msgid="7367556735684742409">"کھولیں"</string>
- <string name="whichOpenHostLinksWith" msgid="7645631470199397485">"<xliff:g id="HOST">%1$s</xliff:g> لنکس کے ساتھ کھولیں"</string>
- <string name="whichOpenLinksWith" msgid="1120936181362907258">"لنکس کے ساتھ کھولیں"</string>
+ <string name="whichOpenHostLinksWith" msgid="7645631470199397485">"‫<xliff:g id="HOST">%1$s</xliff:g> لنکس کے اس کے ساتھ کھولیں"</string>
+ <string name="whichOpenLinksWith" msgid="1120936181362907258">"اس کے ساتھ لنکس کھولیں"</string>
<string name="whichOpenLinksWithApp" msgid="6917864367861910086">"<xliff:g id="APPLICATION">%1$s</xliff:g> کے ذریعے لنکس کھولیں"</string>
<string name="whichOpenHostLinksWithApp" msgid="2401668560768463004">"<xliff:g id="HOST">%1$s</xliff:g> لنکس کو <xliff:g id="APPLICATION">%2$s</xliff:g> کے ذریعے کھولیں"</string>
<string name="whichGiveAccessToApplicationLabel" msgid="7805857277166106236">"رسائی دیں"</string>
@@ -1588,7 +1586,7 @@
</plurals>
<string name="kg_pattern_instructions" msgid="8366024510502517748">"اپنا پیٹرن ڈرا کریں"</string>
<string name="kg_sim_pin_instructions" msgid="6479401489471690359">"‏SIM PIN درج کریں"</string>
- <string name="kg_pin_instructions" msgid="7355933174673539021">"‏PIN درج کریں"</string>
+ <string name="kg_pin_instructions" msgid="7355933174673539021">"‏‫PIN درج کریں"</string>
<string name="kg_password_instructions" msgid="7179782578809398050">"پاس ورڈ درج کریں"</string>
<string name="kg_puk_enter_puk_hint" msgid="6696187482616360994">"‏SIM اب غیر فعال ہوگیا ہے۔ جاری رکھنے کیلئے PUK کوڈ درج کریں۔ تفصیلات کیلئے کیریئر سے رابطہ کریں۔"</string>
<string name="kg_puk_enter_pin_hint" msgid="8190982314659429770">"‏پسندیدہ PIN کوڈ درج کریں"</string>
@@ -1761,7 +1759,7 @@
<string name="print_service_installed_title" msgid="6134880817336942482">"<xliff:g id="NAME">%s</xliff:g> سروس انسٹال ہو گئی"</string>
<string name="print_service_installed_message" msgid="7005672469916968131">"فعال کرنے کیلئے تھپتھپائیں"</string>
<string name="restr_pin_enter_admin_pin" msgid="1199419462726962697">"‏منتظم PIN درج کریں"</string>
- <string name="restr_pin_enter_pin" msgid="373139384161304555">"‏PIN درج کریں"</string>
+ <string name="restr_pin_enter_pin" msgid="373139384161304555">"‏‫PIN درج کریں"</string>
<string name="restr_pin_incorrect" msgid="3861383632940852496">"غلط"</string>
<string name="restr_pin_enter_old_pin" msgid="7537079094090650967">"‏موجودہ PIN"</string>
<string name="restr_pin_enter_new_pin" msgid="3267614461844565431">"‏نیا PIN"</string>
diff --git a/core/res/res/values-uz/strings.xml b/core/res/res/values-uz/strings.xml
index 27b3e726140e..fffa26553312 100644
--- a/core/res/res/values-uz/strings.xml
+++ b/core/res/res/values-uz/strings.xml
@@ -202,10 +202,8 @@
<string name="printing_disabled_by" msgid="3517499806528864633">"Chop etish funksiyasi <xliff:g id="OWNER_APP">%s</xliff:g> tomonidan faolsizlantirilgan."</string>
<string name="personal_apps_suspension_title" msgid="7561416677884286600">"Ish profilingizni yoqing"</string>
<string name="personal_apps_suspension_text" msgid="6115455688932935597">"Ish profilingiz yoniqligida shaxsiy ilovalaringiz bloklanadi"</string>
- <!-- no translation found for personal_apps_suspension_soon_text (8123898693479590) -->
- <skip />
- <!-- no translation found for personal_apps_suspended_turn_profile_on (2758012869627513689) -->
- <skip />
+ <string name="personal_apps_suspension_soon_text" msgid="8123898693479590">"Shaxsiy ilovalar <xliff:g id="DATE">%1$s</xliff:g> <xliff:g id="TIME">%2$s</xliff:g> da bloklanadi. AT administratoringiz ish profili <xliff:g id="NUMBER">%3$d</xliff:g> kundan ortiq oʻchiq qolishini taqiqlagan"</string>
+ <string name="personal_apps_suspended_turn_profile_on" msgid="2758012869627513689">"Yoqish"</string>
<string name="me" msgid="6207584824693813140">"Men"</string>
<string name="power_dialog" product="tablet" msgid="8333207765671417261">"Planshet sozlamalari"</string>
<string name="power_dialog" product="tv" msgid="7792839006640933763">"Android TV parametrlari"</string>
@@ -1308,8 +1306,8 @@
<string name="usb_power_notification_message" msgid="7284765627437897702">"Ulangan qurilma quvvatlanmoqda. Boshqa parametrlar uchun bosing."</string>
<string name="usb_unsupported_audio_accessory_title" msgid="2335775548086533065">"Analogli audio uskuna aniqlandi"</string>
<string name="usb_unsupported_audio_accessory_message" msgid="1300168007129796621">"Biriktirilgan qurilma mazkur telefon bilan mos emas. Batafsil axborot olish uchun bu yerga bosing."</string>
- <string name="adb_active_notification_title" msgid="408390247354560331">"USB orqali nosozliklarni aniqlash"</string>
- <string name="adb_active_notification_message" msgid="5617264033476778211">"USB orqali nosozliklarni aniqlashni faolsizlantirish uchun bosing"</string>
+ <string name="adb_active_notification_title" msgid="408390247354560331">"USB debagging ulandi"</string>
+ <string name="adb_active_notification_message" msgid="5617264033476778211">"USB debaggingni uzish uchun bosing"</string>
<string name="adb_active_notification_message" product="tv" msgid="6624498401272780855">"USB orqali nosozliklarni tuzatishni o‘chirib qo‘yish uchun bosing."</string>
<string name="adbwifi_active_notification_title" msgid="6147343659168302473">"Wi-Fi orqali debagging yoqildi"</string>
<string name="adbwifi_active_notification_message" msgid="930987922852867972">"Wi-Fi orqali debagging uzilishi uchun bosing"</string>
diff --git a/core/res/res/values-vi/strings.xml b/core/res/res/values-vi/strings.xml
index 5fe12fd1b43c..7ecad59d4162 100644
--- a/core/res/res/values-vi/strings.xml
+++ b/core/res/res/values-vi/strings.xml
@@ -202,10 +202,8 @@
<string name="printing_disabled_by" msgid="3517499806528864633">"<xliff:g id="OWNER_APP">%s</xliff:g> đã tắt tính năng in."</string>
<string name="personal_apps_suspension_title" msgid="7561416677884286600">"Bật hồ sơ công việc của bạn"</string>
<string name="personal_apps_suspension_text" msgid="6115455688932935597">"Ứng dụng cá nhân của bạn bị chặn cho tới khi bạn bật hồ sơ công việc"</string>
- <!-- no translation found for personal_apps_suspension_soon_text (8123898693479590) -->
- <skip />
- <!-- no translation found for personal_apps_suspended_turn_profile_on (2758012869627513689) -->
- <skip />
+ <string name="personal_apps_suspension_soon_text" msgid="8123898693479590">"Ứng dụng cá nhân sẽ bị chặn lúc <xliff:g id="TIME">%2$s</xliff:g> vào <xliff:g id="DATE">%1$s</xliff:g>. Quản trị viên CNTT không cho phép bạn tắt hồ sơ công việc quá <xliff:g id="NUMBER">%3$d</xliff:g> ngày."</string>
+ <string name="personal_apps_suspended_turn_profile_on" msgid="2758012869627513689">"Bật"</string>
<string name="me" msgid="6207584824693813140">"Tôi"</string>
<string name="power_dialog" product="tablet" msgid="8333207765671417261">"Tùy chọn máy tính bảng"</string>
<string name="power_dialog" product="tv" msgid="7792839006640933763">"Tùy chọn dành cho Android TV"</string>
@@ -2032,7 +2030,7 @@
<item quantity="other"><xliff:g id="FILE_NAME_2">%s</xliff:g> + <xliff:g id="COUNT_3">%d</xliff:g> tệp</item>
<item quantity="one"><xliff:g id="FILE_NAME_0">%s</xliff:g> + <xliff:g id="COUNT_1">%d</xliff:g> tệp</item>
</plurals>
- <string name="chooser_no_direct_share_targets" msgid="1511722103987329028">"Không có người nào được đề xuất để chia sẻ"</string>
+ <string name="chooser_no_direct_share_targets" msgid="1511722103987329028">"Không có gợi ý về người để chia sẻ"</string>
<string name="chooser_all_apps_button_label" msgid="3230427756238666328">"Danh sách ứng dụng"</string>
<string name="usb_device_resolve_prompt_warn" msgid="325871329788064199">"Ứng dụng này chưa được cấp quyền ghi âm nhưng vẫn có thể ghi âm thông qua thiết bị USB này."</string>
<string name="accessibility_system_action_home_label" msgid="3234748160850301870">"Màn hình chính"</string>
@@ -2065,7 +2063,7 @@
<string name="resolver_cant_share_with_personal_apps_explanation" msgid="2959282422751315171">"Quản trị viên CNTT không cho phép chia sẻ nội dung này với các ứng dụng trong hồ sơ cá nhân của bạn"</string>
<string name="resolver_cant_access_personal_apps" msgid="648291604475669395">"Không thể mở nội dung này bằng các ứng dụng cá nhân"</string>
<string name="resolver_cant_access_personal_apps_explanation" msgid="2298773629302296519">"Quản trị viên CNTT không cho phép mở nội dung này bằng các ứng dụng trong hồ sơ cá nhân của bạn"</string>
- <string name="resolver_turn_on_work_apps" msgid="884910835250037247">"Hồ sơ công việc bị tạm dừng"</string>
+ <string name="resolver_turn_on_work_apps" msgid="884910835250037247">"Hồ sơ công việc đã bị tạm dừng"</string>
<string name="resolver_switch_on_work" msgid="2873009160846966379">"Bật"</string>
<string name="resolver_no_work_apps_available_share" msgid="7933949011797699505">"Các ứng dụng công việc không hỗ trợ nội dung này"</string>
<string name="resolver_no_work_apps_available_resolve" msgid="1244844292366099399">"Các ứng dụng công việc không thể mở nội dung này"</string>
diff --git a/core/res/res/values-zh-rCN/strings.xml b/core/res/res/values-zh-rCN/strings.xml
index 9faa93ad9a5e..6e2b78b0de93 100644
--- a/core/res/res/values-zh-rCN/strings.xml
+++ b/core/res/res/values-zh-rCN/strings.xml
@@ -202,10 +202,8 @@
<string name="printing_disabled_by" msgid="3517499806528864633">"“<xliff:g id="OWNER_APP">%s</xliff:g>”已停用打印功能。"</string>
<string name="personal_apps_suspension_title" msgid="7561416677884286600">"开启工作资料"</string>
<string name="personal_apps_suspension_text" msgid="6115455688932935597">"系统已屏蔽您的个人应用。您需要开启工作资料,系统才会取消屏蔽这些应用"</string>
- <!-- no translation found for personal_apps_suspension_soon_text (8123898693479590) -->
- <skip />
- <!-- no translation found for personal_apps_suspended_turn_profile_on (2758012869627513689) -->
- <skip />
+ <string name="personal_apps_suspension_soon_text" msgid="8123898693479590">"系统将于 <xliff:g id="DATE">%1$s</xliff:g><xliff:g id="TIME">%2$s</xliff:g> 屏蔽个人应用。IT 管理员不允许您的工作资料保持关闭状态超过 <xliff:g id="NUMBER">%3$d</xliff:g> 天。"</string>
+ <string name="personal_apps_suspended_turn_profile_on" msgid="2758012869627513689">"开启"</string>
<string name="me" msgid="6207584824693813140">"我"</string>
<string name="power_dialog" product="tablet" msgid="8333207765671417261">"平板电脑选项"</string>
<string name="power_dialog" product="tv" msgid="7792839006640933763">"Android TV 选项"</string>
diff --git a/core/res/res/values-zh-rHK/strings.xml b/core/res/res/values-zh-rHK/strings.xml
index 66bc070c4775..f808f900cdc0 100644
--- a/core/res/res/values-zh-rHK/strings.xml
+++ b/core/res/res/values-zh-rHK/strings.xml
@@ -202,10 +202,8 @@
<string name="printing_disabled_by" msgid="3517499806528864633">"「<xliff:g id="OWNER_APP">%s</xliff:g>」暫停了列印。"</string>
<string name="personal_apps_suspension_title" msgid="7561416677884286600">"開啟工作設定檔"</string>
<string name="personal_apps_suspension_text" msgid="6115455688932935597">"系統會封鎖您的個人應用程式,直至您開啟工作設定檔為止"</string>
- <!-- no translation found for personal_apps_suspension_soon_text (8123898693479590) -->
- <skip />
- <!-- no translation found for personal_apps_suspended_turn_profile_on (2758012869627513689) -->
- <skip />
+ <string name="personal_apps_suspension_soon_text" msgid="8123898693479590">"個人應用程式將於 <xliff:g id="DATE">%1$s</xliff:g> <xliff:g id="TIME">%2$s</xliff:g> 封鎖。IT 管理員不允許您的工作設定檔保持關閉狀態超過 <xliff:g id="NUMBER">%3$d</xliff:g> 天。"</string>
+ <string name="personal_apps_suspended_turn_profile_on" msgid="2758012869627513689">"開啟"</string>
<string name="me" msgid="6207584824693813140">"我本人"</string>
<string name="power_dialog" product="tablet" msgid="8333207765671417261">"平板電腦選項"</string>
<string name="power_dialog" product="tv" msgid="7792839006640933763">"Android TV 選項"</string>
diff --git a/core/res/res/values-zh-rTW/strings.xml b/core/res/res/values-zh-rTW/strings.xml
index 6a7391bb0f56..559e681b178c 100644
--- a/core/res/res/values-zh-rTW/strings.xml
+++ b/core/res/res/values-zh-rTW/strings.xml
@@ -202,10 +202,8 @@
<string name="printing_disabled_by" msgid="3517499806528864633">"「<xliff:g id="OWNER_APP">%s</xliff:g>」已停用列印功能。"</string>
<string name="personal_apps_suspension_title" msgid="7561416677884286600">"開啟工作資料夾"</string>
<string name="personal_apps_suspension_text" msgid="6115455688932935597">"系統已封鎖你的個人應用程式;你必須開啟工作資料夾,這些應用程式才會解除封鎖"</string>
- <!-- no translation found for personal_apps_suspension_soon_text (8123898693479590) -->
- <skip />
- <!-- no translation found for personal_apps_suspended_turn_profile_on (2758012869627513689) -->
- <skip />
+ <string name="personal_apps_suspension_soon_text" msgid="8123898693479590">"系統將於 <xliff:g id="DATE">%1$s</xliff:g><xliff:g id="TIME">%2$s</xliff:g> 封鎖個人應用程式。IT 管理員不允許工作資料夾關閉超過 <xliff:g id="NUMBER">%3$d</xliff:g> 天。"</string>
+ <string name="personal_apps_suspended_turn_profile_on" msgid="2758012869627513689">"開啟"</string>
<string name="me" msgid="6207584824693813140">"我"</string>
<string name="power_dialog" product="tablet" msgid="8333207765671417261">"平板電腦選項"</string>
<string name="power_dialog" product="tv" msgid="7792839006640933763">"Android TV 選項"</string>
diff --git a/core/res/res/values-zu/strings.xml b/core/res/res/values-zu/strings.xml
index 946e4eac7532..3b95ffb497ba 100644
--- a/core/res/res/values-zu/strings.xml
+++ b/core/res/res/values-zu/strings.xml
@@ -202,10 +202,8 @@
<string name="printing_disabled_by" msgid="3517499806528864633">"Ukuphrinta kukhutshazwe nge-<xliff:g id="OWNER_APP">%s</xliff:g>."</string>
<string name="personal_apps_suspension_title" msgid="7561416677884286600">"Vula iphrofayela yakho yomsebenzi"</string>
<string name="personal_apps_suspension_text" msgid="6115455688932935597">"Izinhlelo zakho zokusebenza zomuntu siqu zivinjelwe kuze kube yilapho uvula iphrofayela yakho yomsebenzi"</string>
- <!-- no translation found for personal_apps_suspension_soon_text (8123898693479590) -->
- <skip />
- <!-- no translation found for personal_apps_suspended_turn_profile_on (2758012869627513689) -->
- <skip />
+ <string name="personal_apps_suspension_soon_text" msgid="8123898693479590">"Izinhlelo zokusebenza zomuntu siqu zizovinjelwa ngomhla ka-<xliff:g id="DATE">%1$s</xliff:g> ngo-<xliff:g id="TIME">%2$s</xliff:g>. Umphathi wakho we-IT akavumeli ukuthi iphrofayela yakho yomsebenzi ihlale ivaliwe izinsuku ezingaphezu kwezi-<xliff:g id="NUMBER">%3$d</xliff:g>."</string>
+ <string name="personal_apps_suspended_turn_profile_on" msgid="2758012869627513689">"Vula"</string>
<string name="me" msgid="6207584824693813140">"Mina"</string>
<string name="power_dialog" product="tablet" msgid="8333207765671417261">"Okukhethwa kukho kwethebhulethi"</string>
<string name="power_dialog" product="tv" msgid="7792839006640933763">"Izinketho ze-Android TV"</string>
diff --git a/core/res/res/values/attrs_manifest.xml b/core/res/res/values/attrs_manifest.xml
index c962256e477c..f42b248f4670 100644
--- a/core/res/res/values/attrs_manifest.xml
+++ b/core/res/res/values/attrs_manifest.xml
@@ -1830,30 +1830,13 @@
<!-- @hide no longer used, kept to preserve padding -->
<attr name="allowAutoRevokePermissionsExemption" format="boolean" />
- <!-- Declare the app's tolerance to having its permissions automatically revoked when unused for an extended
- period of time -->
+ <!-- No longer used. Declaring this does nothing -->
<attr name="autoRevokePermissions">
- <!-- App supports re-requesting its permissions if revoked.
- Revoking app's permissions doesn't cause user experience issues, aside from a repeated permission request.
-
- Permissions may be automatically revoked from an app if unused. The app must check and possibly request the
- necessary permission on each permission-gated call-->
+ <!-- No longer used -->
<enum name="allowed" value="0" />
- <!-- App may experience degraded functionality when its previously-granted permissions are revoked.
- Revoking app's permissions may cause user experience issues, that are not critical to the user.
-
- Apps with this declaration can choose to request an exemption from auto revoke from user by starting
- an activity with {@code Intent.ACTION_AUTO_REVOKE_PERMISSIONS}. -->
+ <!-- No longer used -->
<enum name="discouraged" value="1" />
- <!-- User may experience severe consequences if this app's permissions are revoked unexpectedly.
-
- E.g. app may fail to do a user-critical background job that may likely impact user's
- safety/security/device accessibility.
-
- This declaration may cause an additional review when publishing your app.
-
- Apps with this declaration are exempt from auto revoke by default, though the user has the final say
- in both revoking the permissions as well as the app's auto revoke exemption status. -->
+ <!-- No longer used -->
<enum name="disallowed" value="2" />
</attr>
</declare-styleable>
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 2cad9e6888a6..0e11d49c93e5 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -4313,10 +4313,6 @@
notifications until they target R -->
<string-array name="config_notificationMsgPkgsAllowedAsConvos" translatable="false"/>
- <!-- Contains a blacklist of apps that should not get pre-installed carrier app permission
- grants, even if the UICC claims that the app should be privileged. See b/138150105 -->
- <string-array name="config_restrictedPreinstalledCarrierApps" translatable="false"/>
-
<!-- Sharesheet: define a max number of targets per application for new shortcuts-based direct share introduced in Q -->
<integer name="config_maxShortcutTargetsPerApp">3</integer>
@@ -4456,11 +4452,4 @@
<bool name="config_pdp_reject_enable_retry">false</bool>
<!-- pdp data reject retry delay in ms -->
<integer name="config_pdp_reject_retry_delay_ms">-1</integer>
-
- <!-- Package name that is recognized as an actor for the packages listed in
- @array/config_overlayableConfiguratorTargets. If an overlay targeting one of the listed
- targets is signed with the same signature as the configurator, the overlay will be granted
- the "actor" policy. -->
- <string name="config_overlayableConfigurator" translatable="false" />
- <string-array name="config_overlayableConfiguratorTargets" translatable="false" />
</resources>
diff --git a/core/res/res/values/dimens.xml b/core/res/res/values/dimens.xml
index ad3d20ee5f24..ebaf85c64a14 100644
--- a/core/res/res/values/dimens.xml
+++ b/core/res/res/values/dimens.xml
@@ -273,6 +273,9 @@
<!-- The margin before and after each of the items in the notification header. -->
<dimen name="notification_header_separating_margin">2dp</dimen>
+ <!-- The margin before and after each of the items in the conversation header. -->
+ <dimen name="notification_conversation_header_separating_margin">4dp</dimen>
+
<!-- The absolute size of the notification expand icon. -2 for wrap_content. -->
<dimen name="notification_header_expand_icon_size">-2px</dimen>
@@ -312,6 +315,12 @@
<!-- The margin of the content to an image-->
<dimen name="notification_content_image_margin_end">8dp</dimen>
+ <!-- The padding at the end of actions when the bubble button is visible-->
+ <dimen name="bubble_visible_padding_end">3dp</dimen>
+
+ <!-- The padding at the end of actions when the bubble button is gone-->
+ <dimen name="bubble_gone_padding_end">12dp</dimen>
+
<!-- The spacing between messages in Notification.MessagingStyle -->
<dimen name="notification_messaging_spacing">6dp</dimen>
@@ -713,13 +722,19 @@
<!-- The width of the protection of the face pile layout when expanded-->
<dimen name="conversation_face_pile_protection_width_expanded">1dp</dimen>
<!-- The padding of the expanded message container-->
- <dimen name="expanded_group_conversation_message_padding">14dp</dimen>
+ <dimen name="expanded_group_conversation_message_padding">17dp</dimen>
+ <!-- The stroke width of the ring used to visually mark a conversation as important -->
+ <dimen name="importance_ring_stroke_width">2dp</dimen>
+ <!-- The maximum stroke width used for the animation shown when a conversation is marked as important -->
+ <dimen name="importance_ring_anim_max_stroke_width">10dp</dimen>
+ <!-- The size of the importance ring -->
+ <dimen name="importance_ring_size">20dp</dimen>
<!-- The top padding of the conversation icon container in the regular state-->
- <dimen name="conversation_icon_container_top_padding">9dp</dimen>
+ <dimen name="conversation_icon_container_top_padding">12dp</dimen>
<!-- The top padding of the conversation icon container when the avatar is small-->
- <dimen name="conversation_icon_container_top_padding_small_avatar">17.5dp</dimen>
+ <dimen name="conversation_icon_container_top_padding_small_avatar">9dp</dimen>
<!-- The padding of the conversation header when expanded. This is calculated from the expand button size + notification_content_margin_end -->
<dimen name="conversation_header_expanded_padding_end">38dp</dimen>
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index dc21e878d132..a1c2450be153 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -1613,15 +1613,15 @@
<string name="face_error_no_space">Can\u2019t store new face data. Delete an old one first.</string>
<!-- Generic error message shown when the face operation (e.g. enrollment or authentication) is canceled. Generally not shown to the user. [CHAR LIMIT=50] -->
<string name="face_error_canceled">Face operation canceled.</string>
- <!-- Generic error message shown when the face unlock operation is canceled due to user input. Generally not shown to the user [CHAR LIMIT=54] -->
+ <!-- Generic error message shown when the face unlock operation is canceled due to user input. Generally not shown to the user [CHAR LIMIT=68] -->
<string name="face_error_user_canceled">Face unlock canceled by user.</string>
<!-- Generic error message shown when the face operation fails because too many attempts have been made. [CHAR LIMIT=50] -->
<string name="face_error_lockout">Too many attempts. Try again later.</string>
- <!-- Generic error message shown when the face operation fails because strong authentication is required. [CHAR LIMIT=71] -->
+ <!-- Generic error message shown when the face operation fails because strong authentication is required. [CHAR LIMIT=77] -->
<string name="face_error_lockout_permanent">Too many attempts. Face unlock disabled.</string>
<!-- Generic error message shown when the face hardware can't recognize the face. [CHAR LIMIT=50] -->
<string name="face_error_unable_to_process">Can\u2019t verify face. Try again.</string>
- <!-- Generic error message shown when the user has no enrolled face. [CHAR LIMIT=52] -->
+ <!-- Generic error message shown when the user has no enrolled face. [CHAR LIMIT=59] -->
<string name="face_error_not_enrolled">You haven\u2019t set up face unlock.</string>
<!-- Generic error message shown when the app requests face unlock on a device without a sensor. [CHAR LIMIT=61] -->
<string name="face_error_hw_not_present">Face unlock is not supported on this device.</string>
diff --git a/core/res/res/values/styles_device_defaults.xml b/core/res/res/values/styles_device_defaults.xml
index e9ac679ec39c..ef019ba92769 100644
--- a/core/res/res/values/styles_device_defaults.xml
+++ b/core/res/res/values/styles_device_defaults.xml
@@ -296,9 +296,12 @@ easier.
<style name="TextAppearance.DeviceDefault.Notification.Info" parent="TextAppearance.Material.Notification.Info">
<item name="fontFamily">@string/config_bodyFontFamily</item>
</style>
+ <style name="TextAppearance.DeviceDefault.Notification.Time" parent="TextAppearance.Material.Notification.Time">
+ <item name="fontFamily">@string/config_bodyFontFamily</item>
+ </style>
<style name="TextAppearance.DeviceDefault.Notification.Conversation.AppName"
- parent="@*android:style/TextAppearance.DeviceDefault.Notification.Title">
- <item name="android:textSize">16sp</item>
+ parent="TextAppearance.Material.Notification.Conversation.AppName">
+ <item name="fontFamily">@string/config_headlineFontFamilyMedium</item>
</style>
<style name="TextAppearance.DeviceDefault.Widget" parent="TextAppearance.Material.Widget">
<item name="fontFamily">@string/config_bodyFontFamily</item>
diff --git a/core/res/res/values/styles_material.xml b/core/res/res/values/styles_material.xml
index 2415837cf826..67536fde9b0b 100644
--- a/core/res/res/values/styles_material.xml
+++ b/core/res/res/values/styles_material.xml
@@ -491,6 +491,10 @@ please see styles_device_defaults.xml.
<item name="textColor">#66000000</item>
</style>
+ <style name="TextAppearance.Material.Notification.Conversation.AppName" parent="TextAppearance.Material.Notification.Title">
+ <item name="android:textSize">16sp</item>
+ </style>
+
<style name="TextAppearance.Material.ListItem" parent="TextAppearance.Material.Subhead" />
<style name="TextAppearance.Material.ListItemSecondary" parent="TextAppearance.Material.Body1" />
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index f30d482e06b2..c56c78a0b6a1 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -1785,6 +1785,7 @@
<java-symbol type="string" name="faceunlock_multiple_failures" />
<java-symbol type="string" name="global_actions" />
<java-symbol type="string" name="global_action_power_off" />
+ <java-symbol type="string" name="global_action_power_options" />
<java-symbol type="string" name="global_action_restart" />
<java-symbol type="string" name="global_actions_airplane_mode_off_status" />
<java-symbol type="string" name="global_actions_airplane_mode_on_status" />
@@ -2766,6 +2767,7 @@
<java-symbol type="bool" name="config_mainBuiltInDisplayIsRound" />
<java-symbol type="id" name="actions_container" />
+ <java-symbol type="id" name="actions_container_layout" />
<java-symbol type="id" name="smart_reply_container" />
<java-symbol type="id" name="remote_input_tag" />
<java-symbol type="id" name="pending_intent_tag" />
@@ -3533,6 +3535,8 @@
<java-symbol type="id" name="clip_to_padding_tag" />
<java-symbol type="id" name="clip_children_tag" />
<java-symbol type="id" name="bubble_button" />
+ <java-symbol type="dimen" name="bubble_visible_padding_end" />
+ <java-symbol type="dimen" name="bubble_gone_padding_end" />
<java-symbol type="dimen" name="messaging_avatar_size" />
<java-symbol type="dimen" name="messaging_group_sending_progress_size" />
<java-symbol type="dimen" name="messaging_image_rounding" />
@@ -3823,7 +3827,6 @@
<java-symbol type="string" name="config_defaultSupervisionProfileOwnerComponent" />
<java-symbol type="bool" name="config_inflateSignalStrength" />
- <java-symbol type="array" name="config_restrictedPreinstalledCarrierApps" />
<java-symbol type="drawable" name="android_logotype" />
<java-symbol type="layout" name="platlogo_layout" />
@@ -3834,7 +3837,9 @@
<java-symbol type="string" name="config_factoryResetPackage" />
<java-symbol type="array" name="config_highRefreshRateBlacklist" />
+ <java-symbol type="layout" name="chooser_dialog" />
<java-symbol type="layout" name="chooser_dialog_item" />
+ <java-symbol type="drawable" name="chooser_dialog_background" />
<java-symbol type="id" name="chooser_copy_button" />
<java-symbol type="layout" name="chooser_action_button" />
<java-symbol type="dimen" name="chooser_action_button_icon_size" />
@@ -3897,6 +3902,12 @@
<java-symbol type="array" name="config_defaultImperceptibleKillingExemptionPkgs" />
<java-symbol type="array" name="config_defaultImperceptibleKillingExemptionProcStates" />
+ <java-symbol type="color" name="conversation_important_highlight" />
+ <java-symbol type="dimen" name="importance_ring_stroke_width" />
+ <java-symbol type="dimen" name="importance_ring_anim_max_stroke_width" />
+ <java-symbol type="dimen" name="importance_ring_size" />
+ <java-symbol type="dimen" name="conversation_icon_size_badged" />
+
<java-symbol type="id" name="header_icon_container" />
<java-symbol type="attr" name="notificationHeaderTextAppearance" />
<java-symbol type="string" name="conversation_single_line_name_display" />
@@ -3944,6 +3955,13 @@
<java-symbol type="id" name="conversation_unread_count" />
<java-symbol type="string" name="unread_convo_overflow" />
<java-symbol type="style" name="TextAppearance.DeviceDefault.Notification.Conversation.AppName" />
+ <java-symbol type="drawable" name="conversation_badge_background" />
+ <java-symbol type="drawable" name="conversation_badge_ring" />
+ <java-symbol type="color" name="conversation_important_highlight" />
+ <java-symbol type="dimen" name="importance_ring_stroke_width" />
+ <java-symbol type="dimen" name="importance_ring_anim_max_stroke_width" />
+ <java-symbol type="dimen" name="importance_ring_size" />
+ <java-symbol type="dimen" name="conversation_icon_size_badged" />
<!-- Intent resolver and share sheet -->
<java-symbol type="string" name="resolver_personal_tab" />
@@ -4033,8 +4051,5 @@
<java-symbol type="string" name="config_pdp_reject_service_not_subscribed" />
<java-symbol type="string" name="config_pdp_reject_multi_conn_to_same_pdn_not_allowed" />
- <java-symbol type="string" name="config_overlayableConfigurator" />
- <java-symbol type="array" name="config_overlayableConfiguratorTargets" />
-
<java-symbol type="array" name="config_notificationMsgPkgsAllowedAsConvos" />
</resources>
diff --git a/core/res/res/values/themes_leanback.xml b/core/res/res/values/themes_leanback.xml
index a80725c2758b..9dca9128e362 100644
--- a/core/res/res/values/themes_leanback.xml
+++ b/core/res/res/values/themes_leanback.xml
@@ -128,6 +128,10 @@
<!-- Toolbar attributes -->
<item name="toolbarStyle">@style/Widget.DeviceDefault.Toolbar</item>
+
+ <!-- Icon sizes -->
+ <item name="iconfactoryIconSize">@dimen/resolver_icon_size</item>
+ <item name="iconfactoryBadgeSize">@dimen/resolver_badge_size</item>
</style>
<!-- @hide Special theme for the default system Activity-based Alert dialogs. -->
diff --git a/core/res/res/xml/sms_short_codes.xml b/core/res/res/xml/sms_short_codes.xml
index 70917e76f8b4..d5733e34a8ef 100644
--- a/core/res/res/xml/sms_short_codes.xml
+++ b/core/res/res/xml/sms_short_codes.xml
@@ -39,7 +39,7 @@
<!-- Albania: 5 digits, known short codes listed -->
<shortcode country="al" pattern="\\d{5}" premium="15191|55[56]00" />
- <!-- Argentia: 5 digits, known short codes listed -->
+ <!-- Argentina: 5 digits, known short codes listed -->
<shortcode country="ar" pattern="\\d{5}" free="11711|28291" />
<!-- Armenia: 3-4 digits, emergency numbers 10[123] -->
@@ -70,7 +70,7 @@
<shortcode country="by" pattern="\\d{4}" premium="3336|4161|444[4689]|501[34]|7781" />
<!-- Canada: 5-6 digits -->
- <shortcode country="ca" pattern="\\d{5,6}" premium="60999|88188|43030" standard="244444" />
+ <shortcode country="ca" pattern="\\d{5,6}" premium="60999|88188|43030" standard="244444" free="455677" />
<!-- Switzerland: 3-5 digits: http://www.swisscom.ch/fxres/kmu/thirdpartybusiness_code_of_conduct_en.pdf -->
<shortcode country="ch" pattern="[2-9]\\d{2,4}" premium="543|83111|30118" free="98765|30075|30047" />
diff --git a/core/tests/PackageInstallerSessions/Android.bp b/core/tests/PackageInstallerSessions/Android.bp
new file mode 100644
index 000000000000..e74f30ee10a4
--- /dev/null
+++ b/core/tests/PackageInstallerSessions/Android.bp
@@ -0,0 +1,42 @@
+//
+// Copyright 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.
+//
+
+android_test {
+ name: "FrameworksCorePackageInstallerSessionsTests",
+
+ srcs: [
+ "src/**/*.kt",
+ ],
+ static_libs: [
+ "androidx.test.rules",
+ "compatibility-device-util-axt",
+ "frameworks-base-testutils",
+ "platform-test-annotations",
+ "testng",
+ "truth-prebuilt",
+ ],
+
+ libs: [
+ "android.test.runner",
+ "android.test.base",
+ "framework",
+ "framework-res",
+ ],
+
+ platform_apis: true,
+ sdk_version: "core_platform",
+ test_suites: ["device-tests"],
+}
diff --git a/core/tests/PackageInstallerSessions/AndroidManifest.xml b/core/tests/PackageInstallerSessions/AndroidManifest.xml
new file mode 100644
index 000000000000..5b22d2b4f3e3
--- /dev/null
+++ b/core/tests/PackageInstallerSessions/AndroidManifest.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ * 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.
+ -->
+
+<manifest
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.frameworks.coretests.package_installer_sessions"
+ >
+
+ <application>
+ <uses-library android:name="android.test.runner" />
+ </application>
+
+ <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
+ android:targetPackage="com.android.frameworks.coretests.package_installer_sessions"/>
+</manifest>
diff --git a/core/tests/PackageInstallerSessions/src/android/content/pm/PackageSessionTests.kt b/core/tests/PackageInstallerSessions/src/android/content/pm/PackageSessionTests.kt
new file mode 100644
index 000000000000..494c92a8aa3f
--- /dev/null
+++ b/core/tests/PackageInstallerSessions/src/android/content/pm/PackageSessionTests.kt
@@ -0,0 +1,188 @@
+/*
+ * 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 android.content.pm
+
+import android.content.Context
+import android.content.pm.PackageInstaller.SessionParams
+import android.platform.test.annotations.Presubmit
+import androidx.test.InstrumentationRegistry
+import androidx.test.filters.LargeTest
+import com.android.compatibility.common.util.ShellIdentityUtils
+import com.google.common.truth.Truth.assertThat
+import org.junit.After
+import org.junit.Before
+import org.junit.Test
+import org.testng.Assert.assertThrows
+import kotlin.random.Random
+
+/**
+ * For verifying public [PackageInstaller] session APIs. This differs from
+ * [com.android.server.pm.PackageInstallerSessionTest] in services because that mocks the session,
+ * whereas this test uses the installer on device.
+ */
+@Presubmit
+class PackageSessionTests {
+
+ companion object {
+ /**
+ * Permissions marked "hardRestricted" or "softRestricted" in core/res/AndroidManifest.xml.
+ */
+ private val RESTRICTED_PERMISSIONS = listOf(
+ "android.permission.SEND_SMS",
+ "android.permission.RECEIVE_SMS",
+ "android.permission.READ_SMS",
+ "android.permission.RECEIVE_WAP_PUSH",
+ "android.permission.RECEIVE_MMS",
+ "android.permission.READ_CELL_BROADCASTS",
+ "android.permission.ACCESS_BACKGROUND_LOCATION",
+ "android.permission.READ_CALL_LOG",
+ "android.permission.WRITE_CALL_LOG",
+ "android.permission.PROCESS_OUTGOING_CALLS"
+ )
+ }
+
+ private val context: Context = InstrumentationRegistry.getContext()
+
+ private val installer = context.packageManager.packageInstaller
+
+ @Before
+ @After
+ fun abandonAllSessions() {
+ installer.mySessions.asSequence()
+ .map { it.sessionId }
+ .forEach {
+ try {
+ installer.abandonSession(it)
+ } catch (ignored: Exception) {
+ // Querying for sessions checks by calling package name, but abandoning
+ // checks by UID, which won't match if this test failed to clean up
+ // on a previous install + run + uninstall, so ignore these failures.
+ }
+ }
+ }
+
+ @Test
+ fun truncateAppLabel() {
+ val longLabel = invalidAppLabel()
+ val params = SessionParams(SessionParams.MODE_FULL_INSTALL).apply {
+ setAppLabel(longLabel)
+ }
+
+ createSession(params) {
+ assertThat(installer.getSessionInfo(it)?.appLabel)
+ .isEqualTo(longLabel.take(PackageItemInfo.MAX_SAFE_LABEL_LENGTH))
+ }
+ }
+
+ @Test
+ fun removeInvalidAppPackageName() {
+ val longName = invalidPackageName()
+ val params = SessionParams(SessionParams.MODE_FULL_INSTALL).apply {
+ setAppPackageName(longName)
+ }
+
+ createSession(params) {
+ assertThat(installer.getSessionInfo(it)?.appPackageName)
+ .isEqualTo(null)
+ }
+ }
+
+ @Test
+ fun removeInvalidInstallerPackageName() {
+ val longName = invalidPackageName()
+ val params = SessionParams(SessionParams.MODE_FULL_INSTALL).apply {
+ setInstallerPackageName(longName)
+ }
+
+ createSession(params) {
+ // If a custom installer name is dropped, it defaults to the caller
+ assertThat(installer.getSessionInfo(it)?.installerPackageName)
+ .isEqualTo(context.packageName)
+ }
+ }
+
+ @Test
+ fun truncateWhitelistPermissions() {
+ val params = SessionParams(SessionParams.MODE_FULL_INSTALL).apply {
+ setWhitelistedRestrictedPermissions(invalidPermissions())
+ }
+
+ createSession(params) {
+ assertThat(installer.getSessionInfo(it)?.whitelistedRestrictedPermissions!!)
+ .containsExactlyElementsIn(RESTRICTED_PERMISSIONS)
+ }
+ }
+
+ @LargeTest
+ @Test
+ fun allocateMaxSessionsWithPermission() {
+ ShellIdentityUtils.invokeWithShellPermissions {
+ repeat(1024) { createDummySession() }
+ assertThrows(IllegalStateException::class.java) { createDummySession() }
+ }
+ }
+
+ @LargeTest
+ @Test
+ fun allocateMaxSessionsNoPermission() {
+ repeat(50) { createDummySession() }
+ assertThrows(IllegalStateException::class.java) { createDummySession() }
+ }
+
+ private fun createDummySession() {
+ installer.createSession(SessionParams(SessionParams.MODE_FULL_INSTALL)
+ .apply {
+ setAppPackageName(invalidPackageName())
+ setAppLabel(invalidAppLabel())
+ setWhitelistedRestrictedPermissions(invalidPermissions())
+ })
+ }
+
+ private fun invalidPackageName(maxLength: Int = SessionParams.MAX_PACKAGE_NAME_LENGTH): String {
+ return (0 until (maxLength + 10))
+ .asSequence()
+ .mapIndexed { index, _ ->
+ // A package name needs at least one separator
+ if (index == 2) {
+ '.'
+ } else {
+ Random.nextInt('z' - 'a').toChar() + 'a'.toInt()
+ }
+ }
+ .joinToString(separator = "")
+ }
+
+ private fun invalidAppLabel() = (0 until PackageItemInfo.MAX_SAFE_LABEL_LENGTH + 10)
+ .asSequence()
+ .map { Random.nextInt(Char.MAX_VALUE.toInt()).toChar() }
+ .joinToString(separator = "")
+
+ private fun invalidPermissions() = RESTRICTED_PERMISSIONS.toMutableSet()
+ .apply {
+ // Add some invalid permission names
+ repeat(10) { add(invalidPackageName(300)) }
+ }
+
+ private fun createSession(params: SessionParams, block: (Int) -> Unit = {}) {
+ val sessionId = installer.createSession(params)
+ try {
+ block(sessionId)
+ } finally {
+ installer.abandonSession(sessionId)
+ }
+ }
+}
diff --git a/core/tests/coretests/src/android/content/ContextTest.java b/core/tests/coretests/src/android/content/ContextTest.java
index f13a11e9edfb..17d1389a6602 100644
--- a/core/tests/coretests/src/android/content/ContextTest.java
+++ b/core/tests/coretests/src/android/content/ContextTest.java
@@ -23,12 +23,14 @@ import static android.view.Display.DEFAULT_DISPLAY;
import static com.google.common.truth.Truth.assertThat;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
import android.app.ActivityThread;
import android.content.res.Configuration;
import android.graphics.PixelFormat;
import android.hardware.display.DisplayManager;
import android.hardware.display.VirtualDisplay;
+import android.inputmethodservice.InputMethodService;
import android.media.ImageReader;
import android.os.UserHandle;
import android.view.Display;
@@ -136,6 +138,13 @@ public class ContextTest {
}
@Test
+ public void testIsUiContext_InputMethodService_returnsTrue() {
+ final InputMethodService ims = new InputMethodService();
+
+ assertTrue(ims.isUiContext());
+ }
+
+ @Test
public void testGetDisplayFromDisplayContextDerivedContextOnPrimaryDisplay() {
verifyGetDisplayFromDisplayContextDerivedContext(false /* onSecondaryDisplay */);
}
diff --git a/core/tests/coretests/src/android/view/InsetsSourceConsumerTest.java b/core/tests/coretests/src/android/view/InsetsSourceConsumerTest.java
index 25f94131f820..bf7f339a8484 100644
--- a/core/tests/coretests/src/android/view/InsetsSourceConsumerTest.java
+++ b/core/tests/coretests/src/android/view/InsetsSourceConsumerTest.java
@@ -16,6 +16,9 @@
package android.view;
+import static android.view.InsetsController.ANIMATION_TYPE_NONE;
+import static android.view.InsetsController.ANIMATION_TYPE_USER;
+import static android.view.InsetsState.ITYPE_IME;
import static android.view.InsetsState.ITYPE_STATUS_BAR;
import static android.view.WindowInsets.Type.statusBars;
@@ -23,14 +26,18 @@ import static junit.framework.Assert.assertEquals;
import static junit.framework.TestCase.assertFalse;
import static junit.framework.TestCase.assertTrue;
+import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.reset;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyZeroInteractions;
+import static org.mockito.Mockito.when;
import android.app.Instrumentation;
import android.content.Context;
import android.graphics.Point;
+import android.graphics.Rect;
import android.platform.test.annotations.Presubmit;
import android.view.SurfaceControl.Transaction;
import android.view.WindowManager.BadTokenException;
@@ -122,6 +129,48 @@ public class InsetsSourceConsumerTest {
}
@Test
+ public void testPendingStates() {
+ InsetsState state = new InsetsState();
+ InsetsController controller = mock(InsetsController.class);
+ InsetsSourceConsumer consumer = new InsetsSourceConsumer(
+ ITYPE_IME, state, null, controller);
+
+ when(controller.getAnimationType(anyInt())).thenReturn(ANIMATION_TYPE_NONE);
+
+ InsetsSource source = new InsetsSource(ITYPE_IME);
+ source.setFrame(0, 1, 2, 3);
+ consumer.updateSource(new InsetsSource(source));
+
+ when(controller.getAnimationType(anyInt())).thenReturn(ANIMATION_TYPE_USER);
+
+ // While we're animating, updates are delayed
+ source.setFrame(4, 5, 6, 7);
+ consumer.updateSource(new InsetsSource(source));
+ assertEquals(new Rect(0, 1, 2, 3), state.peekSource(ITYPE_IME).getFrame());
+
+ // Finish the animation, now the pending frame should be applied
+ when(controller.getAnimationType(anyInt())).thenReturn(ANIMATION_TYPE_NONE);
+ assertTrue(consumer.notifyAnimationFinished());
+ assertEquals(new Rect(4, 5, 6, 7), state.peekSource(ITYPE_IME).getFrame());
+
+ when(controller.getAnimationType(anyInt())).thenReturn(ANIMATION_TYPE_USER);
+
+ // Animating again, updates are delayed
+ source.setFrame(8, 9, 10, 11);
+ consumer.updateSource(new InsetsSource(source));
+ assertEquals(new Rect(4, 5, 6, 7), state.peekSource(ITYPE_IME).getFrame());
+
+ // Updating with the current frame triggers a different code path, verify this clears
+ // the pending 8, 9, 10, 11 frame:
+ source.setFrame(4, 5, 6, 7);
+ consumer.updateSource(new InsetsSource(source));
+
+ when(controller.getAnimationType(anyInt())).thenReturn(ANIMATION_TYPE_NONE);
+ assertFalse(consumer.notifyAnimationFinished());
+ assertEquals(new Rect(4, 5, 6, 7), state.peekSource(ITYPE_IME).getFrame());
+ }
+
+ @Test
public void testRestore() {
InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> {
mConsumer.setControl(null, new int[1], new int[1]);
diff --git a/core/tests/coretests/src/android/view/InsetsStateTest.java b/core/tests/coretests/src/android/view/InsetsStateTest.java
index daaf31a6bb65..cd93eeb857f1 100644
--- a/core/tests/coretests/src/android/view/InsetsStateTest.java
+++ b/core/tests/coretests/src/android/view/InsetsStateTest.java
@@ -27,6 +27,8 @@ import static android.view.InsetsState.ITYPE_NAVIGATION_BAR;
import static android.view.InsetsState.ITYPE_STATUS_BAR;
import static android.view.View.SYSTEM_UI_FLAG_LAYOUT_STABLE;
import static android.view.WindowInsets.Type.ime;
+import static android.view.WindowInsets.Type.navigationBars;
+import static android.view.WindowInsets.Type.statusBars;
import static android.view.WindowManager.LayoutParams.SOFT_INPUT_ADJUST_NOTHING;
import static android.view.WindowManager.LayoutParams.SOFT_INPUT_ADJUST_PAN;
import static android.view.WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE;
@@ -341,6 +343,26 @@ public class InsetsStateTest {
}
}
+ @Test
+ public void testCalculateUncontrollableInsets() throws Exception {
+ try (InsetsModeSession session = new InsetsModeSession(ViewRootImpl.NEW_INSETS_MODE_FULL)) {
+ mState.getSource(ITYPE_STATUS_BAR).setFrame(new Rect(0, 0, 200, 100));
+ mState.getSource(ITYPE_STATUS_BAR).setVisible(true);
+ mState.getSource(ITYPE_IME).setFrame(new Rect(0, 200, 200, 300));
+ mState.getSource(ITYPE_IME).setVisible(true);
+ mState.getSource(ITYPE_NAVIGATION_BAR).setFrame(new Rect(100, 0, 200, 300));
+ mState.getSource(ITYPE_NAVIGATION_BAR).setVisible(true);
+
+ mState.setDisplayFrame(new Rect(0, 0, 200, 300));
+ assertEquals(0,
+ mState.calculateUncontrollableInsetsFromFrame(new Rect(0, 0, 200, 300)));
+ assertEquals(statusBars() | ime(),
+ mState.calculateUncontrollableInsetsFromFrame(new Rect(0, 50, 200, 250)));
+ assertEquals(navigationBars(),
+ mState.calculateUncontrollableInsetsFromFrame(new Rect(50, 0, 150, 300)));
+ }
+ }
+
private void assertEqualsAndHashCode() {
assertEquals(mState, mState2);
assertEquals(mState.hashCode(), mState2.hashCode());
diff --git a/core/tests/coretests/src/android/view/autofill/AutofillIdTest.java b/core/tests/coretests/src/android/view/autofill/AutofillIdTest.java
index a8ca6f048a11..b329e55b569f 100644
--- a/core/tests/coretests/src/android/view/autofill/AutofillIdTest.java
+++ b/core/tests/coretests/src/android/view/autofill/AutofillIdTest.java
@@ -126,6 +126,32 @@ public class AutofillIdTest {
}
@Test
+ public void testVirtual_Long_withoutSession() {
+ final AutofillId id = new AutofillId(new AutofillId(42), 108L, 666);
+ final AutofillId idWithoutSession = AutofillId.withoutSession(id);
+ assertThat(idWithoutSession.getViewId()).isEqualTo(42);
+ assertThat(idWithoutSession.isVirtualLong()).isTrue();
+ assertThat(idWithoutSession.isVirtualInt()).isFalse();
+ assertThat(idWithoutSession.isNonVirtual()).isFalse();
+ assertThat(idWithoutSession.getVirtualChildLongId()).isEqualTo(108L);
+ assertThat(idWithoutSession.getVirtualChildIntId()).isEqualTo(View.NO_ID);
+ assertThat(idWithoutSession.getSessionId()).isEqualTo(NO_SESSION);
+ }
+
+ @Test
+ public void testVirtual_Int_withoutSession() {
+ final AutofillId id = new AutofillId(42, 108);
+ final AutofillId idWithoutSession = AutofillId.withoutSession(id);
+ assertThat(idWithoutSession.getViewId()).isEqualTo(42);
+ assertThat(idWithoutSession.isVirtualLong()).isFalse();
+ assertThat(idWithoutSession.isVirtualInt()).isTrue();
+ assertThat(idWithoutSession.isNonVirtual()).isFalse();
+ assertThat(idWithoutSession.getVirtualChildIntId()).isEqualTo(108);
+ assertThat(idWithoutSession.getVirtualChildLongId()).isEqualTo(View.NO_ID);
+ assertThat(idWithoutSession.getSessionId()).isEqualTo(NO_SESSION);
+ }
+
+ @Test
public void testSetResetSession() {
final AutofillId id = new AutofillId(42);
assertNonVirtual(id, 42, NO_SESSION);
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 dcecb5f32096..49de7c80057f 100644
--- a/core/tests/coretests/src/com/android/internal/app/ChooserActivityTest.java
+++ b/core/tests/coretests/src/com/android/internal/app/ChooserActivityTest.java
@@ -21,6 +21,7 @@ import static androidx.test.espresso.action.ViewActions.click;
import static androidx.test.espresso.action.ViewActions.swipeUp;
import static androidx.test.espresso.assertion.ViewAssertions.doesNotExist;
import static androidx.test.espresso.assertion.ViewAssertions.matches;
+import static androidx.test.espresso.matcher.ViewMatchers.hasSibling;
import static androidx.test.espresso.matcher.ViewMatchers.isDisplayed;
import static androidx.test.espresso.matcher.ViewMatchers.withId;
import static androidx.test.espresso.matcher.ViewMatchers.withText;
@@ -34,9 +35,11 @@ import static com.android.internal.app.ChooserListAdapter.SHORTCUT_TARGET_SCORE_
import static com.android.internal.app.ChooserWrapperActivity.sOverrides;
import static com.android.internal.app.MatcherUtils.first;
+import static junit.framework.Assert.assertFalse;
import static junit.framework.Assert.assertNull;
import static junit.framework.Assert.assertTrue;
+import static org.hamcrest.CoreMatchers.allOf;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.CoreMatchers.not;
import static org.hamcrest.CoreMatchers.notNullValue;
@@ -297,9 +300,8 @@ public class ChooserActivityTest {
public void fourOptionsStackedIntoOneTarget() throws InterruptedException {
Intent sendIntent = createSendTextIntent();
- // create 12 unique app targets to ensure the app ranking row can be filled, otherwise
- // targets will not stack
- List<ResolvedComponentInfo> resolvedComponentInfos = createResolvedComponentsForTest(12);
+ // create just enough targets to ensure the a-z list should be shown
+ List<ResolvedComponentInfo> resolvedComponentInfos = createResolvedComponentsForTest(1);
// next create 4 targets in a single app that should be stacked into a single target
String packageName = "xxx.yyy";
@@ -326,8 +328,8 @@ public class ChooserActivityTest {
.launchActivity(Intent.createChooser(sendIntent, null));
waitForIdle();
- // expect 12 unique targets + 1 group + 4 ranked app targets
- assertThat(activity.getAdapter().getCount(), is(17));
+ // expect 1 unique targets + 1 group + 4 ranked app targets
+ assertThat(activity.getAdapter().getCount(), is(6));
ResolveInfo[] chosen = new ResolveInfo[1];
sOverrides.onSafelyStartCallback = targetInfo -> {
@@ -335,7 +337,7 @@ public class ChooserActivityTest {
return true;
};
- onView(withText(appName)).perform(click());
+ onView(allOf(withText(appName), hasSibling(withText("")))).perform(click());
waitForIdle();
// clicking will launch a dialog to choose the activity within the app
@@ -1327,7 +1329,6 @@ public class ChooserActivityTest {
assertThat(activity.getWorkListAdapter().getCount(), is(workProfileTargets));
}
- @Ignore // b/148156663
@Test
public void testWorkTab_selectingWorkTabAppOpensAppInWorkProfile() throws InterruptedException {
// enable the work tab feature flag
@@ -1354,8 +1355,10 @@ public class ChooserActivityTest {
// wait for the share sheet to expand
Thread.sleep(ChooserActivity.LIST_VIEW_UPDATE_INTERVAL_IN_MILLIS);
- onView(first(withText(workResolvedComponentInfos.get(0)
- .getResolveInfoAt(0).activityInfo.applicationInfo.name)))
+ onView(first(allOf(
+ withText(workResolvedComponentInfos.get(0)
+ .getResolveInfoAt(0).activityInfo.applicationInfo.name),
+ isDisplayed())))
.perform(click());
waitForIdle();
assertThat(chosen[0], is(workResolvedComponentInfos.get(0).getResolveInfoAt(0)));
@@ -1953,6 +1956,45 @@ public class ChooserActivityTest {
assertThat(activity.getAdapter().getRankedTargetCount(), is(3));
}
+ @Test
+ public void testWorkTab_selectingWorkTabWithPausedWorkProfile_directShareTargetsNotQueried() {
+ // enable the work tab feature flag
+ ResolverActivity.ENABLE_TABBED_VIEW = true;
+ markWorkProfileUserAvailable();
+ List<ResolvedComponentInfo> personalResolvedComponentInfos =
+ createResolvedComponentsForTestWithOtherProfile(3, /* userId */ 10);
+ List<ResolvedComponentInfo> workResolvedComponentInfos =
+ createResolvedComponentsForTest(3);
+ setupResolverControllers(personalResolvedComponentInfos, workResolvedComponentInfos);
+ sOverrides.isQuietModeEnabled = true;
+ boolean[] isQueryDirectShareCalledOnWorkProfile = new boolean[] { false };
+ sOverrides.onQueryDirectShareTargets = chooserListAdapter -> {
+ isQueryDirectShareCalledOnWorkProfile[0] =
+ (chooserListAdapter.getUserHandle().getIdentifier() == 10);
+ return null;
+ };
+ boolean[] isQueryTargetServicesCalledOnWorkProfile = new boolean[] { false };
+ sOverrides.onQueryTargetServices = chooserListAdapter -> {
+ isQueryTargetServicesCalledOnWorkProfile[0] =
+ (chooserListAdapter.getUserHandle().getIdentifier() == 10);
+ return null;
+ };
+ Intent sendIntent = createSendTextIntent();
+ sendIntent.setType("TestType");
+
+ mActivityRule.launchActivity(Intent.createChooser(sendIntent, "work tab test"));
+ waitForIdle();
+ onView(withId(R.id.contentPanel))
+ .perform(swipeUp());
+ onView(withText(R.string.resolver_work_tab)).perform(click());
+ waitForIdle();
+
+ assertFalse("Direct share targets were queried on a paused work profile",
+ isQueryDirectShareCalledOnWorkProfile[0]);
+ assertFalse("Target services were queried on a paused work profile",
+ isQueryTargetServicesCalledOnWorkProfile[0]);
+ }
+
private Intent createChooserIntent(Intent intent, Intent[] initialIntents) {
Intent chooserIntent = new Intent();
chooserIntent.setAction(Intent.ACTION_CHOOSER);
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 749b0e54b880..44a52639bd35 100644
--- a/core/tests/coretests/src/com/android/internal/app/ChooserWrapperActivity.java
+++ b/core/tests/coretests/src/com/android/internal/app/ChooserWrapperActivity.java
@@ -205,6 +205,23 @@ public class ChooserWrapperActivity extends ChooserActivity {
return getApplicationContext();
}
+ @Override
+ protected void queryDirectShareTargets(ChooserListAdapter adapter,
+ boolean skipAppPredictionService) {
+ if (sOverrides.onQueryDirectShareTargets != null) {
+ sOverrides.onQueryDirectShareTargets.apply(adapter);
+ }
+ super.queryDirectShareTargets(adapter, skipAppPredictionService);
+ }
+
+ @Override
+ protected void queryTargetServices(ChooserListAdapter adapter) {
+ if (sOverrides.onQueryTargetServices != null) {
+ sOverrides.onQueryTargetServices.apply(adapter);
+ }
+ super.queryTargetServices(adapter);
+ }
+
/**
* We cannot directly mock the activity created since instrumentation creates it.
* <p>
@@ -214,6 +231,8 @@ public class ChooserWrapperActivity extends ChooserActivity {
@SuppressWarnings("Since15")
public Function<PackageManager, PackageManager> createPackageManager;
public Function<TargetInfo, Boolean> onSafelyStartCallback;
+ public Function<ChooserListAdapter, Void> onQueryDirectShareTargets;
+ public Function<ChooserListAdapter, Void> onQueryTargetServices;
public ResolverListController resolverListController;
public ResolverListController workResolverListController;
public Boolean isVoiceInteraction;
@@ -233,6 +252,8 @@ public class ChooserWrapperActivity extends ChooserActivity {
public void reset() {
onSafelyStartCallback = null;
+ onQueryDirectShareTargets = null;
+ onQueryTargetServices = null;
isVoiceInteraction = null;
createPackageManager = null;
previewThumbnail = null;
diff --git a/core/tests/coretests/src/com/android/internal/app/ResolverActivityTest.java b/core/tests/coretests/src/com/android/internal/app/ResolverActivityTest.java
index 8bee1e5cab3b..7dc5a8b58f91 100644
--- a/core/tests/coretests/src/com/android/internal/app/ResolverActivityTest.java
+++ b/core/tests/coretests/src/com/android/internal/app/ResolverActivityTest.java
@@ -592,7 +592,6 @@ public class ResolverActivityTest {
TextUtils.equals(initialText, currentText));
}
- @Ignore // b/148156663
@Test
public void testWorkTab_noPersonalApps_canStartWorkApps()
throws InterruptedException {
@@ -617,8 +616,10 @@ public class ResolverActivityTest {
waitForIdle();
// wait for the share sheet to expand
Thread.sleep(ChooserActivity.LIST_VIEW_UPDATE_INTERVAL_IN_MILLIS);
- onView(first(allOf(withText(workResolvedComponentInfos.get(0)
- .getResolveInfoAt(0).activityInfo.applicationInfo.name), isCompletelyDisplayed())))
+ onView(first(allOf(
+ withText(workResolvedComponentInfos.get(0)
+ .getResolveInfoAt(0).activityInfo.applicationInfo.name),
+ isDisplayed())))
.perform(click());
onView(withId(R.id.button_once))
.perform(click());
diff --git a/core/tests/hdmitests/src/android/hardware/hdmi/HdmiAudioSystemClientTest.java b/core/tests/hdmitests/src/android/hardware/hdmi/HdmiAudioSystemClientTest.java
index 7cd2f3b4c2ab..a4f206586625 100644
--- a/core/tests/hdmitests/src/android/hardware/hdmi/HdmiAudioSystemClientTest.java
+++ b/core/tests/hdmitests/src/android/hardware/hdmi/HdmiAudioSystemClientTest.java
@@ -363,6 +363,16 @@ public class HdmiAudioSystemClientTest {
public boolean isHdmiCecVolumeControlEnabled() {
return true;
}
+
+ @Override
+ public void addHdmiCecVolumeControlFeatureListener(
+ IHdmiCecVolumeControlFeatureListener listener) {
+ }
+
+ @Override
+ public void removeHdmiCecVolumeControlFeatureListener(
+ IHdmiCecVolumeControlFeatureListener listener) {
+ }
}
}
diff --git a/core/tests/overlaytests/remount/Android.bp b/core/tests/overlaytests/remount/Android.bp
index 5757cfe75514..939334c94312 100644
--- a/core/tests/overlaytests/remount/Android.bp
+++ b/core/tests/overlaytests/remount/Android.bp
@@ -19,6 +19,9 @@ java_test_host {
"tradefed",
"junit",
],
+ static_libs: [
+ "frameworks-base-hostutils",
+ ],
test_suites: ["general-tests"],
java_resources: [
":com.android.overlaytest.overlaid",
@@ -28,5 +31,6 @@ java_test_host {
":OverlayRemountedTest_Target",
":OverlayRemountedTest_TargetUpgrade",
":OverlayRemountedTest_Overlay",
+ ":OverlayRemountedTest_Overlay_SameCert",
],
}
diff --git a/core/tests/overlaytests/remount/src/com/android/overlaytest/remounted/OverlayRemountedTestBase.java b/core/tests/overlaytests/remount/src/com/android/overlaytest/remounted/OverlayRemountedTestBase.java
index 14b5bf6eacba..1a39e20f9a2b 100644
--- a/core/tests/overlaytests/remount/src/com/android/overlaytest/remounted/OverlayRemountedTestBase.java
+++ b/core/tests/overlaytests/remount/src/com/android/overlaytest/remounted/OverlayRemountedTestBase.java
@@ -18,6 +18,7 @@ package com.android.overlaytest.remounted;
import static org.junit.Assert.fail;
+import com.android.internal.util.test.SystemPreparer;
import com.android.tradefed.device.DeviceNotAvailableException;
import com.android.tradefed.testtype.junit4.BaseHostJUnit4Test;
diff --git a/core/tests/overlaytests/remount/src/com/android/overlaytest/remounted/PackagedUpgradedTest.java b/core/tests/overlaytests/remount/src/com/android/overlaytest/remounted/RegenerateIdmapTest.java
index a4656403b03f..2b68015536ed 100644
--- a/core/tests/overlaytests/remount/src/com/android/overlaytest/remounted/PackagedUpgradedTest.java
+++ b/core/tests/overlaytests/remount/src/com/android/overlaytest/remounted/RegenerateIdmapTest.java
@@ -22,7 +22,9 @@ import org.junit.Test;
import org.junit.runner.RunWith;
@RunWith(DeviceJUnit4ClassRunner.class)
-public class PackagedUpgradedTest extends OverlayRemountedTestBase {
+public class RegenerateIdmapTest extends OverlayRemountedTestBase {
+ private static final String OVERLAY_SIGNATURE_APK =
+ "OverlayRemountedTest_Overlay_SameCert.apk";
private static final String TARGET_UPGRADE_APK = "OverlayRemountedTest_TargetUpgrade.apk";
@Test
@@ -66,4 +68,32 @@ public class PackagedUpgradedTest extends OverlayRemountedTestBase {
assertResource(targetReference, "@" + 0x7f0100ff + " -> true");
assertResource(targetOverlaid, "true");
}
+
+ @Test
+ public void testIdmapPoliciesChanged() throws Exception {
+ final String targetResource = resourceName(TARGET_PACKAGE, "bool",
+ "signature_policy_overlaid");
+
+ mPreparer.pushResourceFile(TARGET_APK, "/product/app/OverlayTarget.apk")
+ .pushResourceFile(OVERLAY_APK, "/product/overlay/TestOverlay.apk")
+ .reboot()
+ .setOverlayEnabled(OVERLAY_PACKAGE, false);
+
+ assertResource(targetResource, "false");
+
+ // The overlay is not signed with the same signature as the target.
+ mPreparer.setOverlayEnabled(OVERLAY_PACKAGE, true);
+ assertResource(targetResource, "false");
+
+ // Replace the overlay with a version of the overlay that is signed with the same signature
+ // as the target.
+ mPreparer.pushResourceFile(OVERLAY_SIGNATURE_APK, "/product/overlay/TestOverlay.apk")
+ .reboot();
+
+ // The idmap should have been recreated with the signature policy fulfilled.
+ assertResource(targetResource, "true");
+
+ mPreparer.setOverlayEnabled(OVERLAY_PACKAGE, false);
+ assertResource(targetResource, "false");
+ }
}
diff --git a/core/tests/overlaytests/remount/src/com/android/overlaytest/remounted/SystemPreparer.java b/core/tests/overlaytests/remount/src/com/android/overlaytest/remounted/SystemPreparer.java
deleted file mode 100644
index bb72d0ee1d03..000000000000
--- a/core/tests/overlaytests/remount/src/com/android/overlaytest/remounted/SystemPreparer.java
+++ /dev/null
@@ -1,151 +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.overlaytest.remounted;
-
-import static org.junit.Assert.assertTrue;
-
-import com.android.tradefed.device.DeviceNotAvailableException;
-import com.android.tradefed.device.ITestDevice;
-
-import org.junit.Assert;
-import org.junit.rules.ExternalResource;
-import org.junit.rules.TemporaryFolder;
-
-import java.io.File;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.util.ArrayList;
-
-class SystemPreparer extends ExternalResource {
- private static final long OVERLAY_ENABLE_TIMEOUT_MS = 30000;
-
- // The paths of the files pushed onto the device through this rule.
- private ArrayList<String> mPushedFiles = new ArrayList<>();
-
- // The package names of packages installed through this rule.
- private ArrayList<String> mInstalledPackages = new ArrayList<>();
-
- private final TemporaryFolder mHostTempFolder;
- private final DeviceProvider mDeviceProvider;
-
- SystemPreparer(TemporaryFolder hostTempFolder, DeviceProvider deviceProvider) {
- mHostTempFolder = hostTempFolder;
- mDeviceProvider = deviceProvider;
- }
-
- /** Copies a file within the host test jar to a path on device. */
- SystemPreparer pushResourceFile(String resourcePath,
- String outputPath) throws DeviceNotAvailableException, IOException {
- final ITestDevice device = mDeviceProvider.getDevice();
- remount();
- assertTrue(device.pushFile(copyResourceToTemp(resourcePath), outputPath));
- mPushedFiles.add(outputPath);
- return this;
- }
-
- /** Installs an APK within the host test jar onto the device. */
- SystemPreparer installResourceApk(String resourcePath, String packageName)
- throws DeviceNotAvailableException, IOException {
- final ITestDevice device = mDeviceProvider.getDevice();
- final File tmpFile = copyResourceToTemp(resourcePath);
- final String result = device.installPackage(tmpFile, true /* reinstall */);
- Assert.assertNull(result);
- mInstalledPackages.add(packageName);
- return this;
- }
-
- /** Sets the enable state of an overlay package. */
- SystemPreparer setOverlayEnabled(String packageName, boolean enabled)
- throws DeviceNotAvailableException {
- final ITestDevice device = mDeviceProvider.getDevice();
- final String enable = enabled ? "enable" : "disable";
-
- // Wait for the overlay to change its enabled state.
- final long endMillis = System.currentTimeMillis() + OVERLAY_ENABLE_TIMEOUT_MS;
- String result;
- while (System.currentTimeMillis() <= endMillis) {
- device.executeShellCommand(String.format("cmd overlay %s %s", enable, packageName));
- result = device.executeShellCommand("cmd overlay dump isenabled "
- + packageName);
- if (((enabled) ? "true\n" : "false\n").equals(result)) {
- return this;
- }
-
- try {
- Thread.sleep(200);
- } catch (InterruptedException ignore) {
- }
- }
-
- throw new IllegalStateException(String.format("Failed to %s overlay %s:\n%s", enable,
- packageName, device.executeShellCommand("cmd overlay list")));
- }
-
- /** Restarts the device and waits until after boot is completed. */
- SystemPreparer reboot() throws DeviceNotAvailableException {
- final ITestDevice device = mDeviceProvider.getDevice();
- device.reboot();
- return this;
- }
-
- SystemPreparer remount() throws DeviceNotAvailableException {
- mDeviceProvider.getDevice().executeAdbCommand("remount");
- return this;
- }
-
- /** Copies a file within the host test jar to a temporary file on the host machine. */
- private File copyResourceToTemp(String resourcePath) throws IOException {
- final File tempFile = mHostTempFolder.newFile(resourcePath);
- final ClassLoader classLoader = getClass().getClassLoader();
- try (InputStream assetIs = classLoader.getResource(resourcePath).openStream();
- FileOutputStream assetOs = new FileOutputStream(tempFile)) {
- if (assetIs == null) {
- throw new IllegalStateException("Failed to find resource " + resourcePath);
- }
-
- int b;
- while ((b = assetIs.read()) >= 0) {
- assetOs.write(b);
- }
- }
-
- return tempFile;
- }
-
- /** Removes installed packages and files that were pushed to the device. */
- @Override
- protected void after() {
- final ITestDevice device = mDeviceProvider.getDevice();
- try {
- remount();
- for (final String file : mPushedFiles) {
- device.deleteFile(file);
- }
- for (final String packageName : mInstalledPackages) {
- device.uninstallPackage(packageName);
- }
- device.reboot();
- } catch (DeviceNotAvailableException e) {
- Assert.fail(e.toString());
- }
- }
-
- interface DeviceProvider {
- ITestDevice getDevice();
- }
-}
diff --git a/core/tests/overlaytests/remount/test-apps/Overlay/Android.bp b/core/tests/overlaytests/remount/test-apps/Overlay/Android.bp
index a1fdbfd3542c..032a0cdcb50d 100644
--- a/core/tests/overlaytests/remount/test-apps/Overlay/Android.bp
+++ b/core/tests/overlaytests/remount/test-apps/Overlay/Android.bp
@@ -19,3 +19,9 @@ android_test_helper_app {
"com.android.overlaytest.overlay",
],
}
+
+android_test_helper_app {
+ name: "OverlayRemountedTest_Overlay_SameCert",
+ certificate: ":rro-remounted-test-a",
+ sdk_version: "current",
+} \ No newline at end of file
diff --git a/core/tests/overlaytests/remount/test-apps/Overlay/res/values/values.xml b/core/tests/overlaytests/remount/test-apps/Overlay/res/values/values.xml
index 675e44f19f95..927d37fc60b9 100644
--- a/core/tests/overlaytests/remount/test-apps/Overlay/res/values/values.xml
+++ b/core/tests/overlaytests/remount/test-apps/Overlay/res/values/values.xml
@@ -17,4 +17,5 @@
<resources>
<bool name="target_overlaid">true</bool>
+ <bool name="signature_policy_overlaid">true</bool>
</resources>
diff --git a/core/tests/overlaytests/remount/test-apps/Target/Android.bp b/core/tests/overlaytests/remount/test-apps/Target/Android.bp
index 19947b1ea51a..e4b4eaa8d220 100644
--- a/core/tests/overlaytests/remount/test-apps/Target/Android.bp
+++ b/core/tests/overlaytests/remount/test-apps/Target/Android.bp
@@ -15,6 +15,7 @@
android_test_helper_app {
name: "OverlayRemountedTest_Target",
sdk_version: "test_current",
+ certificate: ":rro-remounted-test-a",
apex_available: [
"com.android.overlaytest.overlaid",
],
@@ -23,6 +24,7 @@ android_test_helper_app {
android_test_helper_app {
name: "OverlayRemountedTest_TargetUpgrade",
+ certificate: ":rro-remounted-test-a",
resource_dirs: ["res_upgrade"],
sdk_version: "test_current",
}
diff --git a/core/tests/overlaytests/remount/test-apps/Target/res/values/overlayable.xml b/core/tests/overlaytests/remount/test-apps/Target/res/values/overlayable.xml
index 4aa5bcee8f3d..79c9a675a6dd 100644
--- a/core/tests/overlaytests/remount/test-apps/Target/res/values/overlayable.xml
+++ b/core/tests/overlaytests/remount/test-apps/Target/res/values/overlayable.xml
@@ -20,5 +20,8 @@
<policy type="public">
<item type="bool" name="target_overlaid" />
</policy>
+ <policy type="signature">
+ <item type="bool" name="signature_policy_overlaid" />
+ </policy>
</overlayable>
</resources>
diff --git a/core/tests/overlaytests/remount/test-apps/Target/res/values/values.xml b/core/tests/overlaytests/remount/test-apps/Target/res/values/values.xml
index 76253a95b766..64a1683e14be 100644
--- a/core/tests/overlaytests/remount/test-apps/Target/res/values/values.xml
+++ b/core/tests/overlaytests/remount/test-apps/Target/res/values/values.xml
@@ -23,4 +23,6 @@
<bool name="target_overlaid">false</bool>
<public type="bool" name="target_overlaid" id="0x7f010000" />
<bool name="target_reference">@bool/target_overlaid</bool>
+
+ <bool name="signature_policy_overlaid">false</bool>
</resources>
diff --git a/core/tests/overlaytests/remount/test-apps/certs/Android.bp b/core/tests/overlaytests/remount/test-apps/certs/Android.bp
new file mode 100644
index 000000000000..06114efc1249
--- /dev/null
+++ b/core/tests/overlaytests/remount/test-apps/certs/Android.bp
@@ -0,0 +1,19 @@
+// 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.
+
+// development/tools/make_key rro-remounted-test-a '/CN=rro_test_a'
+android_app_certificate {
+ name: "rro-remounted-test-a",
+ certificate: "rro-remounted-test-a",
+}
diff --git a/core/tests/overlaytests/remount/test-apps/certs/rro-remounted-test-a.pk8 b/core/tests/overlaytests/remount/test-apps/certs/rro-remounted-test-a.pk8
new file mode 100644
index 000000000000..aa6cc97d07f6
--- /dev/null
+++ b/core/tests/overlaytests/remount/test-apps/certs/rro-remounted-test-a.pk8
Binary files differ
diff --git a/core/tests/overlaytests/remount/test-apps/certs/rro-remounted-test-a.x509.pem b/core/tests/overlaytests/remount/test-apps/certs/rro-remounted-test-a.x509.pem
new file mode 100644
index 000000000000..be491c7029fe
--- /dev/null
+++ b/core/tests/overlaytests/remount/test-apps/certs/rro-remounted-test-a.x509.pem
@@ -0,0 +1,19 @@
+-----BEGIN CERTIFICATE-----
+MIIDCzCCAfOgAwIBAgIUfphI+C6W6V6RomsP7+CW5dO5cGcwDQYJKoZIhvcNAQEL
+BQAwFTETMBEGA1UEAwwKcnJvX3Rlc3RfYTAeFw0yMDA1MTQxNjM4MDBaFw00NzA5
+MzAxNjM4MDBaMBUxEzARBgNVBAMMCnJyb190ZXN0X2EwggEiMA0GCSqGSIb3DQEB
+AQUAA4IBDwAwggEKAoIBAQCvXM8tcqQFwH7iQG6+8mAx2ADhwbtq+8Rcmiz7wviW
+Yf/eFDRuvZ/ma6lxeVJ7mcbF7A5rinEKdgN5hlW2UlbTmuX5YOiXnX3Y2J5t+8Pi
+aq787IvWxkawwkj0Oy1Hk01Z4w3HTYntYqi36bq4QyNpwh515VqgvEyCHT7IPtQi
+XjfwcTW0thUlSDyDkgxq9NxNEJgaHHOamKkeMCO8CkBWkhlcPXvjcM8DPFmyzDI9
+Czv8IYFZQbcG/N2GPH9hSteMnuC+zyoMio0V/VRctQGlAA8ATsheBkng0zcNRu9Z
+GIavk5AaClmBFTeQx01j3HFSO8UDdDJ5Hk8uDTqecPLpAgMBAAGjUzBRMB0GA1Ud
+DgQWBBSPbIdzSkPbzltj3qIS13LNDiyIiDAfBgNVHSMEGDAWgBSPbIdzSkPbzltj
+3qIS13LNDiyIiDAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQCH
+QvvMGyMvVJaWMEJwVdUnszdXiAlUtDd/2HpdGOxW6xVVAvveP8hJ71gWFQ7Qs3Mr
+3jxclbC37qVAPiQb8kkD8qUgoQYMC43asif6Jn65OU1QkDRF3bFHP+rZVSPEwtvl
+YMbOzHPOLr7HESwlM7TB6EoZ4oOso++jTYI/OSif1MOKOMbOt4X/DE/PXf81ayFs
+uRjpocBqnLwOourABMcaKbA92jB0LRTtgv5ngOJ3+5P1cTiHktFbnqVWa8/A3uSA
+dNR5dpOUjH+nCHTwPl64b7R70PgDxnoqMs0xI7VtJovXor64OZy9P8WTdurz5V/z
+k2IVSi032bf0aTxamvqV
+-----END CERTIFICATE-----
diff --git a/core/tests/screenshothelpertests/src/com/android/internal/util/ScreenshotHelperTest.java b/core/tests/screenshothelpertests/src/com/android/internal/util/ScreenshotHelperTest.java
index fe33cd80f735..4b8173732b4d 100644
--- a/core/tests/screenshothelpertests/src/com/android/internal/util/ScreenshotHelperTest.java
+++ b/core/tests/screenshothelpertests/src/com/android/internal/util/ScreenshotHelperTest.java
@@ -29,11 +29,12 @@ import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
+import android.content.ComponentName;
import android.content.Context;
import android.content.res.Resources;
-import android.graphics.Bitmap;
import android.graphics.Insets;
import android.graphics.Rect;
+import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.view.WindowManager;
@@ -91,8 +92,7 @@ public final class ScreenshotHelperTest {
@Test
public void testProvidedImageScreenshot() {
mScreenshotHelper.provideScreenshot(
- Bitmap.createBitmap(10, 10, Bitmap.Config.ARGB_8888), new Rect(),
- Insets.of(0, 0, 0, 0), 1,
+ new Bundle(), new Rect(), Insets.of(0, 0, 0, 0), 1, 1, new ComponentName("", ""),
WindowManager.ScreenshotSource.SCREENSHOT_OTHER, mHandler, null);
}
diff --git a/data/etc/car/Android.bp b/data/etc/car/Android.bp
index 1b1a624cda50..d6542de91e08 100644
--- a/data/etc/car/Android.bp
+++ b/data/etc/car/Android.bp
@@ -122,6 +122,13 @@ prebuilt_etc {
}
prebuilt_etc {
+ name: "privapp_whitelist_com.android.car.bugreport",
+ sub_dir: "permissions",
+ src: "com.android.car.bugreport.xml",
+ filename_from_src: true,
+}
+
+prebuilt_etc {
name: "privapp_whitelist_com.google.android.car.kitchensink",
sub_dir: "permissions",
src: "com.google.android.car.kitchensink.xml",
diff --git a/packages/CarSystemUI/res/drawable/nav_button_background.xml b/data/etc/car/com.android.car.bugreport.xml
index 376347cdf4a9..432a838a90e8 100644
--- a/packages/CarSystemUI/res/drawable/nav_button_background.xml
+++ b/data/etc/car/com.android.car.bugreport.xml
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
- ~ Copyright (C) 2018 The Android Open Source Project
+ ~ 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.
@@ -14,13 +14,11 @@
~ See the License for the specific language governing permissions and
~ limitations under the License
-->
-
-<ripple xmlns:android="http://schemas.android.com/apk/res/android"
- android:color="@color/nav_bar_ripple_background_color">
- <item android:id="@android:id/mask">
- <shape android:shape="rectangle">
- <solid android:color="?android:colorAccent"/>
- <corners android:radius="6dp"/>
- </shape>
- </item>
-</ripple>
+<permissions>
+ <privapp-permissions package="com.android.car.bugreport">
+ <permission name="android.permission.DUMP"/>
+ <permission name="android.permission.INTERACT_ACROSS_USERS"/>
+ <permission name="android.permission.READ_LOGS"/>
+ <permission name="android.permission.MANAGE_USERS"/>
+ </privapp-permissions>
+ </permissions>
diff --git a/data/etc/preinstalled-packages-platform.xml b/data/etc/preinstalled-packages-platform.xml
index 17e1f2e0c229..625558406b9c 100644
--- a/data/etc/preinstalled-packages-platform.xml
+++ b/data/etc/preinstalled-packages-platform.xml
@@ -17,7 +17,9 @@
<!--
This XML file declares which system packages should be initially installed for new users based on
their user type. All system packages on the device should ideally have an entry in an xml file
-(keyed by its manifest name).
+(keyed by its manifest name), except auto-generated rro packages. Auto-generated RRO packages
+(package name ends with ".auto_generated_rro_product__" or ".auto_generated_rro_vendor__")
+will be installed for new users according to corresponding overlay target packages.
Base user-types (every user will be at least one of these types) are:
SYSTEM (user 0)
@@ -51,7 +53,7 @@ The following three examples should cover most normal cases:
2. For a system package to be pre-installed on all human users (e.g. a web browser), i.e. to be
-installed on any user of type type FULL or PROFILE (since this covers all human users):
+installed on any user of type FULL or PROFILE (since this covers all human users):
<install-in-user-type package="com.android.example">
<install-in user-type="FULL" />
diff --git a/data/etc/privapp-permissions-platform.xml b/data/etc/privapp-permissions-platform.xml
index e00813ce2aaf..9b503eba5c68 100644
--- a/data/etc/privapp-permissions-platform.xml
+++ b/data/etc/privapp-permissions-platform.xml
@@ -378,6 +378,9 @@ applications that come with the platform
<permission name="android.permission.SET_WALLPAPER" />
<permission name="android.permission.SET_WALLPAPER_COMPONENT" />
<permission name="android.permission.REQUEST_NOTIFICATION_ASSISTANT_SERVICE" />
+ <!-- Permissions required for Incremental CTS tests -->
+ <permission name="com.android.permission.USE_INSTALLER_V2"/>
+ <permission name="android.permission.LOADER_USAGE_STATS"/>
<!-- Permission required to test system only camera devices. -->
<permission name="android.permission.SYSTEM_CAMERA" />
<!-- Permission required to test ExplicitHealthCheckServiceImpl. -->
@@ -418,6 +421,8 @@ applications that come with the platform
<permission name="android.permission.TV_INPUT_HARDWARE" />
<!-- Permission required for CTS test - PrivilegedLocationPermissionTest -->
<permission name="android.permission.LOCATION_HARDWARE" />
+ <!-- Permissions required for GTS test - GtsDialerAudioTestCases -->
+ <permission name="android.permission.CAPTURE_AUDIO_OUTPUT" />
</privapp-permissions>
<privapp-permissions package="com.android.statementservice">
diff --git a/data/keyboards/Vendor_045e_Product_0b12.kl b/data/keyboards/Vendor_045e_Product_0b12.kl
new file mode 100644
index 000000000000..0b44c7434af2
--- /dev/null
+++ b/data/keyboards/Vendor_045e_Product_0b12.kl
@@ -0,0 +1,59 @@
+# Copyright (C) 2020 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+#
+# XBox USB Controller
+#
+
+key 304 BUTTON_A
+key 305 BUTTON_B
+key 307 BUTTON_X
+key 308 BUTTON_Y
+key 310 BUTTON_L1
+key 311 BUTTON_R1
+
+key 317 BUTTON_THUMBL
+key 318 BUTTON_THUMBR
+
+# Left and right stick.
+# The reported value for flat is 128 out of a range from -32767 to 32768, which is absurd.
+# This confuses applications that rely on the flat value because the joystick actually
+# settles in a flat range of +/- 4096 or so.
+axis 0x00 X flat 4096
+axis 0x01 Y flat 4096
+axis 0x03 Z flat 4096
+axis 0x04 RZ flat 4096
+
+# Triggers.
+axis 0x02 LTRIGGER
+axis 0x05 RTRIGGER
+
+# Hat.
+axis 0x10 HAT_X
+axis 0x11 HAT_Y
+
+# Mapping according to https://www.kernel.org/doc/Documentation/input/gamepad.txt
+
+# Two overlapping rectangles
+key 314 BUTTON_SELECT
+
+# The branded "X" button in the center of the controller
+key 316 BUTTON_MODE
+
+# Three parallel horizontal lines (hamburger menu)
+key 315 BUTTON_START
+
+#Button below the "X" button
+key 167 MEDIA_RECORD
+
diff --git a/identity/java/android/security/identity/IdentityCredential.java b/identity/java/android/security/identity/IdentityCredential.java
index b351b3d77430..493c85a930be 100644
--- a/identity/java/android/security/identity/IdentityCredential.java
+++ b/identity/java/android/security/identity/IdentityCredential.java
@@ -167,25 +167,14 @@ public abstract class IdentityCredential {
* IntentToRetain = bool
* </pre>
*
- * <p>If the {@code sessionTranscript} parameter is not {@code null}, it must contain CBOR
- * data conforming to the following CDDL schema:
- *
- * <pre>
- * SessionTranscript = [
- * DeviceEngagementBytes,
- * EReaderKeyBytes
- * ]
- *
- * DeviceEngagementBytes = #6.24(bstr .cbor DeviceEngagement) ; Bytes of DeviceEngagement
- * EReaderKeyBytes = #6.24(bstr .cbor EReaderKey.Pub) ; Bytes of EReaderKey.pub
- *
- * EReaderKey.Pub = COSE_Key ; Ephemeral public key provided by reader
- * </pre>
- *
- * <p>where a {@code COSE_Key} structure for the public part of the key-pair previously
- * generated by {@link #createEphemeralKeyPair()} must appear somewhere in
- * {@code DeviceEngagement} and the X and Y coordinates must both be present
- * in uncompressed form.
+ * <p>If the {@code sessionTranscript} parameter is not {@code null}, the X and Y coordinates
+ * of the public part of the key-pair previously generated by {@link #createEphemeralKeyPair()}
+ * must appear somewhere in the bytes of the CBOR. Each of these coordinates must appear
+ * encoded with the most significant bits first and use the exact amount of bits indicated by
+ * the key size of the ephemeral keys. For example, if the ephemeral key is using the P-256
+ * curve then the 32 bytes for the X coordinate encoded with the most significant bits first
+ * must appear somewhere in {@code sessionTranscript} and ditto for the 32 bytes for the Y
+ * coordinate.
*
* <p>If {@code readerAuth} is not {@code null} it must be the bytes of a {@code COSE_Sign1}
* structure as defined in RFC 8152. For the payload nil shall be used and the
diff --git a/identity/java/android/security/identity/WritableIdentityCredential.java b/identity/java/android/security/identity/WritableIdentityCredential.java
index c7aa32855abc..305d0ead0652 100644
--- a/identity/java/android/security/identity/WritableIdentityCredential.java
+++ b/identity/java/android/security/identity/WritableIdentityCredential.java
@@ -56,10 +56,10 @@ public abstract class WritableIdentityCredential {
* authority doesn't care about the nature of the security hardware. If called, however, this
* method must be called before {@link #personalize(PersonalizationData)}.
*
- * @param challenge is a byte array whose contents should be unique, fresh and provided by
- * the issuing authority. The value provided is embedded in the attestation
- * extension and enables the issuing authority to verify that the attestation
- * certificate is fresh.
+ * @param challenge is a non-empty byte array whose contents should be unique, fresh and
+ * provided by the issuing authority. The value provided is embedded in the
+ * attestation extension and enables the issuing authority to verify that the
+ * attestation certificate is fresh.
* @return the X.509 certificate for this credential's CredentialKey.
*/
public abstract @NonNull Collection<X509Certificate> getCredentialKeyCertificateChain(
diff --git a/libs/androidfw/include/androidfw/ResourceTypes.h b/libs/androidfw/include/androidfw/ResourceTypes.h
index 2bfc7fc38d1c..21be81cb85bd 100644
--- a/libs/androidfw/include/androidfw/ResourceTypes.h
+++ b/libs/androidfw/include/androidfw/ResourceTypes.h
@@ -41,7 +41,7 @@
namespace android {
constexpr const static uint32_t kIdmapMagic = 0x504D4449u;
-constexpr const static uint32_t kIdmapCurrentVersion = 0x00000003u;
+constexpr const static uint32_t kIdmapCurrentVersion = 0x00000004u;
/**
* In C++11, char16_t is defined as *at least* 16 bits. We do a lot of
@@ -1746,6 +1746,9 @@ struct Idmap_header {
uint32_t target_crc32;
uint32_t overlay_crc32;
+ uint32_t fulfilled_policies;
+ uint8_t enforce_overlayable;
+
uint8_t target_path[256];
uint8_t overlay_path[256];
diff --git a/libs/androidfw/tests/data/overlay/overlay.apk b/libs/androidfw/tests/data/overlay/overlay.apk
index 62e98662e68d..f1ed59279fdb 100644
--- a/libs/androidfw/tests/data/overlay/overlay.apk
+++ b/libs/androidfw/tests/data/overlay/overlay.apk
Binary files differ
diff --git a/libs/androidfw/tests/data/overlay/overlay.idmap b/libs/androidfw/tests/data/overlay/overlay.idmap
index 3759ed650033..29c5eb6a9ccf 100644
--- a/libs/androidfw/tests/data/overlay/overlay.idmap
+++ b/libs/androidfw/tests/data/overlay/overlay.idmap
Binary files differ
diff --git a/location/java/com/android/internal/location/GpsNetInitiatedHandler.java b/location/java/com/android/internal/location/GpsNetInitiatedHandler.java
index 9846436b3ac8..67a040dba3e7 100644
--- a/location/java/com/android/internal/location/GpsNetInitiatedHandler.java
+++ b/location/java/com/android/internal/location/GpsNetInitiatedHandler.java
@@ -18,7 +18,6 @@ package com.android.internal.location;
import android.app.Notification;
import android.app.NotificationManager;
-import android.app.PendingIntent;
import android.compat.annotation.UnsupportedAppUsage;
import android.content.BroadcastReceiver;
import android.content.Context;
@@ -402,13 +401,9 @@ public class GpsNetInitiatedHandler {
mNiNotificationBuilder.setDefaults(0);
}
- // if not to popup dialog immediately, pending intent will open the dialog
- Intent intent = !mPopupImmediately ? getDlgIntent(notif) : new Intent();
- PendingIntent pi = PendingIntent.getBroadcast(mContext, 0, intent, 0);
mNiNotificationBuilder.setTicker(getNotifTicker(notif, mContext))
.setContentTitle(title)
- .setContentText(message)
- .setContentIntent(pi);
+ .setContentText(message);
notificationManager.notifyAsUser(null, notif.notificationId, mNiNotificationBuilder.build(),
UserHandle.ALL);
diff --git a/location/java/com/android/internal/location/gnssmetrics/GnssMetrics.java b/location/java/com/android/internal/location/gnssmetrics/GnssMetrics.java
index 323bba3fdd71..6c401161062f 100644
--- a/location/java/com/android/internal/location/gnssmetrics/GnssMetrics.java
+++ b/location/java/com/android/internal/location/gnssmetrics/GnssMetrics.java
@@ -32,7 +32,7 @@ import android.util.TimeUtils;
import com.android.internal.app.IBatteryStats;
import com.android.internal.location.nano.GnssLogsProto.GnssLog;
import com.android.internal.location.nano.GnssLogsProto.PowerMetrics;
-import com.android.internal.os.BackgroundThread;
+import com.android.internal.util.ConcurrentUtils;
import com.android.internal.util.FrameworkStatsLog;
import java.util.ArrayList;
@@ -124,8 +124,6 @@ public class GnssMetrics {
private long mL5SvStatusReportsUsedInFix;
/** Stats manager service for reporting atoms */
private StatsManager mStatsManager;
- /** Pull atom callback, this is called when atom pull request occurs */
- private StatsPullAtomCallbackImpl mPullAtomCallback;
/* Statds Logging Variables Section End */
public GnssMetrics(Context context, IBatteryStats stats) {
@@ -467,8 +465,8 @@ public class GnssMetrics {
mConstellationTypes = new boolean[GnssStatus.CONSTELLATION_COUNT];
}
- /** Class for storing statistics */
- private class Statistics {
+ /** Thread-safe class for storing statistics */
+ private static class Statistics {
private int mCount;
private double mSum;
@@ -476,7 +474,7 @@ public class GnssMetrics {
private long mLongSum;
/** Resets statistics */
- public void reset() {
+ public synchronized void reset() {
mCount = 0;
mSum = 0.0;
mSumSquare = 0.0;
@@ -484,7 +482,7 @@ public class GnssMetrics {
}
/** Adds an item */
- public void addItem(double item) {
+ public synchronized void addItem(double item) {
mCount++;
mSum += item;
mSumSquare += item * item;
@@ -492,17 +490,17 @@ public class GnssMetrics {
}
/** Returns number of items added */
- public int getCount() {
+ public synchronized int getCount() {
return mCount;
}
/** Returns mean */
- public double getMean() {
+ public synchronized double getMean() {
return mSum / mCount;
}
/** Returns standard deviation */
- public double getStandardDeviation() {
+ public synchronized double getStandardDeviation() {
double m = mSum / mCount;
m = m * m;
double v = mSumSquare / mCount;
@@ -513,7 +511,7 @@ public class GnssMetrics {
}
/** Returns long sum */
- public long getLongSum() {
+ public synchronized long getLongSum() {
return mLongSum;
}
}
@@ -623,11 +621,11 @@ public class GnssMetrics {
}
private void registerGnssStats() {
- mPullAtomCallback = new StatsPullAtomCallbackImpl();
+ StatsPullAtomCallbackImpl pullAtomCallback = new StatsPullAtomCallbackImpl();
mStatsManager.setPullAtomCallback(
FrameworkStatsLog.GNSS_STATS,
null, // use default PullAtomMetadata values
- BackgroundThread.getExecutor(), mPullAtomCallback);
+ ConcurrentUtils.DIRECT_EXECUTOR, pullAtomCallback);
}
/**
diff --git a/media/java/android/media/IMediaRouter2.aidl b/media/java/android/media/IMediaRouter2.aidl
index a8b82ba401eb..ca14052c964f 100644
--- a/media/java/android/media/IMediaRouter2.aidl
+++ b/media/java/android/media/IMediaRouter2.aidl
@@ -24,6 +24,8 @@ import android.os.Bundle;
* @hide
*/
oneway interface IMediaRouter2 {
+ void notifyRouterRegistered(in List<MediaRoute2Info> currentRoutes,
+ in RoutingSessionInfo currentSystemSessionInfo);
void notifyRoutesAdded(in List<MediaRoute2Info> routes);
void notifyRoutesRemoved(in List<MediaRoute2Info> routes);
void notifyRoutesChanged(in List<MediaRoute2Info> routes);
diff --git a/media/java/android/media/IMediaRouter2Manager.aidl b/media/java/android/media/IMediaRouter2Manager.aidl
index 5925d380115c..5113dc2058e0 100644
--- a/media/java/android/media/IMediaRouter2Manager.aidl
+++ b/media/java/android/media/IMediaRouter2Manager.aidl
@@ -24,8 +24,9 @@ import android.media.RoutingSessionInfo;
* {@hide}
*/
oneway interface IMediaRouter2Manager {
- void notifySessionCreated(int requestId, in RoutingSessionInfo sessionInfo);
- void notifySessionUpdated(in RoutingSessionInfo sessionInfo);
+ void notifySessionCreated(int requestId, in RoutingSessionInfo session);
+ void notifySessionUpdated(in RoutingSessionInfo session);
+ void notifySessionReleased(in RoutingSessionInfo session);
void notifyPreferredFeaturesChanged(String packageName, in List<String> preferredFeatures);
void notifyRoutesAdded(in List<MediaRoute2Info> routes);
void notifyRoutesRemoved(in List<MediaRoute2Info> routes);
diff --git a/media/java/android/media/MediaCas.java b/media/java/android/media/MediaCas.java
index c652628eb425..590def4d4ced 100644
--- a/media/java/android/media/MediaCas.java
+++ b/media/java/android/media/MediaCas.java
@@ -20,6 +20,7 @@ import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.TestApi;
+import android.app.ActivityManager;
import android.content.Context;
import android.hardware.cas.V1_0.HidlCasPluginDescriptor;
import android.hardware.cas.V1_0.ICas;
@@ -43,6 +44,8 @@ import android.os.RemoteException;
import android.util.Log;
import android.util.Singleton;
+import com.android.internal.util.FrameworkStatsLog;
+
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
@@ -122,6 +125,7 @@ public final class MediaCas implements AutoCloseable {
private String mTvInputServiceSessionId;
private int mClientId;
private int mCasSystemId;
+ private int mUserId;
private TunerResourceManager mTunerResourceManager = null;
private final Map<Session, Integer> mSessionMap = new HashMap<>();
@@ -673,6 +677,8 @@ public final class MediaCas implements AutoCloseable {
*/
public MediaCas(int CA_system_id) throws UnsupportedCasException {
try {
+ mCasSystemId = CA_system_id;
+ mUserId = ActivityManager.getCurrentUser();
IMediaCasService service = getService();
android.hardware.cas.V1_2.IMediaCasService serviceV12 =
android.hardware.cas.V1_2.IMediaCasService.castFrom(service);
@@ -721,7 +727,6 @@ public final class MediaCas implements AutoCloseable {
this(casSystemId);
Objects.requireNonNull(context, "context must not be null");
- mCasSystemId = casSystemId;
mTunerResourceManager = (TunerResourceManager)
context.getSystemService(Context.TV_TUNER_RESOURCE_MGR_SERVICE);
if (mTunerResourceManager != null) {
@@ -925,10 +930,18 @@ public final class MediaCas implements AutoCloseable {
mICas.openSession(cb);
MediaCasException.throwExceptionIfNeeded(cb.mStatus);
addSessionToResourceMap(cb.mSession, sessionResourceHandle);
+ Log.d(TAG, "Write Stats Log for succeed to Open Session.");
+ FrameworkStatsLog
+ .write(FrameworkStatsLog.TV_CAS_SESSION_OPEN_STATUS, mUserId, mCasSystemId,
+ FrameworkStatsLog.TV_CAS_SESSION_OPEN_STATUS__STATE__SUCCEEDED);
return cb.mSession;
} catch (RemoteException e) {
cleanupAndRethrowIllegalState();
}
+ Log.d(TAG, "Write Stats Log for fail to Open Session.");
+ FrameworkStatsLog
+ .write(FrameworkStatsLog.TV_CAS_SESSION_OPEN_STATUS, mUserId, mCasSystemId,
+ FrameworkStatsLog.TV_CAS_SESSION_OPEN_STATUS__STATE__FAILED);
return null;
}
@@ -964,10 +977,18 @@ public final class MediaCas implements AutoCloseable {
mICasV12.openSession_1_2(sessionUsage, scramblingMode, cb);
MediaCasException.throwExceptionIfNeeded(cb.mStatus);
addSessionToResourceMap(cb.mSession, sessionResourceHandle);
+ Log.d(TAG, "Write Stats Log for succeed to Open Session.");
+ FrameworkStatsLog
+ .write(FrameworkStatsLog.TV_CAS_SESSION_OPEN_STATUS, mUserId, mCasSystemId,
+ FrameworkStatsLog.TV_CAS_SESSION_OPEN_STATUS__STATE__SUCCEEDED);
return cb.mSession;
} catch (RemoteException e) {
cleanupAndRethrowIllegalState();
}
+ Log.d(TAG, "Write Stats Log for fail to Open Session.");
+ FrameworkStatsLog
+ .write(FrameworkStatsLog.TV_CAS_SESSION_OPEN_STATUS, mUserId, mCasSystemId,
+ FrameworkStatsLog.TV_CAS_SESSION_OPEN_STATUS__STATE__FAILED);
return null;
}
diff --git a/media/java/android/media/MediaRoute2ProviderService.java b/media/java/android/media/MediaRoute2ProviderService.java
index 72162c44ec29..05c6e3ad9392 100644
--- a/media/java/android/media/MediaRoute2ProviderService.java
+++ b/media/java/android/media/MediaRoute2ProviderService.java
@@ -137,7 +137,7 @@ public abstract class MediaRoute2ProviderService extends Service {
private final AtomicBoolean mStatePublishScheduled = new AtomicBoolean(false);
private MediaRoute2ProviderServiceStub mStub;
private IMediaRoute2ProviderServiceCallback mRemoteCallback;
- private MediaRoute2ProviderInfo mProviderInfo;
+ private volatile MediaRoute2ProviderInfo mProviderInfo;
@GuardedBy("mSessionLock")
private ArrayMap<String, RoutingSessionInfo> mSessionInfo = new ArrayMap<>();
@@ -167,8 +167,8 @@ public abstract class MediaRoute2ProviderService extends Service {
/**
* Called when a volume setting is requested on a route of the provider
*
- * @param requestId the id of this request
- * @param routeId the id of the route
+ * @param requestId the ID of this request
+ * @param routeId the ID of the route
* @param volume the target volume
* @see MediaRoute2Info.Builder#setVolume(int)
*/
@@ -178,8 +178,8 @@ public abstract class MediaRoute2ProviderService extends Service {
* Called when {@link MediaRouter2.RoutingController#setVolume(int)} is called on
* a routing session of the provider
*
- * @param requestId the id of this request
- * @param sessionId the id of the routing session
+ * @param requestId the ID of this request
+ * @param sessionId the ID of the routing session
* @param volume the target volume
* @see RoutingSessionInfo.Builder#setVolume(int)
*/
@@ -188,7 +188,7 @@ public abstract class MediaRoute2ProviderService extends Service {
/**
* Gets information of the session with the given id.
*
- * @param sessionId id of the session
+ * @param sessionId the ID of the session
* @return information of the session with the given id.
* null if the session is released or ID is not valid.
*/
@@ -218,7 +218,7 @@ public abstract class MediaRoute2ProviderService extends Service {
* If this session is created without any creation request, use {@link #REQUEST_ID_NONE}
* as the request ID.
*
- * @param requestId id of the previous request to create this session provided in
+ * @param requestId the ID of the previous request to create this session provided in
* {@link #onCreateSession(long, String, String, Bundle)}. Can be
* {@link #REQUEST_ID_NONE} if this session is created without any request.
* @param sessionInfo information of the new session.
@@ -233,23 +233,19 @@ public abstract class MediaRoute2ProviderService extends Service {
String sessionId = sessionInfo.getId();
synchronized (mSessionLock) {
if (mSessionInfo.containsKey(sessionId)) {
- // TODO: Notify failure to the requester, and throw exception if needed.
Log.w(TAG, "Ignoring duplicate session id.");
return;
}
mSessionInfo.put(sessionInfo.getId(), sessionInfo);
- }
- if (mRemoteCallback == null) {
- return;
- }
- try {
- // TODO: Calling binder calls in multiple thread may cause timing issue.
- // Consider to change implementations to avoid the problems.
- // For example, post binder calls, always send all sessions at once, etc.
- mRemoteCallback.notifySessionCreated(requestId, sessionInfo);
- } catch (RemoteException ex) {
- Log.w(TAG, "Failed to notify session created.");
+ if (mRemoteCallback == null) {
+ return;
+ }
+ try {
+ mRemoteCallback.notifySessionCreated(requestId, sessionInfo);
+ } catch (RemoteException ex) {
+ Log.w(TAG, "Failed to notify session created.");
+ }
}
}
@@ -268,22 +264,22 @@ public abstract class MediaRoute2ProviderService extends Service {
Log.w(TAG, "Ignoring unknown session info.");
return;
}
- }
- if (mRemoteCallback == null) {
- return;
- }
- try {
- mRemoteCallback.notifySessionUpdated(sessionInfo);
- } catch (RemoteException ex) {
- Log.w(TAG, "Failed to notify session info changed.");
+ if (mRemoteCallback == null) {
+ return;
+ }
+ try {
+ mRemoteCallback.notifySessionUpdated(sessionInfo);
+ } catch (RemoteException ex) {
+ Log.w(TAG, "Failed to notify session info changed.");
+ }
}
}
/**
* Notifies that the session is released.
*
- * @param sessionId id of the released session.
+ * @param sessionId the ID of the released session.
* @see #onReleaseSession(long, String)
*/
public final void notifySessionReleased(@NonNull String sessionId) {
@@ -293,20 +289,20 @@ public abstract class MediaRoute2ProviderService extends Service {
RoutingSessionInfo sessionInfo;
synchronized (mSessionLock) {
sessionInfo = mSessionInfo.remove(sessionId);
- }
- if (sessionInfo == null) {
- Log.w(TAG, "Ignoring unknown session info.");
- return;
- }
+ if (sessionInfo == null) {
+ Log.w(TAG, "Ignoring unknown session info.");
+ return;
+ }
- if (mRemoteCallback == null) {
- return;
- }
- try {
- mRemoteCallback.notifySessionReleased(sessionInfo);
- } catch (RemoteException ex) {
- Log.w(TAG, "Failed to notify session info changed.");
+ if (mRemoteCallback == null) {
+ return;
+ }
+ try {
+ mRemoteCallback.notifySessionReleased(sessionInfo);
+ } catch (RemoteException ex) {
+ Log.w(TAG, "Failed to notify session info changed.");
+ }
}
}
@@ -349,9 +345,9 @@ public abstract class MediaRoute2ProviderService extends Service {
* If you can't create the session or want to reject the request, call
* {@link #notifyRequestFailed(long, int)} with the given {@code requestId}.
*
- * @param requestId the id of this request
+ * @param requestId the ID of this request
* @param packageName the package name of the application that selected the route
- * @param routeId the id of the route initially being connected
+ * @param routeId the ID of the route initially being connected
* @param sessionHints an optional bundle of app-specific arguments sent by
* {@link MediaRouter2}, or null if none. The contents of this bundle
* may affect the result of session creation.
@@ -373,8 +369,8 @@ public abstract class MediaRoute2ProviderService extends Service {
* Note: Calling {@link #notifySessionReleased(String)} will <em>NOT</em> trigger
* this method to be called.
*
- * @param requestId the id of this request
- * @param sessionId id of the session being released.
+ * @param requestId the ID of this request
+ * @param sessionId the ID of the session being released.
* @see #notifySessionReleased(String)
* @see #getSessionInfo(String)
*/
@@ -385,9 +381,9 @@ public abstract class MediaRoute2ProviderService extends Service {
* After the route is selected, call {@link #notifySessionUpdated(RoutingSessionInfo)}
* to update session info.
*
- * @param requestId the id of this request
- * @param sessionId id of the session
- * @param routeId id of the route
+ * @param requestId the ID of this request
+ * @param sessionId the ID of the session
+ * @param routeId the ID of the route
*/
public abstract void onSelectRoute(long requestId, @NonNull String sessionId,
@NonNull String routeId);
@@ -397,9 +393,9 @@ public abstract class MediaRoute2ProviderService extends Service {
* After the route is deselected, call {@link #notifySessionUpdated(RoutingSessionInfo)}
* to update session info.
*
- * @param requestId the id of this request
- * @param sessionId id of the session
- * @param routeId id of the route
+ * @param requestId the ID of this request
+ * @param sessionId the ID of the session
+ * @param routeId the ID of the route
*/
public abstract void onDeselectRoute(long requestId, @NonNull String sessionId,
@NonNull String routeId);
@@ -409,9 +405,9 @@ public abstract class MediaRoute2ProviderService extends Service {
* After the transfer is finished, call {@link #notifySessionUpdated(RoutingSessionInfo)}
* to update session info.
*
- * @param requestId the id of this request
- * @param sessionId id of the session
- * @param routeId id of the route
+ * @param requestId the ID of this request
+ * @param sessionId the ID of the session
+ * @param routeId the ID of the route
*/
public abstract void onTransferToRoute(long requestId, @NonNull String sessionId,
@NonNull String routeId);
@@ -476,13 +472,39 @@ public abstract class MediaRoute2ProviderService extends Service {
final class MediaRoute2ProviderServiceStub extends IMediaRoute2ProviderService.Stub {
MediaRoute2ProviderServiceStub() { }
- boolean checkCallerisSystem() {
+ private boolean checkCallerIsSystem() {
return Binder.getCallingUid() == Process.SYSTEM_UID;
}
+ private boolean checkSessionIdIsValid(String sessionId, String description) {
+ if (TextUtils.isEmpty(sessionId)) {
+ Log.w(TAG, description + ": Ignoring empty sessionId from system service.");
+ return false;
+ }
+ if (getSessionInfo(sessionId) == null) {
+ Log.w(TAG, description + ": Ignoring unknown session from system service. "
+ + "sessionId=" + sessionId);
+ return false;
+ }
+ return true;
+ }
+
+ private boolean checkRouteIdIsValid(String routeId, String description) {
+ if (TextUtils.isEmpty(routeId)) {
+ Log.w(TAG, description + ": Ignoring empty routeId from system service.");
+ return false;
+ }
+ if (mProviderInfo == null || mProviderInfo.getRoute(routeId) == null) {
+ Log.w(TAG, description + ": Ignoring unknown route from system service. "
+ + "routeId=" + routeId);
+ return false;
+ }
+ return true;
+ }
+
@Override
public void setCallback(IMediaRoute2ProviderServiceCallback callback) {
- if (!checkCallerisSystem()) {
+ if (!checkCallerIsSystem()) {
return;
}
mHandler.sendMessage(obtainMessage(MediaRoute2ProviderService::setCallback,
@@ -491,7 +513,7 @@ public abstract class MediaRoute2ProviderService extends Service {
@Override
public void updateDiscoveryPreference(RouteDiscoveryPreference discoveryPreference) {
- if (!checkCallerisSystem()) {
+ if (!checkCallerIsSystem()) {
return;
}
mHandler.sendMessage(obtainMessage(
@@ -501,7 +523,10 @@ public abstract class MediaRoute2ProviderService extends Service {
@Override
public void setRouteVolume(long requestId, String routeId, int volume) {
- if (!checkCallerisSystem()) {
+ if (!checkCallerIsSystem()) {
+ return;
+ }
+ if (!checkRouteIdIsValid(routeId, "setRouteVolume")) {
return;
}
mHandler.sendMessage(obtainMessage(MediaRoute2ProviderService::onSetRouteVolume,
@@ -511,7 +536,10 @@ public abstract class MediaRoute2ProviderService extends Service {
@Override
public void requestCreateSession(long requestId, String packageName, String routeId,
@Nullable Bundle requestCreateSession) {
- if (!checkCallerisSystem()) {
+ if (!checkCallerIsSystem()) {
+ return;
+ }
+ if (!checkRouteIdIsValid(routeId, "requestCreateSession")) {
return;
}
mHandler.sendMessage(obtainMessage(MediaRoute2ProviderService::onCreateSession,
@@ -519,14 +547,13 @@ public abstract class MediaRoute2ProviderService extends Service {
requestCreateSession));
}
- //TODO: Ignore requests with unknown session ID.
@Override
public void selectRoute(long requestId, String sessionId, String routeId) {
- if (!checkCallerisSystem()) {
+ if (!checkCallerIsSystem()) {
return;
}
- if (TextUtils.isEmpty(sessionId)) {
- Log.w(TAG, "selectRoute: Ignoring empty sessionId from system service.");
+ if (!checkSessionIdIsValid(sessionId, "selectRoute")
+ || !checkRouteIdIsValid(routeId, "selectRoute")) {
return;
}
mHandler.sendMessage(obtainMessage(MediaRoute2ProviderService::onSelectRoute,
@@ -535,11 +562,11 @@ public abstract class MediaRoute2ProviderService extends Service {
@Override
public void deselectRoute(long requestId, String sessionId, String routeId) {
- if (!checkCallerisSystem()) {
+ if (!checkCallerIsSystem()) {
return;
}
- if (TextUtils.isEmpty(sessionId)) {
- Log.w(TAG, "deselectRoute: Ignoring empty sessionId from system service.");
+ if (!checkSessionIdIsValid(sessionId, "deselectRoute")
+ || !checkRouteIdIsValid(routeId, "deselectRoute")) {
return;
}
mHandler.sendMessage(obtainMessage(MediaRoute2ProviderService::onDeselectRoute,
@@ -548,11 +575,11 @@ public abstract class MediaRoute2ProviderService extends Service {
@Override
public void transferToRoute(long requestId, String sessionId, String routeId) {
- if (!checkCallerisSystem()) {
+ if (!checkCallerIsSystem()) {
return;
}
- if (TextUtils.isEmpty(sessionId)) {
- Log.w(TAG, "transferToRoute: Ignoring empty sessionId from system service.");
+ if (!checkSessionIdIsValid(sessionId, "transferToRoute")
+ || !checkRouteIdIsValid(routeId, "transferToRoute")) {
return;
}
mHandler.sendMessage(obtainMessage(MediaRoute2ProviderService::onTransferToRoute,
@@ -561,7 +588,10 @@ public abstract class MediaRoute2ProviderService extends Service {
@Override
public void setSessionVolume(long requestId, String sessionId, int volume) {
- if (!checkCallerisSystem()) {
+ if (!checkCallerIsSystem()) {
+ return;
+ }
+ if (!checkSessionIdIsValid(sessionId, "setSessionVolume")) {
return;
}
mHandler.sendMessage(obtainMessage(MediaRoute2ProviderService::onSetSessionVolume,
@@ -570,11 +600,10 @@ public abstract class MediaRoute2ProviderService extends Service {
@Override
public void releaseSession(long requestId, String sessionId) {
- if (!checkCallerisSystem()) {
+ if (!checkCallerIsSystem()) {
return;
}
- if (TextUtils.isEmpty(sessionId)) {
- Log.w(TAG, "releaseSession: Ignoring empty sessionId from system service.");
+ if (!checkSessionIdIsValid(sessionId, "releaseSession")) {
return;
}
mHandler.sendMessage(obtainMessage(MediaRoute2ProviderService::onReleaseSession,
diff --git a/media/java/android/media/MediaRouter2.java b/media/java/android/media/MediaRouter2.java
index 6179b483ca53..e767c68f13ac 100644
--- a/media/java/android/media/MediaRouter2.java
+++ b/media/java/android/media/MediaRouter2.java
@@ -54,7 +54,7 @@ import java.util.stream.Collectors;
* Media Router 2 allows applications to control the routing of media channels
* and streams from the current device to remote speakers and devices.
*/
-// TODO: Add method names at the beginning of log messages. (e.g. updateControllerOnHandler)
+// TODO(b/157873330): Add method names at the beginning of log messages. (e.g. selectRoute)
// Not only MediaRouter2, but also to service / manager / provider.
// TODO: ensure thread-safe and document it
public final class MediaRouter2 {
@@ -92,7 +92,7 @@ public final class MediaRouter2 {
MediaRouter2Stub mStub;
@GuardedBy("sRouterLock")
- private final Map<String, RoutingController> mRoutingControllers = new ArrayMap<>();
+ private final Map<String, RoutingController> mNonSystemRoutingControllers = new ArrayMap<>();
private final AtomicInteger mControllerCreationRequestCnt = new AtomicInteger(1);
@@ -230,7 +230,7 @@ public final class MediaRouter2 {
Log.e(TAG, "unregisterRouteCallback: Unable to set discovery request.");
}
}
- if (mRouteCallbackRecords.size() == 0) {
+ if (mRouteCallbackRecords.isEmpty() && mNonSystemRoutingControllers.isEmpty()) {
try {
mMediaRouterService.unregisterRouter2(mStub);
} catch (RemoteException ex) {
@@ -399,11 +399,16 @@ public final class MediaRouter2 {
Objects.requireNonNull(controller, "controller must not be null");
Objects.requireNonNull(route, "route must not be null");
- // TODO: Check thread-safety
- if (!mRoutes.containsKey(route.getId())) {
+ boolean routeFound;
+ synchronized (sRouterLock) {
+ // TODO: Check thread-safety
+ routeFound = mRoutes.containsKey(route.getId());
+ }
+ if (!routeFound) {
notifyTransferFailure(route);
return;
}
+
if (controller.getRoutingSessionInfo().getTransferableRoutes().contains(route.getId())) {
controller.transferToRoute(route);
return;
@@ -470,7 +475,7 @@ public final class MediaRouter2 {
List<RoutingController> result = new ArrayList<>();
result.add(0, mSystemController);
synchronized (sRouterLock) {
- result.addAll(mRoutingControllers.values());
+ result.addAll(mNonSystemRoutingControllers.values());
}
return result;
}
@@ -500,11 +505,78 @@ public final class MediaRouter2 {
}
}
+ void syncRoutesOnHandler(List<MediaRoute2Info> currentRoutes,
+ RoutingSessionInfo currentSystemSessionInfo) {
+ if (currentRoutes == null || currentRoutes.isEmpty() || currentSystemSessionInfo == null) {
+ Log.e(TAG, "syncRoutesOnHandler: Received wrong data. currentRoutes=" + currentRoutes
+ + ", currentSystemSessionInfo=" + currentSystemSessionInfo);
+ return;
+ }
+
+ List<MediaRoute2Info> addedRoutes = new ArrayList<>();
+ List<MediaRoute2Info> removedRoutes = new ArrayList<>();
+ List<MediaRoute2Info> changedRoutes = new ArrayList<>();
+
+ synchronized (sRouterLock) {
+ List<String> currentRoutesIds = currentRoutes.stream().map(MediaRoute2Info::getId)
+ .collect(Collectors.toList());
+
+ for (String routeId : mRoutes.keySet()) {
+ if (!currentRoutesIds.contains(routeId)) {
+ // This route is removed while the callback is unregistered.
+ MediaRoute2Info route = mRoutes.get(routeId);
+ if (route.isSystemRoute()
+ || route.hasAnyFeatures(mDiscoveryPreference.getPreferredFeatures())) {
+ removedRoutes.add(mRoutes.get(routeId));
+ }
+ }
+ }
+
+ for (MediaRoute2Info route : currentRoutes) {
+ if (mRoutes.containsKey(route.getId())) {
+ if (!route.equals(mRoutes.get(route.getId()))) {
+ // This route is changed while the callback is unregistered.
+ if (route.isSystemRoute()
+ || route.hasAnyFeatures(
+ mDiscoveryPreference.getPreferredFeatures())) {
+ changedRoutes.add(route);
+ }
+ }
+ } else {
+ // This route is added while the callback is unregistered.
+ if (route.isSystemRoute()
+ || route.hasAnyFeatures(mDiscoveryPreference.getPreferredFeatures())) {
+ addedRoutes.add(route);
+ }
+ }
+ }
+
+ mRoutes.clear();
+ for (MediaRoute2Info route : currentRoutes) {
+ mRoutes.put(route.getId(), route);
+ }
+
+ mShouldUpdateRoutes = true;
+ }
+
+ if (addedRoutes.size() > 0) {
+ notifyRoutesAdded(addedRoutes);
+ }
+ if (removedRoutes.size() > 0) {
+ notifyRoutesRemoved(removedRoutes);
+ }
+ if (changedRoutes.size() > 0) {
+ notifyRoutesChanged(changedRoutes);
+ }
+
+ RoutingSessionInfo oldInfo = mSystemController.getRoutingSessionInfo();
+ mSystemController.setRoutingSessionInfo(currentSystemSessionInfo);
+ if (!oldInfo.equals(currentSystemSessionInfo)) {
+ notifyControllerUpdated(mSystemController);
+ }
+ }
+
void addRoutesOnHandler(List<MediaRoute2Info> routes) {
- // TODO: When onRoutesAdded is first called,
- // 1) clear mRoutes before adding the routes
- // 2) Call onRouteSelected(system_route, reason_fallback) if previously selected route
- // does not exist anymore. => We may need 'boolean MediaRoute2Info#isSystemRoute()'.
List<MediaRoute2Info> addedRoutes = new ArrayList<>();
synchronized (sRouterLock) {
for (MediaRoute2Info route : routes) {
@@ -617,7 +689,7 @@ public final class MediaRouter2 {
} else {
newController = new RoutingController(sessionInfo);
synchronized (sRouterLock) {
- mRoutingControllers.put(newController.getId(), newController);
+ mNonSystemRoutingControllers.put(newController.getId(), newController);
}
}
@@ -645,7 +717,7 @@ public final class MediaRouter2 {
RoutingController matchingController;
synchronized (sRouterLock) {
- matchingController = mRoutingControllers.get(sessionInfo.getId());
+ matchingController = mNonSystemRoutingControllers.get(sessionInfo.getId());
}
if (matchingController == null) {
@@ -674,7 +746,7 @@ public final class MediaRouter2 {
final String uniqueSessionId = sessionInfo.getId();
RoutingController matchingController;
synchronized (sRouterLock) {
- matchingController = mRoutingControllers.get(uniqueSessionId);
+ matchingController = mNonSystemRoutingControllers.get(uniqueSessionId);
}
if (matchingController == null) {
@@ -1214,7 +1286,7 @@ public final class MediaRouter2 {
* Any operations on this controller after calling this method will be ignored.
* The devices that are playing media will stop playing it.
*/
- // TODO: Add tests using {@link MediaRouter2Manager#getActiveSessions()}.
+ // TODO(b/157872573): Add tests using {@link MediaRouter2Manager#getActiveSessions()}.
public void release() {
releaseInternal(/* shouldReleaseSession= */ true, /* shouldNotifyStop= */ true);
}
@@ -1232,23 +1304,34 @@ public final class MediaRouter2 {
mIsReleased = true;
}
- MediaRouter2Stub stub;
synchronized (sRouterLock) {
- mRoutingControllers.remove(getId(), this);
- stub = mStub;
- }
+ if (!mNonSystemRoutingControllers.remove(getId(), this)) {
+ Log.w(TAG, "releaseInternal: Ignoring unknown controller.");
+ return false;
+ }
- if (shouldReleaseSession && stub != null) {
- try {
- mMediaRouterService.releaseSessionWithRouter2(stub, getId());
- } catch (RemoteException ex) {
- Log.e(TAG, "Unable to release session", ex);
+ if (shouldReleaseSession && mStub != null) {
+ try {
+ mMediaRouterService.releaseSessionWithRouter2(mStub, getId());
+ } catch (RemoteException ex) {
+ Log.e(TAG, "Unable to release session", ex);
+ }
}
- }
- if (shouldNotifyStop) {
- mHandler.sendMessage(obtainMessage(MediaRouter2::notifyStop, MediaRouter2.this,
- RoutingController.this));
+ if (shouldNotifyStop) {
+ mHandler.sendMessage(obtainMessage(MediaRouter2::notifyStop, MediaRouter2.this,
+ RoutingController.this));
+ }
+
+ if (mRouteCallbackRecords.isEmpty() && mNonSystemRoutingControllers.isEmpty()
+ && mStub != null) {
+ try {
+ mMediaRouterService.unregisterRouter2(mStub);
+ } catch (RemoteException ex) {
+ Log.e(TAG, "releaseInternal: Unable to unregister media router.", ex);
+ }
+ mStub = null;
+ }
}
return true;
}
@@ -1415,6 +1498,13 @@ public final class MediaRouter2 {
class MediaRouter2Stub extends IMediaRouter2.Stub {
@Override
+ public void notifyRouterRegistered(List<MediaRoute2Info> currentRoutes,
+ RoutingSessionInfo currentSystemSessionInfo) {
+ mHandler.sendMessage(obtainMessage(MediaRouter2::syncRoutesOnHandler,
+ MediaRouter2.this, currentRoutes, currentSystemSessionInfo));
+ }
+
+ @Override
public void notifyRoutesAdded(List<MediaRoute2Info> routes) {
mHandler.sendMessage(obtainMessage(MediaRouter2::addRoutesOnHandler,
MediaRouter2.this, routes));
diff --git a/media/java/android/media/MediaRouter2Manager.java b/media/java/android/media/MediaRouter2Manager.java
index 4ebfce830a70..1c2d581b733d 100644
--- a/media/java/android/media/MediaRouter2Manager.java
+++ b/media/java/android/media/MediaRouter2Manager.java
@@ -25,12 +25,14 @@ import android.content.Context;
import android.media.session.MediaController;
import android.media.session.MediaSessionManager;
import android.os.Handler;
+import android.os.Message;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.text.TextUtils;
import android.util.Log;
import com.android.internal.annotations.GuardedBy;
+import com.android.internal.annotations.VisibleForTesting;
import java.util.ArrayList;
import java.util.Collections;
@@ -52,6 +54,9 @@ import java.util.stream.Collectors;
public final class MediaRouter2Manager {
private static final String TAG = "MR2Manager";
private static final Object sLock = new Object();
+ /** @hide */
+ @VisibleForTesting
+ public static final int TRANSFER_TIMEOUT_MS = 30_000;
@GuardedBy("sLock")
private static MediaRouter2Manager sInstance;
@@ -151,8 +156,6 @@ public final class MediaRouter2Manager {
return null;
}
- //TODO: Use cache not to create array. For now, it's unclear when to purge the cache.
- //Do this when we finalize how to set control categories.
/**
* Gets available routes for an application.
*
@@ -339,30 +342,18 @@ public final class MediaRouter2Manager {
Objects.requireNonNull(sessionInfo, "sessionInfo must not be null");
Objects.requireNonNull(route, "route must not be null");
- //TODO: Ignore unknown route.
- if (sessionInfo.getTransferableRoutes().contains(route.getId())) {
- transferToRoute(sessionInfo, route);
- return;
- }
-
- if (TextUtils.isEmpty(sessionInfo.getClientPackageName())) {
- Log.w(TAG, "transfer: Ignoring transfer without package name.");
- notifyTransferFailed(sessionInfo, route);
- return;
+ synchronized (mRoutesLock) {
+ if (!mRoutes.containsKey(route.getId())) {
+ Log.w(TAG, "transfer: Ignoring an unknown route id=" + route.getId());
+ notifyTransferFailed(sessionInfo, route);
+ return;
+ }
}
- Client client = getOrCreateClient();
- if (client != null) {
- try {
- int requestId = mNextRequestId.getAndIncrement();
- //TODO: Ensure that every request is eventually removed.
- mTransferRequests.add(new TransferRequest(requestId, sessionInfo, route));
-
- mMediaRouterService.requestCreateSessionWithManager(
- client, requestId, sessionInfo.getClientPackageName(), route);
- } catch (RemoteException ex) {
- Log.e(TAG, "Unable to select media route", ex);
- }
+ if (sessionInfo.getTransferableRoutes().contains(route.getId())) {
+ transferToRoute(sessionInfo, route);
+ } else {
+ requestCreateSession(sessionInfo, route);
}
}
@@ -518,15 +509,15 @@ public final class MediaRouter2Manager {
notifyRequestFailed(reason);
}
- void handleSessionsUpdated(RoutingSessionInfo sessionInfo) {
+ void handleSessionsUpdatedOnHandler(RoutingSessionInfo sessionInfo) {
for (TransferRequest request : mTransferRequests) {
String sessionId = request.mOldSessionInfo.getId();
if (!TextUtils.equals(sessionId, sessionInfo.getId())) {
continue;
}
if (sessionInfo.getSelectedRoutes().contains(request.mTargetRoute.getId())) {
- notifyTransferred(request.mOldSessionInfo, sessionInfo);
mTransferRequests.remove(request);
+ notifyTransferred(request.mOldSessionInfo, sessionInfo);
break;
}
}
@@ -560,6 +551,12 @@ public final class MediaRouter2Manager {
}
}
+ void notifySessionReleased(RoutingSessionInfo session) {
+ for (CallbackRecord record : mCallbackRecords) {
+ record.mExecutor.execute(() -> record.mCallback.onSessionReleased(session));
+ }
+ }
+
void notifyRequestFailed(int reason) {
for (CallbackRecord record : mCallbackRecords) {
record.mExecutor.execute(() -> record.mCallback.onRequestFailed(reason));
@@ -597,7 +594,7 @@ public final class MediaRouter2Manager {
public List<MediaRoute2Info> getSelectedRoutes(@NonNull RoutingSessionInfo sessionInfo) {
Objects.requireNonNull(sessionInfo, "sessionInfo must not be null");
- synchronized (sLock) {
+ synchronized (mRoutesLock) {
return sessionInfo.getSelectedRoutes().stream().map(mRoutes::get)
.filter(Objects::nonNull)
.collect(Collectors.toList());
@@ -613,7 +610,7 @@ public final class MediaRouter2Manager {
List<String> selectedRouteIds = sessionInfo.getSelectedRoutes();
- synchronized (sLock) {
+ synchronized (mRoutesLock) {
return sessionInfo.getSelectableRoutes().stream()
.filter(routeId -> !selectedRouteIds.contains(routeId))
.map(mRoutes::get)
@@ -631,7 +628,7 @@ public final class MediaRouter2Manager {
List<String> selectedRouteIds = sessionInfo.getSelectedRoutes();
- synchronized (sLock) {
+ synchronized (mRoutesLock) {
return sessionInfo.getDeselectableRoutes().stream()
.filter(routeId -> selectedRouteIds.contains(routeId))
.map(mRoutes::get)
@@ -727,65 +724,89 @@ public final class MediaRouter2Manager {
}
/**
- * Transfers to a given route for the remote session.
+ * Requests releasing a session.
+ * <p>
+ * If a session is released, any operation on the session will be ignored.
+ * {@link Callback#onTransferred(RoutingSessionInfo, RoutingSessionInfo)} with {@code null}
+ * session will be called when the session is released.
+ * </p>
*
- * @hide
+ * @see Callback#onTransferred(RoutingSessionInfo, RoutingSessionInfo)
*/
- void transferToRoute(@NonNull RoutingSessionInfo sessionInfo,
- @NonNull MediaRoute2Info route) {
+ public void releaseSession(@NonNull RoutingSessionInfo sessionInfo) {
Objects.requireNonNull(sessionInfo, "sessionInfo must not be null");
- Objects.requireNonNull(route, "route must not be null");
-
- if (sessionInfo.getSelectedRoutes().contains(route.getId())) {
- Log.w(TAG, "Ignoring transferring to a route that is already added. route="
- + route);
- return;
- }
- if (!sessionInfo.getTransferableRoutes().contains(route.getId())) {
- Log.w(TAG, "Ignoring transferring to a non-transferable route=" + route);
- return;
+ Client client = getOrCreateClient();
+ if (client != null) {
+ try {
+ int requestId = mNextRequestId.getAndIncrement();
+ mMediaRouterService.releaseSessionWithManager(
+ client, requestId, sessionInfo.getId());
+ } catch (RemoteException ex) {
+ Log.e(TAG, "releaseSession: Failed to send a request", ex);
+ }
}
+ }
- int requestId = mNextRequestId.getAndIncrement();
- mTransferRequests.add(new TransferRequest(requestId, sessionInfo, route));
+ /**
+ * Transfers the remote session to the given route.
+ *
+ * @hide
+ */
+ private void transferToRoute(@NonNull RoutingSessionInfo session,
+ @NonNull MediaRoute2Info route) {
+ int requestId = createTransferRequest(session, route);
Client client = getOrCreateClient();
if (client != null) {
try {
mMediaRouterService.transferToRouteWithManager(
- client, requestId, sessionInfo.getId(), route);
+ client, requestId, session.getId(), route);
} catch (RemoteException ex) {
Log.e(TAG, "transferToRoute: Failed to send a request.", ex);
}
}
}
- /**
- * Requests releasing a session.
- * <p>
- * If a session is released, any operation on the session will be ignored.
- * {@link Callback#onTransferred(RoutingSessionInfo, RoutingSessionInfo)} with {@code null}
- * session will be called when the session is released.
- * </p>
- *
- * @see Callback#onTransferred(RoutingSessionInfo, RoutingSessionInfo)
- */
- public void releaseSession(@NonNull RoutingSessionInfo sessionInfo) {
- Objects.requireNonNull(sessionInfo, "sessionInfo must not be null");
+ private void requestCreateSession(RoutingSessionInfo oldSession, MediaRoute2Info route) {
+ if (TextUtils.isEmpty(oldSession.getClientPackageName())) {
+ Log.w(TAG, "requestCreateSession: Can't create a session without package name.");
+ notifyTransferFailed(oldSession, route);
+ return;
+ }
+
+ int requestId = createTransferRequest(oldSession, route);
Client client = getOrCreateClient();
if (client != null) {
try {
- int requestId = mNextRequestId.getAndIncrement();
- mMediaRouterService.releaseSessionWithManager(
- client, requestId, sessionInfo.getId());
+ mMediaRouterService.requestCreateSessionWithManager(
+ client, requestId, oldSession.getClientPackageName(), route);
} catch (RemoteException ex) {
- Log.e(TAG, "releaseSession: Failed to send a request", ex);
+ Log.e(TAG, "requestCreateSession: Failed to send a request", ex);
}
}
}
+ private int createTransferRequest(RoutingSessionInfo session, MediaRoute2Info route) {
+ int requestId = mNextRequestId.getAndIncrement();
+ TransferRequest transferRequest = new TransferRequest(requestId, session, route);
+ mTransferRequests.add(transferRequest);
+
+ Message timeoutMessage =
+ obtainMessage(MediaRouter2Manager::handleTransferTimeout, this, transferRequest);
+ mHandler.sendMessageDelayed(timeoutMessage, TRANSFER_TIMEOUT_MS);
+ return requestId;
+ }
+
+ private void handleTransferTimeout(TransferRequest request) {
+ boolean removed = mTransferRequests.remove(request);
+ if (removed) {
+ notifyTransferFailed(request.mOldSessionInfo, request.mTargetRoute);
+ }
+ }
+
+
private boolean areSessionsMatched(MediaController mediaController,
RoutingSessionInfo sessionInfo) {
MediaController.PlaybackInfo playbackInfo = mediaController.getPlaybackInfo();
@@ -849,9 +870,16 @@ public final class MediaRouter2Manager {
/**
* Called when a session is changed.
- * @param sessionInfo the updated session
+ * @param session the updated session
*/
- public void onSessionUpdated(@NonNull RoutingSessionInfo sessionInfo) {}
+ public void onSessionUpdated(@NonNull RoutingSessionInfo session) {}
+
+ /**
+ * Called when a session is released.
+ * @param session the released session.
+ * @see #releaseSession(RoutingSessionInfo)
+ */
+ public void onSessionReleased(@NonNull RoutingSessionInfo session) {}
/**
* Called when media is transferred.
@@ -907,7 +935,7 @@ public final class MediaRouter2Manager {
if (!(obj instanceof CallbackRecord)) {
return false;
}
- return mCallback == ((CallbackRecord) obj).mCallback;
+ return mCallback == ((CallbackRecord) obj).mCallback;
}
@Override
@@ -931,15 +959,21 @@ public final class MediaRouter2Manager {
class Client extends IMediaRouter2Manager.Stub {
@Override
- public void notifySessionCreated(int requestId, RoutingSessionInfo sessionInfo) {
+ public void notifySessionCreated(int requestId, RoutingSessionInfo session) {
mHandler.sendMessage(obtainMessage(MediaRouter2Manager::createSessionOnHandler,
- MediaRouter2Manager.this, requestId, sessionInfo));
+ MediaRouter2Manager.this, requestId, session));
+ }
+
+ @Override
+ public void notifySessionUpdated(RoutingSessionInfo session) {
+ mHandler.sendMessage(obtainMessage(MediaRouter2Manager::handleSessionsUpdatedOnHandler,
+ MediaRouter2Manager.this, session));
}
@Override
- public void notifySessionUpdated(RoutingSessionInfo sessionInfo) {
- mHandler.sendMessage(obtainMessage(MediaRouter2Manager::handleSessionsUpdated,
- MediaRouter2Manager.this, sessionInfo));
+ public void notifySessionReleased(RoutingSessionInfo session) {
+ mHandler.sendMessage(obtainMessage(MediaRouter2Manager::notifySessionReleased,
+ MediaRouter2Manager.this, session));
}
@Override
diff --git a/media/java/android/media/SoundPool.java b/media/java/android/media/SoundPool.java
index 26e65dda5ebf..1bf2863989a5 100644
--- a/media/java/android/media/SoundPool.java
+++ b/media/java/android/media/SoundPool.java
@@ -16,28 +16,22 @@
package android.media;
-import java.io.File;
-import java.io.FileDescriptor;
-import java.lang.ref.WeakReference;
-
import android.annotation.NonNull;
import android.annotation.Nullable;
-import android.app.ActivityThread;
-import android.app.AppOpsManager;
import android.content.Context;
import android.content.res.AssetFileDescriptor;
-import android.media.PlayerBase;
import android.os.Handler;
-import android.os.IBinder;
import android.os.Looper;
import android.os.Message;
import android.os.ParcelFileDescriptor;
-import android.os.Process;
-import android.os.RemoteException;
-import android.os.ServiceManager;
import android.util.AndroidRuntimeException;
import android.util.Log;
+import java.io.File;
+import java.io.FileDescriptor;
+import java.lang.ref.WeakReference;
+import java.util.concurrent.atomic.AtomicReference;
+
/**
* The SoundPool class manages and plays audio resources for applications.
@@ -122,13 +116,12 @@ public class SoundPool extends PlayerBase {
private final static String TAG = "SoundPool";
private final static boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
+ private final AtomicReference<EventHandler> mEventHandler = new AtomicReference<>(null);
+
private long mNativeContext; // accessed by native methods
- private EventHandler mEventHandler;
- private SoundPool.OnLoadCompleteListener mOnLoadCompleteListener;
private boolean mHasAppOpsPlayAudio;
- private final Object mLock;
private final AudioAttributes mAttributes;
/**
@@ -159,7 +152,6 @@ public class SoundPool extends PlayerBase {
if (native_setup(new WeakReference<SoundPool>(this), maxStreams, attributes) != 0) {
throw new RuntimeException("Native setup failed");
}
- mLock = new Object();
mAttributes = attributes;
baseRegisterPlayer();
@@ -491,21 +483,18 @@ public class SoundPool extends PlayerBase {
* Sets the callback hook for the OnLoadCompleteListener.
*/
public void setOnLoadCompleteListener(OnLoadCompleteListener listener) {
- synchronized(mLock) {
- if (listener != null) {
- // setup message handler
- Looper looper;
- if ((looper = Looper.myLooper()) != null) {
- mEventHandler = new EventHandler(looper);
- } else if ((looper = Looper.getMainLooper()) != null) {
- mEventHandler = new EventHandler(looper);
- } else {
- mEventHandler = null;
- }
- } else {
- mEventHandler = null;
- }
- mOnLoadCompleteListener = listener;
+ if (listener == null) {
+ mEventHandler.set(null);
+ return;
+ }
+
+ Looper looper;
+ if ((looper = Looper.myLooper()) != null) {
+ mEventHandler.set(new EventHandler(looper, listener));
+ } else if ((looper = Looper.getMainLooper()) != null) {
+ mEventHandler.set(new EventHandler(looper, listener));
+ } else {
+ mEventHandler.set(null);
}
}
@@ -525,35 +514,36 @@ public class SoundPool extends PlayerBase {
@SuppressWarnings("unchecked")
private static void postEventFromNative(Object ref, int msg, int arg1, int arg2, Object obj) {
SoundPool soundPool = ((WeakReference<SoundPool>) ref).get();
- if (soundPool == null)
+ if (soundPool == null) {
return;
+ }
- if (soundPool.mEventHandler != null) {
- Message m = soundPool.mEventHandler.obtainMessage(msg, arg1, arg2, obj);
- soundPool.mEventHandler.sendMessage(m);
+ Handler eventHandler = soundPool.mEventHandler.get();
+ if (eventHandler == null) {
+ return;
}
+
+ Message message = eventHandler.obtainMessage(msg, arg1, arg2, obj);
+ eventHandler.sendMessage(message);
}
private final class EventHandler extends Handler {
- public EventHandler(Looper looper) {
+ private final OnLoadCompleteListener mOnLoadCompleteListener;
+
+ EventHandler(Looper looper, @NonNull OnLoadCompleteListener onLoadCompleteListener) {
super(looper);
+ mOnLoadCompleteListener = onLoadCompleteListener;
}
@Override
public void handleMessage(Message msg) {
- switch(msg.what) {
- case SAMPLE_LOADED:
- if (DEBUG) Log.d(TAG, "Sample " + msg.arg1 + " loaded");
- synchronized(mLock) {
- if (mOnLoadCompleteListener != null) {
- mOnLoadCompleteListener.onLoadComplete(SoundPool.this, msg.arg1, msg.arg2);
- }
- }
- break;
- default:
+ if (msg.what != SAMPLE_LOADED) {
Log.e(TAG, "Unknown message type " + msg.what);
return;
}
+
+ if (DEBUG) Log.d(TAG, "Sample " + msg.arg1 + " loaded");
+ mOnLoadCompleteListener.onLoadComplete(SoundPool.this, msg.arg1, msg.arg2);
}
}
diff --git a/media/java/android/media/projection/MediaProjectionManager.java b/media/java/android/media/projection/MediaProjectionManager.java
index c4d27eca02f8..e719b2a04720 100644
--- a/media/java/android/media/projection/MediaProjectionManager.java
+++ b/media/java/android/media/projection/MediaProjectionManager.java
@@ -90,6 +90,17 @@ public final class MediaProjectionManager {
* projection is stopped. This allows for user controls to be displayed on top of the screen
* being captured.
*
+ * <p>
+ * Apps targeting SDK version {@link android.os.Build.VERSION_CODES#Q} or later should specify
+ * the foreground service type using the attribute {@link android.R.attr#foregroundServiceType}
+ * in the service element of the app's manifest file.
+ * The {@link android.content.pm.ServiceInfo#FOREGROUND_SERVICE_TYPE_MEDIA_PROJECTION} attribute
+ * should be specified.
+ * </p>
+ *
+ * @see <a href="https://developer.android.com/preview/privacy/foreground-service-types">
+ * Foregroud Service Types</a>
+ *
* @param resultCode The result code from {@link android.app.Activity#onActivityResult(int,
* int, android.content.Intent)}
* @param resultData The resulting data from {@link android.app.Activity#onActivityResult(int,
diff --git a/media/java/android/media/soundtrigger_middleware/RecognitionEvent.aidl b/media/java/android/media/soundtrigger_middleware/RecognitionEvent.aidl
index de4d060ce484..a237ec1aa3b3 100644
--- a/media/java/android/media/soundtrigger_middleware/RecognitionEvent.aidl
+++ b/media/java/android/media/soundtrigger_middleware/RecognitionEvent.aidl
@@ -43,9 +43,9 @@ parcelable RecognitionEvent {
boolean triggerInData;
/**
* Audio format of either the trigger in event data or to use for capture of the rest of the
- * utterance.
+ * utterance. May be null when no audio is available for this event type.
*/
- AudioConfig audioConfig;
+ @nullable AudioConfig audioConfig;
/** Additional data. */
byte[] data;
}
diff --git a/media/java/android/media/tv/TvRecordingClient.java b/media/java/android/media/tv/TvRecordingClient.java
index 8ae98ae5e937..23fadac8a72b 100644
--- a/media/java/android/media/tv/TvRecordingClient.java
+++ b/media/java/android/media/tv/TvRecordingClient.java
@@ -146,6 +146,8 @@ public class TvRecordingClient {
mPendingAppPrivateCommands.clear();
if (mSession != null) {
mSession.release();
+ mIsTuned = false;
+ mIsRecordingStarted = false;
mSession = null;
}
}
diff --git a/media/java/android/media/tv/tuner/dvr/DvrPlayback.java b/media/java/android/media/tv/tuner/dvr/DvrPlayback.java
index 68071b0b0fe3..bb00bb3b8d56 100644
--- a/media/java/android/media/tv/tuner/dvr/DvrPlayback.java
+++ b/media/java/android/media/tv/tuner/dvr/DvrPlayback.java
@@ -20,12 +20,16 @@ import android.annotation.BytesLong;
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.SystemApi;
+import android.app.ActivityManager;
import android.hardware.tv.tuner.V1_0.Constants;
import android.media.tv.tuner.Tuner;
import android.media.tv.tuner.Tuner.Result;
import android.media.tv.tuner.TunerUtils;
import android.media.tv.tuner.filter.Filter;
import android.os.ParcelFileDescriptor;
+import android.util.Log;
+
+import com.android.internal.util.FrameworkStatsLog;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@@ -72,9 +76,15 @@ public class DvrPlayback implements AutoCloseable {
*/
public static final int PLAYBACK_STATUS_FULL = Constants.PlaybackStatus.SPACE_FULL;
+ private static final String TAG = "TvTunerPlayback";
+
private long mNativeContext;
private OnPlaybackStatusChangedListener mListener;
private Executor mExecutor;
+ private int mUserId;
+ private static int sInstantId = 0;
+ private int mSegmentId = 0;
+ private int mUnderflow;
private native int nativeAttachFilter(Filter filter);
private native int nativeDetachFilter(Filter filter);
@@ -88,6 +98,9 @@ public class DvrPlayback implements AutoCloseable {
private native long nativeRead(byte[] bytes, long offset, long size);
private DvrPlayback() {
+ mUserId = ActivityManager.getCurrentUser();
+ mSegmentId = (sInstantId & 0x0000ffff) << 16;
+ sInstantId++;
}
/** @hide */
@@ -98,6 +111,9 @@ public class DvrPlayback implements AutoCloseable {
}
private void onPlaybackStatusChanged(int status) {
+ if (status == PLAYBACK_STATUS_EMPTY) {
+ mUnderflow++;
+ }
if (mExecutor != null && mListener != null) {
mExecutor.execute(() -> mListener.onPlaybackStatusChanged(status));
}
@@ -154,6 +170,13 @@ public class DvrPlayback implements AutoCloseable {
*/
@Result
public int start() {
+ mSegmentId = (mSegmentId & 0xffff0000) | (((mSegmentId & 0x0000ffff) + 1) & 0x0000ffff);
+ mUnderflow = 0;
+ Log.d(TAG, "Write Stats Log for Playback.");
+ FrameworkStatsLog
+ .write(FrameworkStatsLog.TV_TUNER_DVR_STATUS, mUserId,
+ FrameworkStatsLog.TV_TUNER_DVR_STATUS__TYPE__PLAYBACK,
+ FrameworkStatsLog.TV_TUNER_DVR_STATUS__STATE__STARTED, mSegmentId, 0);
return nativeStartDvr();
}
@@ -167,6 +190,11 @@ public class DvrPlayback implements AutoCloseable {
*/
@Result
public int stop() {
+ Log.d(TAG, "Write Stats Log for Playback.");
+ FrameworkStatsLog
+ .write(FrameworkStatsLog.TV_TUNER_DVR_STATUS, mUserId,
+ FrameworkStatsLog.TV_TUNER_DVR_STATUS__TYPE__PLAYBACK,
+ FrameworkStatsLog.TV_TUNER_DVR_STATUS__STATE__STOPPED, mSegmentId, mUnderflow);
return nativeStopDvr();
}
diff --git a/media/java/android/media/tv/tuner/dvr/DvrRecorder.java b/media/java/android/media/tv/tuner/dvr/DvrRecorder.java
index 198bd0f4e78e..887116725961 100644
--- a/media/java/android/media/tv/tuner/dvr/DvrRecorder.java
+++ b/media/java/android/media/tv/tuner/dvr/DvrRecorder.java
@@ -19,14 +19,19 @@ package android.media.tv.tuner.dvr;
import android.annotation.BytesLong;
import android.annotation.NonNull;
import android.annotation.SystemApi;
+import android.app.ActivityManager;
import android.media.tv.tuner.Tuner;
import android.media.tv.tuner.Tuner.Result;
import android.media.tv.tuner.TunerUtils;
import android.media.tv.tuner.filter.Filter;
import android.os.ParcelFileDescriptor;
+import android.util.Log;
+
+import com.android.internal.util.FrameworkStatsLog;
import java.util.concurrent.Executor;
+
/**
* Digital Video Record (DVR) recorder class which provides record control on Demux's output buffer.
*
@@ -34,9 +39,14 @@ import java.util.concurrent.Executor;
*/
@SystemApi
public class DvrRecorder implements AutoCloseable {
+ private static final String TAG = "TvTunerRecord";
private long mNativeContext;
private OnRecordStatusChangedListener mListener;
private Executor mExecutor;
+ private int mUserId;
+ private static int sInstantId = 0;
+ private int mSegmentId = 0;
+ private int mOverflow;
private native int nativeAttachFilter(Filter filter);
private native int nativeDetachFilter(Filter filter);
@@ -50,6 +60,9 @@ public class DvrRecorder implements AutoCloseable {
private native long nativeWrite(byte[] bytes, long offset, long size);
private DvrRecorder() {
+ mUserId = ActivityManager.getCurrentUser();
+ mSegmentId = (sInstantId & 0x0000ffff) << 16;
+ sInstantId++;
}
/** @hide */
@@ -60,6 +73,9 @@ public class DvrRecorder implements AutoCloseable {
}
private void onRecordStatusChanged(int status) {
+ if (status == Filter.STATUS_OVERFLOW) {
+ mOverflow++;
+ }
if (mExecutor != null && mListener != null) {
mExecutor.execute(() -> mListener.onRecordStatusChanged(status));
}
@@ -112,6 +128,13 @@ public class DvrRecorder implements AutoCloseable {
*/
@Result
public int start() {
+ mSegmentId = (mSegmentId & 0xffff0000) | (((mSegmentId & 0x0000ffff) + 1) & 0x0000ffff);
+ mOverflow = 0;
+ Log.d(TAG, "Write Stats Log for Record.");
+ FrameworkStatsLog
+ .write(FrameworkStatsLog.TV_TUNER_DVR_STATUS, mUserId,
+ FrameworkStatsLog.TV_TUNER_DVR_STATUS__TYPE__RECORD,
+ FrameworkStatsLog.TV_TUNER_DVR_STATUS__STATE__STARTED, mSegmentId, 0);
return nativeStartDvr();
}
@@ -124,6 +147,11 @@ public class DvrRecorder implements AutoCloseable {
*/
@Result
public int stop() {
+ Log.d(TAG, "Write Stats Log for Playback.");
+ FrameworkStatsLog
+ .write(FrameworkStatsLog.TV_TUNER_DVR_STATUS, mUserId,
+ FrameworkStatsLog.TV_TUNER_DVR_STATUS__TYPE__RECORD,
+ FrameworkStatsLog.TV_TUNER_DVR_STATUS__STATE__STOPPED, mSegmentId, mOverflow);
return nativeStopDvr();
}
diff --git a/media/jni/android_media_MediaCodec.cpp b/media/jni/android_media_MediaCodec.cpp
index a03b24cbbcf6..f970b598d6f8 100644
--- a/media/jni/android_media_MediaCodec.cpp
+++ b/media/jni/android_media_MediaCodec.cpp
@@ -233,10 +233,12 @@ void JMediaCodec::release() {
}
void JMediaCodec::releaseAsync() {
- if (mCodec != NULL) {
- mCodec->releaseAsync();
- }
- mInitStatus = NO_INIT;
+ std::call_once(mAsyncReleaseFlag, [this] {
+ if (mCodec != NULL) {
+ mCodec->releaseAsync(new AMessage(kWhatAsyncReleaseComplete, this));
+ }
+ mInitStatus = NO_INIT;
+ });
}
JMediaCodec::~JMediaCodec() {
@@ -1084,6 +1086,12 @@ void JMediaCodec::onMessageReceived(const sp<AMessage> &msg) {
handleFrameRenderedNotification(msg);
break;
}
+ case kWhatAsyncReleaseComplete:
+ {
+ mCodec.clear();
+ mLooper->stop();
+ break;
+ }
default:
TRESPASS();
}
diff --git a/media/jni/android_media_MediaCodec.h b/media/jni/android_media_MediaCodec.h
index 5c34341a86a1..a58f9a74b563 100644
--- a/media/jni/android_media_MediaCodec.h
+++ b/media/jni/android_media_MediaCodec.h
@@ -173,6 +173,7 @@ private:
enum {
kWhatCallbackNotify,
kWhatFrameRendered,
+ kWhatAsyncReleaseComplete,
};
jclass mClass;
@@ -185,6 +186,7 @@ private:
bool mGraphicOutput{false};
bool mHasCryptoOrDescrambler{false};
std::once_flag mReleaseFlag;
+ std::once_flag mAsyncReleaseFlag;
sp<AMessage> mCallbackNotification;
sp<AMessage> mOnFrameRenderedNotification;
diff --git a/media/jni/soundpool/Sound.cpp b/media/jni/soundpool/Sound.cpp
index c3abdc22b19d..f8b4bdb1f4d5 100644
--- a/media/jni/soundpool/Sound.cpp
+++ b/media/jni/soundpool/Sound.cpp
@@ -31,7 +31,7 @@ constexpr size_t kDefaultHeapSize = 1024 * 1024; // 1MB (compatible with low m
Sound::Sound(int32_t soundID, int fd, int64_t offset, int64_t length)
: mSoundID(soundID)
- , mFd(fcntl(fd, F_DUPFD_CLOEXEC)) // like dup(fd) but closes on exec to prevent leaks.
+ , mFd(fcntl(fd, F_DUPFD_CLOEXEC, (int)0 /* arg */)) // dup(fd) + close on exec to prevent leaks.
, mOffset(offset)
, mLength(length)
{
diff --git a/media/tests/MediaRouter/src/com/android/mediaroutertest/MediaRouter2ManagerTest.java b/media/tests/MediaRouter/src/com/android/mediaroutertest/MediaRouter2ManagerTest.java
index c05c21cf2752..957558107de9 100644
--- a/media/tests/MediaRouter/src/com/android/mediaroutertest/MediaRouter2ManagerTest.java
+++ b/media/tests/MediaRouter/src/com/android/mediaroutertest/MediaRouter2ManagerTest.java
@@ -17,6 +17,7 @@
package com.android.mediaroutertest;
import static android.media.MediaRoute2Info.FEATURE_LIVE_AUDIO;
+import static android.media.MediaRoute2Info.FEATURE_REMOTE_PLAYBACK;
import static android.media.MediaRoute2Info.PLAYBACK_VOLUME_FIXED;
import static android.media.MediaRoute2Info.PLAYBACK_VOLUME_VARIABLE;
import static android.media.MediaRoute2ProviderService.REASON_REJECTED;
@@ -28,6 +29,7 @@ import static com.android.mediaroutertest.StubMediaRoute2ProviderService.ROUTE_I
import static com.android.mediaroutertest.StubMediaRoute2ProviderService.ROUTE_ID2;
import static com.android.mediaroutertest.StubMediaRoute2ProviderService.ROUTE_ID4_TO_SELECT_AND_DESELECT;
import static com.android.mediaroutertest.StubMediaRoute2ProviderService.ROUTE_ID5_TO_TRANSFER_TO;
+import static com.android.mediaroutertest.StubMediaRoute2ProviderService.ROUTE_ID6_TO_BE_IGNORED;
import static com.android.mediaroutertest.StubMediaRoute2ProviderService.ROUTE_ID_FIXED_VOLUME;
import static com.android.mediaroutertest.StubMediaRoute2ProviderService.ROUTE_ID_SPECIAL_FEATURE;
import static com.android.mediaroutertest.StubMediaRoute2ProviderService.ROUTE_ID_VARIABLE_VOLUME;
@@ -51,6 +53,7 @@ import android.media.RouteDiscoveryPreference;
import android.media.RoutingSessionInfo;
import android.os.Bundle;
import android.support.test.InstrumentationRegistry;
+import android.support.test.filters.LargeTest;
import android.support.test.filters.SmallTest;
import android.support.test.runner.AndroidJUnit4;
import android.text.TextUtils;
@@ -79,6 +82,8 @@ public class MediaRouter2ManagerTest {
private static final int TIMEOUT_MS = 5000;
private static final String TEST_KEY = "test_key";
private static final String TEST_VALUE = "test_value";
+ private static final String TEST_ID_UNKNOWN = "id_unknown";
+ private static final String TEST_NAME_UNKNOWN = "unknown";
private Context mContext;
private MediaRouter2Manager mManager;
@@ -109,7 +114,7 @@ public class MediaRouter2ManagerTest {
mContext = InstrumentationRegistry.getTargetContext();
mManager = MediaRouter2Manager.getInstance(mContext);
mRouter2 = MediaRouter2.getInstance(mContext);
- //TODO: If we need to support thread pool executors, change this to thread pool executor.
+ // If we need to support thread pool executors, change this to thread pool executor.
mExecutor = Executors.newSingleThreadExecutor();
mPackageName = mContext.getPackageName();
}
@@ -253,7 +258,6 @@ public class MediaRouter2ManagerTest {
CountDownLatch latch = new CountDownLatch(1);
addManagerCallback(new MediaRouter2Manager.Callback());
- //TODO: remove this when it's not necessary.
addRouterCallback(new MediaRouter2.RouteCallback() {});
addTransferCallback(new MediaRouter2.TransferCallback() {
@Override
@@ -277,17 +281,19 @@ public class MediaRouter2ManagerTest {
}
@Test
- public void testGetRoutingControllers() throws Exception {
+ public void testGetRoutingSessions() throws Exception {
CountDownLatch latch = new CountDownLatch(1);
Map<String, MediaRoute2Info> routes = waitAndGetRoutesWithManager(FEATURES_ALL);
+ MediaRoute2Info routeToSelect = routes.get(ROUTE_ID1);
+
addRouterCallback(new RouteCallback() {});
addManagerCallback(new MediaRouter2Manager.Callback() {
@Override
public void onTransferred(RoutingSessionInfo oldSessionInfo,
RoutingSessionInfo newSessionInfo) {
if (TextUtils.equals(mPackageName, newSessionInfo.getClientPackageName())
- && newSessionInfo.getSelectedRoutes().contains(ROUTE_ID1)) {
+ && newSessionInfo.getSelectedRoutes().contains(routeToSelect.getId())) {
latch.countDown();
}
}
@@ -295,11 +301,10 @@ public class MediaRouter2ManagerTest {
assertEquals(1, mManager.getRoutingSessions(mPackageName).size());
- mManager.selectRoute(mPackageName, routes.get(ROUTE_ID1));
- latch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS);
+ mManager.selectRoute(mPackageName, routeToSelect);
+ assertTrue(latch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
List<RoutingSessionInfo> sessions = mManager.getRoutingSessions(mPackageName);
-
assertEquals(2, sessions.size());
RoutingSessionInfo sessionInfo = sessions.get(1);
@@ -310,6 +315,77 @@ public class MediaRouter2ManagerTest {
assertEquals(1, mManager.getRoutingSessions(mPackageName).size());
}
+ @Test
+ public void testTransfer_unknownRoute_fail() throws Exception {
+ addRouterCallback(new RouteCallback() {});
+
+ CountDownLatch onSessionCreatedLatch = new CountDownLatch(1);
+ CountDownLatch onTransferFailedLatch = new CountDownLatch(1);
+
+ addManagerCallback(new MediaRouter2Manager.Callback() {
+ @Override
+ public void onTransferred(RoutingSessionInfo oldSessionInfo,
+ RoutingSessionInfo newSessionInfo) {
+ assertNotNull(newSessionInfo);
+ onSessionCreatedLatch.countDown();
+ }
+ @Override
+ public void onTransferFailed(RoutingSessionInfo session, MediaRoute2Info route) {
+ onTransferFailedLatch.countDown();
+ }
+ });
+
+ MediaRoute2Info unknownRoute =
+ new MediaRoute2Info.Builder(TEST_ID_UNKNOWN, TEST_NAME_UNKNOWN)
+ .addFeature(FEATURE_REMOTE_PLAYBACK)
+ .build();
+
+ mManager.transfer(mManager.getSystemRoutingSession(), unknownRoute);
+ assertFalse(onSessionCreatedLatch.await(WAIT_TIME_MS, TimeUnit.MILLISECONDS));
+ assertTrue(onTransferFailedLatch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
+ }
+
+ @Test
+ public void testRouterRelease_managerGetRoutingSessions() throws Exception {
+ CountDownLatch transferLatch = new CountDownLatch(1);
+ CountDownLatch releaseLatch = new CountDownLatch(1);
+
+ Map<String, MediaRoute2Info> routes = waitAndGetRoutesWithManager(FEATURES_ALL);
+ MediaRoute2Info routeToSelect = routes.get(ROUTE_ID1);
+ assertNotNull(routeToSelect);
+
+ addRouterCallback(new RouteCallback() {});
+ addManagerCallback(new MediaRouter2Manager.Callback() {
+ @Override
+ public void onTransferred(RoutingSessionInfo oldSessionInfo,
+ RoutingSessionInfo newSessionInfo) {
+ if (TextUtils.equals(mPackageName, newSessionInfo.getClientPackageName())
+ && newSessionInfo.getSelectedRoutes().contains(routeToSelect.getId())) {
+ transferLatch.countDown();
+ }
+ }
+ @Override
+ public void onSessionReleased(RoutingSessionInfo session) {
+ releaseLatch.countDown();
+ }
+ });
+
+ assertEquals(1, mManager.getRoutingSessions(mPackageName).size());
+ assertEquals(1, mRouter2.getControllers().size());
+
+ mManager.transfer(mManager.getRoutingSessions(mPackageName).get(0), routeToSelect);
+ assertTrue(transferLatch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
+
+ assertEquals(2, mManager.getRoutingSessions(mPackageName).size());
+ assertEquals(2, mRouter2.getControllers().size());
+ mRouter2.getControllers().get(1).release();
+
+ assertTrue(releaseLatch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
+
+ assertEquals(1, mRouter2.getControllers().size());
+ assertEquals(1, mManager.getRoutingSessions(mPackageName).size());
+ }
+
/**
* Tests select, transfer, release of routes of a provider
*/
@@ -351,6 +427,35 @@ public class MediaRouter2ManagerTest {
}
@Test
+ @LargeTest
+ public void testTransfer_ignored_fails() throws Exception {
+ Map<String, MediaRoute2Info> routes = waitAndGetRoutesWithManager(FEATURES_ALL);
+ addRouterCallback(new RouteCallback() {});
+
+ CountDownLatch onSessionCreatedLatch = new CountDownLatch(1);
+ CountDownLatch onFailedLatch = new CountDownLatch(1);
+
+ addManagerCallback(new MediaRouter2Manager.Callback() {
+ @Override
+ public void onTransferred(RoutingSessionInfo oldSessionInfo,
+ RoutingSessionInfo newSessionInfo) {
+ onSessionCreatedLatch.countDown();
+ }
+ @Override
+ public void onTransferFailed(RoutingSessionInfo session, MediaRoute2Info route) {
+ onFailedLatch.countDown();
+ }
+ });
+
+ List<RoutingSessionInfo> sessions = mManager.getRoutingSessions(mPackageName);
+ RoutingSessionInfo targetSession = sessions.get(sessions.size() - 1);
+ mManager.transfer(targetSession, routes.get(ROUTE_ID6_TO_BE_IGNORED));
+
+ assertFalse(onSessionCreatedLatch.await(WAIT_TIME_MS, TimeUnit.MILLISECONDS));
+ assertTrue(onFailedLatch.await(MediaRouter2Manager.TRANSFER_TIMEOUT_MS,
+ TimeUnit.MILLISECONDS));
+ }
+ @Test
public void testSetSystemRouteVolume() throws Exception {
// ensure client
addManagerCallback(new MediaRouter2Manager.Callback());
@@ -640,8 +745,10 @@ public class MediaRouter2ManagerTest {
mRouter2.registerRouteCallback(mExecutor, routeCallback,
new RouteDiscoveryPreference.Builder(routeFeatures, true).build());
try {
- addedLatch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS);
- featuresLatch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS);
+ if (mManager.getAllRoutes().isEmpty()) {
+ addedLatch.await(WAIT_TIME_MS, TimeUnit.MILLISECONDS);
+ }
+ featuresLatch.await(WAIT_TIME_MS, TimeUnit.MILLISECONDS);
return createRouteMap(mManager.getAvailableRoutes(mPackageName));
} finally {
mRouter2.unregisterRouteCallback(routeCallback);
diff --git a/media/tests/MediaRouter/src/com/android/mediaroutertest/StubMediaRoute2ProviderService.java b/media/tests/MediaRouter/src/com/android/mediaroutertest/StubMediaRoute2ProviderService.java
index 4e398f26366a..4551876d774a 100644
--- a/media/tests/MediaRouter/src/com/android/mediaroutertest/StubMediaRoute2ProviderService.java
+++ b/media/tests/MediaRouter/src/com/android/mediaroutertest/StubMediaRoute2ProviderService.java
@@ -53,6 +53,9 @@ public class StubMediaRoute2ProviderService extends MediaRoute2ProviderService {
public static final String ROUTE_ID5_TO_TRANSFER_TO = "route_id5_to_transfer_to";
public static final String ROUTE_NAME5 = "Sample Route 5 - Route to transfer to";
+ public static final String ROUTE_ID6_TO_BE_IGNORED = "route_id6_to_be_ignored";
+ public static final String ROUTE_NAME6 = "Sample Route 6 - Route to be ignored";
+
public static final String ROUTE_ID_SPECIAL_FEATURE = "route_special_feature";
public static final String ROUTE_NAME_SPECIAL_FEATURE = "Special Feature Route";
@@ -98,7 +101,10 @@ public class StubMediaRoute2ProviderService extends MediaRoute2ProviderService {
ROUTE_ID5_TO_TRANSFER_TO, ROUTE_NAME5)
.addFeature(FEATURE_SAMPLE)
.build();
-
+ MediaRoute2Info route6 = new MediaRoute2Info.Builder(
+ ROUTE_ID6_TO_BE_IGNORED, ROUTE_NAME6)
+ .addFeature(FEATURE_SAMPLE)
+ .build();
MediaRoute2Info routeSpecial =
new MediaRoute2Info.Builder(ROUTE_ID_SPECIAL_FEATURE, ROUTE_NAME_SPECIAL_FEATURE)
.addFeature(FEATURE_SAMPLE)
@@ -121,6 +127,7 @@ public class StubMediaRoute2ProviderService extends MediaRoute2ProviderService {
mRoutes.put(route3.getId(), route3);
mRoutes.put(route4.getId(), route4);
mRoutes.put(route5.getId(), route5);
+ mRoutes.put(route6.getId(), route6);
mRoutes.put(routeSpecial.getId(), routeSpecial);
mRoutes.put(fixedVolumeRoute.getId(), fixedVolumeRoute);
@@ -219,6 +226,10 @@ public class StubMediaRoute2ProviderService extends MediaRoute2ProviderService {
notifyRequestFailed(requestId, REASON_UNKNOWN_ERROR);
return;
}
+ // Ignores the request intentionally for testing
+ if (TextUtils.equals(ROUTE_ID6_TO_BE_IGNORED, routeId)) {
+ return;
+ }
maybeDeselectRoute(routeId);
final String sessionId = String.valueOf(mNextSessionId);
diff --git a/packages/CarSystemUI/Android.bp b/packages/CarSystemUI/Android.bp
index 2a8a39a1fe1a..32b33a758535 100644
--- a/packages/CarSystemUI/Android.bp
+++ b/packages/CarSystemUI/Android.bp
@@ -32,6 +32,7 @@ android_library {
"SystemUIPluginLib",
"SystemUISharedLib",
"SettingsLib",
+ "car-ui-lib",
"android.car.userlib",
"androidx.legacy_legacy-support-v4",
"androidx.recyclerview_recyclerview",
@@ -95,6 +96,7 @@ android_library {
"androidx.slice_slice-builders",
"androidx.arch.core_core-runtime",
"androidx.lifecycle_lifecycle-extensions",
+ "car-ui-lib",
"SystemUI-tags",
"SystemUI-proto",
"metrics-helper-lib",
diff --git a/packages/CarSystemUI/res/layout/car_left_navigation_bar.xml b/packages/CarSystemUI/res/layout/car_left_navigation_bar.xml
index a8c70989253e..94816f81a4c5 100644
--- a/packages/CarSystemUI/res/layout/car_left_navigation_bar.xml
+++ b/packages/CarSystemUI/res/layout/car_left_navigation_bar.xml
@@ -79,7 +79,7 @@
android:gravity="bottom"
android:orientation="vertical">
- <com.android.keyguard.AlphaOptimizedImageButton
+ <com.android.systemui.statusbar.AlphaOptimizedImageView
android:id="@+id/note"
android:layout_height="wrap_content"
android:layout_width="match_parent"
diff --git a/packages/CarSystemUI/res/layout/car_navigation_bar.xml b/packages/CarSystemUI/res/layout/car_navigation_bar.xml
index 2a715d0c3494..93174983b116 100644
--- a/packages/CarSystemUI/res/layout/car_navigation_bar.xml
+++ b/packages/CarSystemUI/res/layout/car_navigation_bar.xml
@@ -29,9 +29,10 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
- android:paddingStart="20dp"
+ android:gravity="center"
+ android:layoutDirection="ltr"
android:paddingEnd="20dp"
- android:gravity="center">
+ android:paddingStart="20dp">
<com.android.systemui.car.navigationbar.CarNavigationButton
android:id="@+id/home"
@@ -135,9 +136,10 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
- android:paddingStart="@dimen/car_keyline_1"
- android:paddingEnd="@dimen/car_keyline_1"
android:gravity="center"
+ android:layoutDirection="ltr"
+ android:paddingEnd="@dimen/car_keyline_1"
+ android:paddingStart="@dimen/car_keyline_1"
android:visibility="gone"
/>
diff --git a/packages/CarSystemUI/res/layout/car_navigation_button.xml b/packages/CarSystemUI/res/layout/car_navigation_button.xml
index ca4e76ee104b..a8f115742023 100644
--- a/packages/CarSystemUI/res/layout/car_navigation_button.xml
+++ b/packages/CarSystemUI/res/layout/car_navigation_button.xml
@@ -27,7 +27,7 @@
android:animateLayoutChanges="true"
android:orientation="vertical">
- <com.android.keyguard.AlphaOptimizedImageButton
+ <com.android.systemui.statusbar.AlphaOptimizedImageView
android:id="@+id/car_nav_button_icon_image"
android:layout_height="@dimen/car_navigation_button_icon_height"
android:layout_width="match_parent"
@@ -40,7 +40,7 @@
android:clickable="false"
/>
- <com.android.keyguard.AlphaOptimizedImageButton
+ <com.android.systemui.statusbar.AlphaOptimizedImageView
android:id="@+id/car_nav_button_more_icon"
android:layout_height="wrap_content"
android:layout_width="match_parent"
diff --git a/packages/CarSystemUI/res/layout/car_right_navigation_bar.xml b/packages/CarSystemUI/res/layout/car_right_navigation_bar.xml
index fd75570e759c..dc9583382921 100644
--- a/packages/CarSystemUI/res/layout/car_right_navigation_bar.xml
+++ b/packages/CarSystemUI/res/layout/car_right_navigation_bar.xml
@@ -82,7 +82,7 @@
android:gravity="bottom"
android:orientation="vertical">
- <com.android.keyguard.AlphaOptimizedImageButton
+ <com.android.systemui.statusbar.AlphaOptimizedImageView
android:id="@+id/note"
android:layout_height="wrap_content"
android:layout_width="match_parent"
diff --git a/packages/CarSystemUI/res/layout/car_top_navigation_bar.xml b/packages/CarSystemUI/res/layout/car_top_navigation_bar.xml
index 60e0d7e430df..cdc29eec21cd 100644
--- a/packages/CarSystemUI/res/layout/car_top_navigation_bar.xml
+++ b/packages/CarSystemUI/res/layout/car_top_navigation_bar.xml
@@ -27,7 +27,8 @@
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:layout_weight="1">
+ android:layout_weight="1"
+ android:layoutDirection="ltr">
<FrameLayout
android:id="@+id/left_hvac_container"
diff --git a/packages/CarSystemUI/res/layout/headsup_container_bottom.xml b/packages/CarSystemUI/res/layout/headsup_container_bottom.xml
index caf1677234d0..1782d2536035 100644
--- a/packages/CarSystemUI/res/layout/headsup_container_bottom.xml
+++ b/packages/CarSystemUI/res/layout/headsup_container_bottom.xml
@@ -29,6 +29,15 @@
android:orientation="horizontal"
app:layout_constraintGuide_begin="@dimen/headsup_scrim_height"/>
+ <!-- Include a FocusParkingView at the beginning or end. The rotary controller "parks" the
+ focus here when the user navigates to another window. This is also used to prevent
+ wrap-around which is why it must be first or last in Tab order. -->
+ <com.android.car.ui.FocusParkingView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ app:layout_constraintLeft_toLeftOf="parent"
+ app:layout_constraintTop_toTopOf="parent"/>
+
<View
android:id="@+id/scrim"
android:layout_width="match_parent"
diff --git a/packages/CarSystemUI/res/values/styles.xml b/packages/CarSystemUI/res/values/styles.xml
index 371bebdebc86..7fc69e6d5d8f 100644
--- a/packages/CarSystemUI/res/values/styles.xml
+++ b/packages/CarSystemUI/res/values/styles.xml
@@ -44,6 +44,6 @@
<style name="NavigationBarButton">
<item name="android:layout_height">96dp</item>
<item name="android:layout_width">96dp</item>
- <item name="android:background">@drawable/nav_button_background</item>
+ <item name="android:background">@*android:drawable/item_background_material</item>
</style>
</resources> \ No newline at end of file
diff --git a/packages/CarSystemUI/src/com/android/systemui/car/keyguard/CarKeyguardViewController.java b/packages/CarSystemUI/src/com/android/systemui/car/keyguard/CarKeyguardViewController.java
index ab61b443df97..69766cc6c0d0 100644
--- a/packages/CarSystemUI/src/com/android/systemui/car/keyguard/CarKeyguardViewController.java
+++ b/packages/CarSystemUI/src/com/android/systemui/car/keyguard/CarKeyguardViewController.java
@@ -103,6 +103,7 @@ public class CarKeyguardViewController extends OverlayViewController implements
private KeyguardBouncer mBouncer;
private OnKeyguardCancelClickedListener mKeyguardCancelClickedListener;
private boolean mShowing;
+ private boolean mIsOccluded;
@Inject
public CarKeyguardViewController(
@@ -219,6 +220,15 @@ public class CarKeyguardViewController extends OverlayViewController implements
}
@Override
+ public void setOccluded(boolean occluded, boolean animate) {
+ mIsOccluded = occluded;
+ getOverlayViewGlobalStateController().setOccluded(occluded);
+ if (!occluded) {
+ reset(/* hideBouncerWhenShowing= */ false);
+ }
+ }
+
+ @Override
public void onCancelClicked() {
if (mBouncer == null) return;
@@ -236,6 +246,12 @@ public class CarKeyguardViewController extends OverlayViewController implements
@Override
public void dismissAndCollapse() {
+ // If dismissing and collapsing Keyguard is requested (e.g. by a Keyguard-dismissing
+ // Activity) while Keyguard is occluded, unocclude Keyguard so the user can authenticate to
+ // dismiss Keyguard.
+ if (mIsOccluded) {
+ setOccluded(/* occluded= */ false, /* animate= */ false);
+ }
if (!mBouncer.isSecure()) {
hide(/* startTime= */ 0, /* fadeoutDuration= */ 0);
}
@@ -315,11 +331,6 @@ public class CarKeyguardViewController extends OverlayViewController implements
}
@Override
- public void setOccluded(boolean occluded, boolean animate) {
- // no-op
- }
-
- @Override
public boolean shouldDisableWindowAnimationsForUnlock() {
return false;
}
diff --git a/packages/CarSystemUI/src/com/android/systemui/car/navigationbar/CarNavigationBarView.java b/packages/CarSystemUI/src/com/android/systemui/car/navigationbar/CarNavigationBarView.java
index 20fc1bcd6013..0ced4021ce38 100644
--- a/packages/CarSystemUI/src/com/android/systemui/car/navigationbar/CarNavigationBarView.java
+++ b/packages/CarSystemUI/src/com/android/systemui/car/navigationbar/CarNavigationBarView.java
@@ -74,8 +74,10 @@ public class CarNavigationBarView extends LinearLayout {
mDarkIconManager.setShouldLog(true);
Dependency.get(StatusBarIconController.class).addIconGroup(mDarkIconManager);
}
- // needs to be clickable so that it will receive ACTION_MOVE events
+ // Needs to be clickable so that it will receive ACTION_MOVE events.
setClickable(true);
+ // Needs to not be focusable so rotary won't highlight the entire nav bar.
+ setFocusable(false);
}
@Override
diff --git a/packages/CarSystemUI/src/com/android/systemui/car/navigationbar/CarNavigationButton.java b/packages/CarSystemUI/src/com/android/systemui/car/navigationbar/CarNavigationButton.java
index 5e113d6366a1..e7e33a5439f9 100644
--- a/packages/CarSystemUI/src/com/android/systemui/car/navigationbar/CarNavigationButton.java
+++ b/packages/CarSystemUI/src/com/android/systemui/car/navigationbar/CarNavigationButton.java
@@ -32,8 +32,8 @@ import android.widget.ImageView;
import android.widget.LinearLayout;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.keyguard.AlphaOptimizedImageButton;
import com.android.systemui.R;
+import com.android.systemui.statusbar.AlphaOptimizedImageView;
import java.net.URISyntaxException;
@@ -53,8 +53,8 @@ public class CarNavigationButton extends LinearLayout {
private static final String EXTRA_BUTTON_PACKAGES = "packages";
private Context mContext;
- private AlphaOptimizedImageButton mIcon;
- private AlphaOptimizedImageButton mMoreIcon;
+ private AlphaOptimizedImageView mIcon;
+ private AlphaOptimizedImageView mMoreIcon;
private ImageView mUnseenIcon;
private String mIntent;
private String mLongIntent;
diff --git a/packages/CarSystemUI/src/com/android/systemui/car/navigationbar/NavigationBarViewFactory.java b/packages/CarSystemUI/src/com/android/systemui/car/navigationbar/NavigationBarViewFactory.java
index 3b7b48a77186..d60bc418ece2 100644
--- a/packages/CarSystemUI/src/com/android/systemui/car/navigationbar/NavigationBarViewFactory.java
+++ b/packages/CarSystemUI/src/com/android/systemui/car/navigationbar/NavigationBarViewFactory.java
@@ -24,6 +24,7 @@ import android.view.ViewGroup;
import androidx.annotation.LayoutRes;
+import com.android.car.ui.FocusParkingView;
import com.android.systemui.R;
import javax.inject.Inject;
@@ -146,6 +147,12 @@ public class NavigationBarViewFactory {
CarNavigationBarView view = (CarNavigationBarView) View.inflate(mContext, barLayout,
/* root= */ null);
+
+ // Include a FocusParkingView at the end. The rotary controller "parks" the focus here when
+ // the user navigates to another window. This is also used to prevent wrap-around which is
+ // why it must be first or last in Tab order.
+ view.addView(new FocusParkingView(mContext));
+
mCachedViewMap.put(type, view);
return mCachedViewMap.get(type);
}
diff --git a/packages/CarSystemUI/src/com/android/systemui/car/notification/CarHeadsUpNotificationSystemContainer.java b/packages/CarSystemUI/src/com/android/systemui/car/notification/CarHeadsUpNotificationSystemContainer.java
index aeb1d39599db..d4f720715a69 100644
--- a/packages/CarSystemUI/src/com/android/systemui/car/notification/CarHeadsUpNotificationSystemContainer.java
+++ b/packages/CarSystemUI/src/com/android/systemui/car/notification/CarHeadsUpNotificationSystemContainer.java
@@ -24,7 +24,6 @@ import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.WindowManager;
-import android.widget.FrameLayout;
import com.android.car.notification.R;
import com.android.car.notification.headsup.CarHeadsUpNotificationContainer;
@@ -44,7 +43,7 @@ public class CarHeadsUpNotificationSystemContainer implements CarHeadsUpNotifica
private final OverlayViewGlobalStateController mOverlayViewGlobalStateController;
private final ViewGroup mWindow;
- private final FrameLayout mHeadsUpContentFrame;
+ private final ViewGroup mHeadsUpContentFrame;
@Inject
CarHeadsUpNotificationSystemContainer(Context context,
diff --git a/packages/CarSystemUI/src/com/android/systemui/car/window/OverlayViewController.java b/packages/CarSystemUI/src/com/android/systemui/car/window/OverlayViewController.java
index 30e26578bd73..3969f92c690a 100644
--- a/packages/CarSystemUI/src/com/android/systemui/car/window/OverlayViewController.java
+++ b/packages/CarSystemUI/src/com/android/systemui/car/window/OverlayViewController.java
@@ -138,4 +138,11 @@ public class OverlayViewController {
protected boolean shouldShowNavigationBar() {
return false;
}
+
+ /**
+ * Returns {@code true} if this view should be hidden during the occluded state.
+ */
+ protected boolean shouldShowWhenOccluded() {
+ return false;
+ }
}
diff --git a/packages/CarSystemUI/src/com/android/systemui/car/window/OverlayViewGlobalStateController.java b/packages/CarSystemUI/src/com/android/systemui/car/window/OverlayViewGlobalStateController.java
index 70260b0d4cef..8e9410964313 100644
--- a/packages/CarSystemUI/src/com/android/systemui/car/window/OverlayViewGlobalStateController.java
+++ b/packages/CarSystemUI/src/com/android/systemui/car/window/OverlayViewGlobalStateController.java
@@ -24,7 +24,9 @@ import androidx.annotation.VisibleForTesting;
import com.android.systemui.car.navigationbar.CarNavigationBarController;
import java.util.HashMap;
+import java.util.HashSet;
import java.util.Map;
+import java.util.Set;
import java.util.SortedMap;
import java.util.TreeMap;
@@ -47,11 +49,16 @@ public class OverlayViewGlobalStateController {
private static final int UNKNOWN_Z_ORDER = -1;
private final SystemUIOverlayWindowController mSystemUIOverlayWindowController;
private final CarNavigationBarController mCarNavigationBarController;
+
+ private boolean mIsOccluded;
+
@VisibleForTesting
Map<OverlayViewController, Integer> mZOrderMap;
@VisibleForTesting
SortedMap<Integer, OverlayViewController> mZOrderVisibleSortedMap;
@VisibleForTesting
+ Set<OverlayViewController> mViewsHiddenForOcclusion;
+ @VisibleForTesting
OverlayViewController mHighestZOrder;
@Inject
@@ -63,6 +70,7 @@ public class OverlayViewGlobalStateController {
mCarNavigationBarController = carNavigationBarController;
mZOrderMap = new HashMap<>();
mZOrderVisibleSortedMap = new TreeMap<>();
+ mViewsHiddenForOcclusion = new HashSet<>();
}
/**
@@ -91,6 +99,10 @@ public class OverlayViewGlobalStateController {
*/
public void showView(OverlayViewController viewController, @Nullable Runnable show) {
debugLog();
+ if (mIsOccluded && !viewController.shouldShowWhenOccluded()) {
+ mViewsHiddenForOcclusion.add(viewController);
+ return;
+ }
if (mZOrderVisibleSortedMap.isEmpty()) {
setWindowVisible(true);
}
@@ -147,6 +159,10 @@ public class OverlayViewGlobalStateController {
*/
public void hideView(OverlayViewController viewController, @Nullable Runnable hide) {
debugLog();
+ if (mIsOccluded && mViewsHiddenForOcclusion.contains(viewController)) {
+ mViewsHiddenForOcclusion.remove(viewController);
+ return;
+ }
if (!viewController.isInflated()) {
Log.d(TAG, "Content cannot be hidden since it isn't inflated: "
+ viewController.getClass().getName());
@@ -240,6 +256,43 @@ public class OverlayViewGlobalStateController {
return mZOrderVisibleSortedMap.isEmpty() || mHighestZOrder.shouldShowHUN();
}
+ /**
+ * Set the OverlayViewWindow to be in occluded or unoccluded state. When OverlayViewWindow is
+ * occluded, all views mounted to it that are not configured to be shown during occlusion will
+ * be hidden.
+ */
+ public void setOccluded(boolean occluded) {
+ if (occluded) {
+ // Hide views before setting mIsOccluded to true so the regular hideView logic is used,
+ // not the one used during occlusion.
+ hideViewsForOcclusion();
+ mIsOccluded = true;
+ } else {
+ mIsOccluded = false;
+ // show views after setting mIsOccluded to false so the regular showView logic is used,
+ // not the one used during occlusion.
+ showViewsHiddenForOcclusion();
+ }
+ }
+
+ private void hideViewsForOcclusion() {
+ HashSet<OverlayViewController> viewsCurrentlyShowing = new HashSet<>(
+ mZOrderVisibleSortedMap.values());
+ viewsCurrentlyShowing.forEach(overlayController -> {
+ if (!overlayController.shouldShowWhenOccluded()) {
+ hideView(overlayController, overlayController::hideInternal);
+ mViewsHiddenForOcclusion.add(overlayController);
+ }
+ });
+ }
+
+ private void showViewsHiddenForOcclusion() {
+ mViewsHiddenForOcclusion.forEach(overlayViewController -> {
+ showView(overlayViewController, overlayViewController::showInternal);
+ });
+ mViewsHiddenForOcclusion.clear();
+ }
+
private void debugLog() {
if (!DEBUG) {
return;
@@ -250,5 +303,8 @@ public class OverlayViewGlobalStateController {
Log.d(TAG, "mZOrderVisibleSortedMap: " + mZOrderVisibleSortedMap);
Log.d(TAG, "mZOrderMap.size(): " + mZOrderMap.size());
Log.d(TAG, "mZOrderMap: " + mZOrderMap);
+ Log.d(TAG, "mIsOccluded: " + mIsOccluded);
+ Log.d(TAG, "mViewsHiddenForOcclusion: " + mViewsHiddenForOcclusion);
+ Log.d(TAG, "mViewsHiddenForOcclusion.size(): " + mViewsHiddenForOcclusion.size());
}
}
diff --git a/packages/CarSystemUI/tests/src/com/android/systemui/car/keyguard/CarKeyguardViewControllerTest.java b/packages/CarSystemUI/tests/src/com/android/systemui/car/keyguard/CarKeyguardViewControllerTest.java
index 38836d85e8d4..189e240169c3 100644
--- a/packages/CarSystemUI/tests/src/com/android/systemui/car/keyguard/CarKeyguardViewControllerTest.java
+++ b/packages/CarSystemUI/tests/src/com/android/systemui/car/keyguard/CarKeyguardViewControllerTest.java
@@ -22,6 +22,7 @@ import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.inOrder;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.reset;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@@ -169,6 +170,18 @@ public class CarKeyguardViewControllerTest extends SysuiTestCase {
}
@Test
+ public void setOccludedFalse_currentlyOccluded_bouncerReset() {
+ when(mBouncer.isSecure()).thenReturn(true);
+ mCarKeyguardViewController.show(/* options= */ null);
+ mCarKeyguardViewController.setOccluded(/* occluded= */ true, /* animate= */ false);
+ reset(mBouncer);
+
+ mCarKeyguardViewController.setOccluded(/* occluded= */ false, /* animate= */ false);
+
+ verify(mBouncer).show(/* resetSecuritySelection= */ true);
+ }
+
+ @Test
public void onCancelClicked_callsCancelClickedListener() {
when(mBouncer.isSecure()).thenReturn(true);
mCarKeyguardViewController.show(/* options= */ null);
diff --git a/packages/CarSystemUI/tests/src/com/android/systemui/car/navigationbar/CarNavigationButtonTest.java b/packages/CarSystemUI/tests/src/com/android/systemui/car/navigationbar/CarNavigationButtonTest.java
index 54282d39998b..bcaa5e9a03ee 100644
--- a/packages/CarSystemUI/tests/src/com/android/systemui/car/navigationbar/CarNavigationButtonTest.java
+++ b/packages/CarSystemUI/tests/src/com/android/systemui/car/navigationbar/CarNavigationButtonTest.java
@@ -36,8 +36,8 @@ import android.widget.LinearLayout;
import androidx.test.filters.SmallTest;
-import com.android.keyguard.AlphaOptimizedImageButton;
import com.android.systemui.SysuiTestCase;
+import com.android.systemui.statusbar.AlphaOptimizedImageView;
import com.android.systemui.tests.R;
import org.junit.Before;
@@ -74,7 +74,7 @@ public class CarNavigationButtonTest extends SysuiTestCase {
@Test
public void onCreate_iconIsVisible() {
- AlphaOptimizedImageButton icon = mDefaultButton.findViewById(
+ AlphaOptimizedImageView icon = mDefaultButton.findViewById(
R.id.car_nav_button_icon_image);
assertThat(icon.getDrawable()).isNotNull();
@@ -83,12 +83,12 @@ public class CarNavigationButtonTest extends SysuiTestCase {
@Test
public void onSelected_selectedIconDefined_togglesIcon() {
mDefaultButton.setSelected(true);
- Drawable selectedIconDrawable = ((AlphaOptimizedImageButton) mDefaultButton.findViewById(
+ Drawable selectedIconDrawable = ((AlphaOptimizedImageView) mDefaultButton.findViewById(
R.id.car_nav_button_icon_image)).getDrawable();
mDefaultButton.setSelected(false);
- Drawable unselectedIconDrawable = ((AlphaOptimizedImageButton) mDefaultButton.findViewById(
+ Drawable unselectedIconDrawable = ((AlphaOptimizedImageView) mDefaultButton.findViewById(
R.id.car_nav_button_icon_image)).getDrawable();
assertThat(selectedIconDrawable).isNotEqualTo(unselectedIconDrawable);
@@ -100,12 +100,12 @@ public class CarNavigationButtonTest extends SysuiTestCase {
R.id.selected_icon_undefined);
selectedIconUndefinedButton.setSelected(true);
- Drawable selectedIconDrawable = ((AlphaOptimizedImageButton) mDefaultButton.findViewById(
+ Drawable selectedIconDrawable = ((AlphaOptimizedImageView) mDefaultButton.findViewById(
R.id.car_nav_button_icon_image)).getDrawable();
selectedIconUndefinedButton.setSelected(false);
- Drawable unselectedIconDrawable = ((AlphaOptimizedImageButton) mDefaultButton.findViewById(
+ Drawable unselectedIconDrawable = ((AlphaOptimizedImageView) mDefaultButton.findViewById(
R.id.car_nav_button_icon_image)).getDrawable();
assertThat(selectedIconDrawable).isEqualTo(unselectedIconDrawable);
@@ -150,7 +150,7 @@ public class CarNavigationButtonTest extends SysuiTestCase {
@Test
public void onSelected_doesNotShowMoreWhenSelected_doesNotShowMoreIcon() {
mDefaultButton.setSelected(true);
- AlphaOptimizedImageButton moreIcon = mDefaultButton.findViewById(
+ AlphaOptimizedImageView moreIcon = mDefaultButton.findViewById(
R.id.car_nav_button_more_icon);
assertThat(moreIcon.getVisibility()).isEqualTo(View.GONE);
@@ -161,7 +161,7 @@ public class CarNavigationButtonTest extends SysuiTestCase {
CarNavigationButton showMoreWhenSelected = mTestView.findViewById(
R.id.not_highlightable_more_button);
showMoreWhenSelected.setSelected(true);
- AlphaOptimizedImageButton moreIcon = showMoreWhenSelected.findViewById(
+ AlphaOptimizedImageView moreIcon = showMoreWhenSelected.findViewById(
R.id.car_nav_button_more_icon);
assertThat(moreIcon.getVisibility()).isEqualTo(View.VISIBLE);
@@ -173,7 +173,7 @@ public class CarNavigationButtonTest extends SysuiTestCase {
R.id.highlightable_no_more_button);
showMoreWhenSelected.setSelected(true);
showMoreWhenSelected.setSelected(false);
- AlphaOptimizedImageButton moreIcon = showMoreWhenSelected.findViewById(
+ AlphaOptimizedImageView moreIcon = showMoreWhenSelected.findViewById(
R.id.car_nav_button_more_icon);
assertThat(moreIcon.getVisibility()).isEqualTo(View.GONE);
@@ -187,7 +187,7 @@ public class CarNavigationButtonTest extends SysuiTestCase {
roleBasedButton.setSelected(false);
roleBasedButton.setAppIcon(appIcon);
- Drawable currentDrawable = ((AlphaOptimizedImageButton) roleBasedButton.findViewById(
+ Drawable currentDrawable = ((AlphaOptimizedImageView) roleBasedButton.findViewById(
R.id.car_nav_button_icon_image)).getDrawable();
assertThat(currentDrawable).isEqualTo(appIcon);
@@ -212,7 +212,7 @@ public class CarNavigationButtonTest extends SysuiTestCase {
roleBasedButton.setSelected(true);
roleBasedButton.setAppIcon(appIcon);
- Drawable currentDrawable = ((AlphaOptimizedImageButton) roleBasedButton.findViewById(
+ Drawable currentDrawable = ((AlphaOptimizedImageView) roleBasedButton.findViewById(
R.id.car_nav_button_icon_image)).getDrawable();
assertThat(currentDrawable).isEqualTo(appIcon);
diff --git a/packages/CarSystemUI/tests/src/com/android/systemui/car/window/OverlayViewGlobalStateControllerTest.java b/packages/CarSystemUI/tests/src/com/android/systemui/car/window/OverlayViewGlobalStateControllerTest.java
index 9e6e616e3ccf..cba42e5a9be4 100644
--- a/packages/CarSystemUI/tests/src/com/android/systemui/car/window/OverlayViewGlobalStateControllerTest.java
+++ b/packages/CarSystemUI/tests/src/com/android/systemui/car/window/OverlayViewGlobalStateControllerTest.java
@@ -491,6 +491,81 @@ public class OverlayViewGlobalStateControllerTest extends SysuiTestCase {
}
@Test
+ public void setOccludedTrue_viewToHideWhenOccludedVisible_viewHidden() {
+ setupOverlayViewController1();
+ setOverlayViewControllerAsShowing(mOverlayViewController1);
+ when(mOverlayViewController1.shouldShowWhenOccluded()).thenReturn(false);
+
+ mOverlayViewGlobalStateController.setOccluded(true);
+
+ assertThat(mOverlayViewGlobalStateController.mZOrderVisibleSortedMap.containsValue(
+ mOverlayViewController1)).isFalse();
+ }
+
+ @Test
+ public void setOccludedTrue_viewToNotHideWhenOccludedVisible_viewShown() {
+ setupOverlayViewController1();
+ setOverlayViewControllerAsShowing(mOverlayViewController1);
+ when(mOverlayViewController1.shouldShowWhenOccluded()).thenReturn(true);
+
+ mOverlayViewGlobalStateController.setOccluded(true);
+
+ assertThat(mOverlayViewGlobalStateController.mZOrderVisibleSortedMap.containsValue(
+ mOverlayViewController1)).isTrue();
+ }
+
+ @Test
+ public void hideViewAndThenSetOccludedTrue_viewHiddenForOcclusion_viewHiddenAfterOcclusion() {
+ setupOverlayViewController1();
+ setOverlayViewControllerAsShowing(mOverlayViewController1);
+ when(mOverlayViewController1.shouldShowWhenOccluded()).thenReturn(false);
+ mOverlayViewGlobalStateController.setOccluded(true);
+
+ mOverlayViewGlobalStateController.hideView(mOverlayViewController1, /* runnable= */ null);
+ mOverlayViewGlobalStateController.setOccluded(false);
+
+ assertThat(mOverlayViewGlobalStateController.mZOrderVisibleSortedMap.containsValue(
+ mOverlayViewController1)).isFalse();
+ }
+
+ @Test
+ public void setOccludedTrueAndThenShowView_viewToNotHideForOcclusion_viewShown() {
+ setupOverlayViewController1();
+ when(mOverlayViewController1.shouldShowWhenOccluded()).thenReturn(true);
+
+ mOverlayViewGlobalStateController.setOccluded(true);
+ setOverlayViewControllerAsShowing(mOverlayViewController1);
+
+ assertThat(mOverlayViewGlobalStateController.mZOrderVisibleSortedMap.containsValue(
+ mOverlayViewController1)).isTrue();
+ }
+
+ @Test
+ public void setOccludedTrueAndThenShowView_viewToHideForOcclusion_viewHidden() {
+ setupOverlayViewController1();
+ when(mOverlayViewController1.shouldShowWhenOccluded()).thenReturn(false);
+
+ mOverlayViewGlobalStateController.setOccluded(true);
+ setOverlayViewControllerAsShowing(mOverlayViewController1);
+
+ assertThat(mOverlayViewGlobalStateController.mZOrderVisibleSortedMap.containsValue(
+ mOverlayViewController1)).isFalse();
+ }
+
+ @Test
+ public void setOccludedFalse_viewShownAfterSetOccludedTrue_viewToHideForOcclusion_viewShown() {
+ setupOverlayViewController1();
+ when(mOverlayViewController1.shouldShowWhenOccluded()).thenReturn(false);
+ mOverlayViewGlobalStateController.setOccluded(true);
+ setOverlayViewControllerAsShowing(mOverlayViewController1);
+
+ mOverlayViewGlobalStateController.setOccluded(false);
+
+ assertThat(mOverlayViewGlobalStateController.mZOrderVisibleSortedMap.containsValue(
+ mOverlayViewController1)).isTrue();
+ }
+
+ @Test
public void inflateView_notInflated_inflates() {
when(mOverlayViewController2.isInflated()).thenReturn(false);
diff --git a/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java b/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java
index 8f919c3d86ca..132922a59fc1 100644
--- a/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java
+++ b/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java
@@ -520,9 +520,11 @@ public class ExternalStorageProvider extends FileSystemProvider {
final RootInfo root = resolvedDocId.first;
File child = resolvedDocId.second;
+ final File rootFile = root.visiblePath != null ? root.visiblePath
+ : root.path;
final File parent = TextUtils.isEmpty(parentDocId)
- ? root.path
- : getFileForDocId(parentDocId);
+ ? rootFile
+ : getFileForDocId(parentDocId);
return new Path(parentDocId == null ? root.rootId : null, findDocumentPath(parent, child));
}
diff --git a/packages/PackageInstaller/res/values-or/strings.xml b/packages/PackageInstaller/res/values-or/strings.xml
index b9908d299a49..f3b97a98ccf4 100644
--- a/packages/PackageInstaller/res/values-or/strings.xml
+++ b/packages/PackageInstaller/res/values-or/strings.xml
@@ -19,7 +19,7 @@
<string name="app_name" msgid="7488448184431507488">"ପ୍ୟାକେଜ୍‌ ଇନଷ୍ଟଲର୍‍"</string>
<string name="install" msgid="711829760615509273">"ଇନଷ୍ଟଲ୍‍ କରନ୍ତୁ"</string>
<string name="done" msgid="6632441120016885253">"ହୋଇଗଲା"</string>
- <string name="cancel" msgid="1018267193425558088">"କ୍ୟାନ୍ସଲ୍ କରନ୍ତୁ"</string>
+ <string name="cancel" msgid="1018267193425558088">"ବାତିଲ୍ କରନ୍ତୁ"</string>
<string name="installing" msgid="4921993079741206516">"ଇନଷ୍ଟଲ୍‌ କରାଯାଉଛି…"</string>
<string name="installing_app" msgid="1165095864863849422">"<xliff:g id="PACKAGE_LABEL">%1$s</xliff:g> ଇନଷ୍ଟଲ୍‌ କରାଯାଉଛି…"</string>
<string name="install_done" msgid="5987363587661783896">"ଆପ୍‍ ଇନଷ୍ଟଲ୍‌ ହୋଇଗଲା।"</string>
diff --git a/packages/SettingsLib/AdaptiveIcon/res/values/colors.xml b/packages/SettingsLib/AdaptiveIcon/res/values/colors.xml
index 76d106a067dd..8f5b2ed3aaaf 100644
--- a/packages/SettingsLib/AdaptiveIcon/res/values/colors.xml
+++ b/packages/SettingsLib/AdaptiveIcon/res/values/colors.xml
@@ -18,4 +18,8 @@
<color name="homepage_generic_icon_background">#1A73E8</color>
<color name="bt_outline_color">#1f000000</color> <!-- icon outline color -->
+
+ <color name="advanced_outline_color">#BDC1C6</color> <!-- icon outline color -->
+
+ <color name="advanced_icon_color">#3C4043</color>
</resources>
diff --git a/packages/SettingsLib/AdaptiveIcon/res/values/dimens.xml b/packages/SettingsLib/AdaptiveIcon/res/values/dimens.xml
index 7f5b58c48abb..8f6e358cd9b6 100644
--- a/packages/SettingsLib/AdaptiveIcon/res/values/dimens.xml
+++ b/packages/SettingsLib/AdaptiveIcon/res/values/dimens.xml
@@ -18,6 +18,8 @@
<resources>
<!-- Dashboard foreground image inset (from background edge to foreground edge) -->
<dimen name="dashboard_tile_foreground_image_inset">6dp</dimen>
+ <!-- Advanced dashboard foreground image inset (from background edge to foreground edge) -->
+ <dimen name="advanced_dashboard_tile_foreground_image_inset">9dp</dimen>
<!-- Stroke size of adaptive outline -->
<dimen name="adaptive_outline_stroke">1dp</dimen>
diff --git a/packages/SettingsLib/AdaptiveIcon/src/com/android/settingslib/widget/AdaptiveOutlineDrawable.java b/packages/SettingsLib/AdaptiveIcon/src/com/android/settingslib/widget/AdaptiveOutlineDrawable.java
index 1c65bc248961..3bf43dd4d1bf 100644
--- a/packages/SettingsLib/AdaptiveIcon/src/com/android/settingslib/widget/AdaptiveOutlineDrawable.java
+++ b/packages/SettingsLib/AdaptiveIcon/src/com/android/settingslib/widget/AdaptiveOutlineDrawable.java
@@ -16,6 +16,10 @@
package com.android.settingslib.widget;
+import static com.android.settingslib.widget.AdaptiveOutlineDrawable.AdaptiveOutlineIconType.TYPE_ADVANCED;
+import static com.android.settingslib.widget.AdaptiveOutlineDrawable.AdaptiveOutlineIconType.TYPE_DEFAULT;
+
+import android.annotation.ColorInt;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.Canvas;
@@ -25,37 +29,99 @@ import android.graphics.Path;
import android.graphics.Rect;
import android.graphics.drawable.AdaptiveIconDrawable;
import android.graphics.drawable.DrawableWrapper;
+import android.os.RemoteException;
+import android.util.DisplayMetrics;
import android.util.PathParser;
+import android.view.Display;
+import android.view.IWindowManager;
+import android.view.WindowManagerGlobal;
+import androidx.annotation.IntDef;
import androidx.annotation.VisibleForTesting;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
/**
* Adaptive outline drawable with white plain background color and black outline
*/
public class AdaptiveOutlineDrawable extends DrawableWrapper {
+
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef({TYPE_DEFAULT, TYPE_ADVANCED})
+ public @interface AdaptiveOutlineIconType {
+ int TYPE_DEFAULT = 0;
+ int TYPE_ADVANCED = 1;
+ }
+
@VisibleForTesting
- final Paint mOutlinePaint;
+ Paint mOutlinePaint;
private Path mPath;
- private final int mInsetPx;
- private final Bitmap mBitmap;
+ private int mInsetPx;
+ private int mStrokeWidth;
+ private Bitmap mBitmap;
+ private int mType;
+ private float mDensity;
public AdaptiveOutlineDrawable(Resources resources, Bitmap bitmap) {
super(new AdaptiveIconShapeDrawable(resources));
+ init(resources, bitmap, TYPE_DEFAULT);
+ }
+
+ public AdaptiveOutlineDrawable(Resources resources, Bitmap bitmap,
+ @AdaptiveOutlineIconType int type) {
+ super(new AdaptiveIconShapeDrawable(resources));
+
+ init(resources, bitmap, type);
+ }
+
+ private void init(Resources resources, Bitmap bitmap,
+ @AdaptiveOutlineIconType int type) {
+ mType = type;
getDrawable().setTint(Color.WHITE);
mPath = new Path(PathParser.createPathFromPathData(
resources.getString(com.android.internal.R.string.config_icon_mask)));
+ mStrokeWidth = resources.getDimensionPixelSize(R.dimen.adaptive_outline_stroke);
+ mDensity = resources.getDisplayMetrics().density;
mOutlinePaint = new Paint();
- mOutlinePaint.setColor(resources.getColor(R.color.bt_outline_color, null));
+ mOutlinePaint.setColor(getColor(resources, type));
mOutlinePaint.setStyle(Paint.Style.STROKE);
- mOutlinePaint.setStrokeWidth(resources.getDimension(R.dimen.adaptive_outline_stroke));
+ mOutlinePaint.setStrokeWidth(mStrokeWidth);
mOutlinePaint.setAntiAlias(true);
- mInsetPx = resources
- .getDimensionPixelSize(R.dimen.dashboard_tile_foreground_image_inset);
+ mInsetPx = getDimensionPixelSize(resources, type);
mBitmap = bitmap;
}
+ private @ColorInt int getColor(Resources resources, @AdaptiveOutlineIconType int type) {
+ int resId;
+ switch (type) {
+ case TYPE_ADVANCED:
+ resId = R.color.advanced_outline_color;
+ break;
+ case TYPE_DEFAULT:
+ default:
+ resId = R.color.bt_outline_color;
+ break;
+ }
+ return resources.getColor(resId, /* theme */ null);
+ }
+
+ private int getDimensionPixelSize(Resources resources, @AdaptiveOutlineIconType int type) {
+ int resId;
+ switch (type) {
+ case TYPE_ADVANCED:
+ resId = R.dimen.advanced_dashboard_tile_foreground_image_inset;
+ break;
+ case TYPE_DEFAULT:
+ default:
+ resId = R.dimen.dashboard_tile_foreground_image_inset;
+ break;
+ }
+ return resources.getDimensionPixelSize(resId);
+ }
+
@Override
public void draw(Canvas canvas) {
super.draw(canvas);
@@ -68,13 +134,32 @@ public class AdaptiveOutlineDrawable extends DrawableWrapper {
final int count = canvas.save();
canvas.scale(scaleX, scaleY);
// Draw outline
- canvas.drawPath(mPath, mOutlinePaint);
+ if (mType == TYPE_DEFAULT) {
+ canvas.drawPath(mPath, mOutlinePaint);
+ } else {
+ final float defaultDensity = getDefaultDisplayDensity(Display.DEFAULT_DISPLAY)
+ / (float) DisplayMetrics.DENSITY_DEFAULT;
+ final int insetPx =
+ Math.round(mInsetPx / (float) (Math.floor(
+ (mDensity / defaultDensity) * 100) / 100.0));
+ canvas.drawCircle(2 * insetPx, 2 * insetPx, 2 * insetPx - mStrokeWidth,
+ mOutlinePaint);
+ }
canvas.restoreToCount(count);
// Draw the foreground icon
canvas.drawBitmap(mBitmap, bounds.left + mInsetPx, bounds.top + mInsetPx, null);
}
+ private static int getDefaultDisplayDensity(int displayId) {
+ try {
+ final IWindowManager wm = WindowManagerGlobal.getWindowManagerService();
+ return wm.getInitialDisplayDensity(displayId);
+ } catch (RemoteException exc) {
+ return -1;
+ }
+ }
+
@Override
public int getIntrinsicHeight() {
return mBitmap.getHeight() + 2 * mInsetPx;
diff --git a/packages/SettingsLib/OWNERS b/packages/SettingsLib/OWNERS
index a28ba8584054..d7bd6a49d75b 100644
--- a/packages/SettingsLib/OWNERS
+++ b/packages/SettingsLib/OWNERS
@@ -3,6 +3,7 @@ dsandler@android.com
edgarwang@google.com
emilychuang@google.com
evanlaird@google.com
+juliacr@google.com
leifhendrik@google.com
rafftsai@google.com
tmfang@google.com
diff --git a/packages/SettingsLib/SearchWidget/res/values-fa/strings.xml b/packages/SettingsLib/SearchWidget/res/values-fa/strings.xml
index fa5f9bdfe07b..2c9aaa5e9f95 100644
--- a/packages/SettingsLib/SearchWidget/res/values-fa/strings.xml
+++ b/packages/SettingsLib/SearchWidget/res/values-fa/strings.xml
@@ -17,5 +17,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="search_menu" msgid="1914043873178389845">"جستجوی تنظیمات"</string>
+ <string name="search_menu" msgid="1914043873178389845">"تنظیمات جستجو"</string>
</resources>
diff --git a/packages/SettingsLib/SearchWidget/res/values-tl/strings.xml b/packages/SettingsLib/SearchWidget/res/values-tl/strings.xml
index 111cf5a15dba..14b7b2f62eee 100644
--- a/packages/SettingsLib/SearchWidget/res/values-tl/strings.xml
+++ b/packages/SettingsLib/SearchWidget/res/values-tl/strings.xml
@@ -17,5 +17,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="search_menu" msgid="1914043873178389845">"Mga setting ng paghahanap"</string>
+ <string name="search_menu" msgid="1914043873178389845">"Maghanap sa mga setting"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-ar/strings.xml b/packages/SettingsLib/res/values-ar/strings.xml
index 2b51b54a2fe3..69f7fb086b64 100644
--- a/packages/SettingsLib/res/values-ar/strings.xml
+++ b/packages/SettingsLib/res/values-ar/strings.xml
@@ -557,5 +557,5 @@
<string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"غير مفعّل"</string>
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"مفعّل"</string>
<string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"يجب إعادة تشغيل جهازك ليتم تطبيق هذا التغيير. يمكنك إعادة التشغيل الآن أو إلغاء التغيير."</string>
- <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"سمّاعة رأس سلكية"</string>
+ <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"سمّاعة سلكية"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-be/strings.xml b/packages/SettingsLib/res/values-be/strings.xml
index d039c9f646df..1b5062efa23e 100644
--- a/packages/SettingsLib/res/values-be/strings.xml
+++ b/packages/SettingsLib/res/values-be/strings.xml
@@ -140,8 +140,8 @@
<string name="accessibility_wifi_security_type_none" msgid="162352241518066966">"Адкрытая сетка"</string>
<string name="accessibility_wifi_security_type_secured" msgid="2399774097343238942">"Бяспечная сетка"</string>
<string name="process_kernel_label" msgid="950292573930336765">"АС Android"</string>
- <string name="data_usage_uninstalled_apps" msgid="1933665711856171491">"Выдаленыя прыкладанні"</string>
- <string name="data_usage_uninstalled_apps_users" msgid="5533981546921913295">"Выдаленыя прыкладанні і карыстальнiкi"</string>
+ <string name="data_usage_uninstalled_apps" msgid="1933665711856171491">"Выдаленыя праграмы"</string>
+ <string name="data_usage_uninstalled_apps_users" msgid="5533981546921913295">"Выдаленыя праграмы і карыстальнiкi"</string>
<string name="data_usage_ota" msgid="7984667793701597001">"Абнаўленні сістэмы"</string>
<string name="tether_settings_title_usb" msgid="3728686573430917722">"USB-мадэм"</string>
<string name="tether_settings_title_wifi" msgid="4803402057533895526">"Партатыўны хот-спот"</string>
diff --git a/packages/SettingsLib/res/values-bn/arrays.xml b/packages/SettingsLib/res/values-bn/arrays.xml
index a131a3b1ad91..b19cde4f2778 100644
--- a/packages/SettingsLib/res/values-bn/arrays.xml
+++ b/packages/SettingsLib/res/values-bn/arrays.xml
@@ -40,7 +40,7 @@
<item msgid="8339720953594087771">"<xliff:g id="NETWORK_NAME">%1$s</xliff:g> এর সাথে কানেক্ট হচ্ছে…"</item>
<item msgid="3028983857109369308">"<xliff:g id="NETWORK_NAME">%1$s</xliff:g> দিয়ে যাচাইকরণ করা হচ্ছে..."</item>
<item msgid="4287401332778341890">"<xliff:g id="NETWORK_NAME">%1$s</xliff:g> থেকে আইপি অ্যাড্রেস জানা হচ্ছে…"</item>
- <item msgid="1043944043827424501">"<xliff:g id="NETWORK_NAME">%1$s</xliff:g> তে কানেক্ট হয়েছে"</item>
+ <item msgid="1043944043827424501">"<xliff:g id="NETWORK_NAME">%1$s</xliff:g>-এ কানেক্ট হয়েছে"</item>
<item msgid="7445993821842009653">"স্থগিত করা হয়েছে"</item>
<item msgid="1175040558087735707">"<xliff:g id="NETWORK_NAME">%1$s</xliff:g> থেকে ডিসকানেক্ট হচ্ছে…"</item>
<item msgid="699832486578171722">"ডিসকানেক্ট করা হয়েছে"</item>
diff --git a/packages/SettingsLib/res/values-el/strings.xml b/packages/SettingsLib/res/values-el/strings.xml
index 8db0b7e9dd28..2644cb987e3a 100644
--- a/packages/SettingsLib/res/values-el/strings.xml
+++ b/packages/SettingsLib/res/values-el/strings.xml
@@ -194,7 +194,7 @@
<item msgid="581904787661470707">"Ταχύτατη"</item>
</string-array>
<string name="choose_profile" msgid="343803890897657450">"Επιλογή προφίλ"</string>
- <string name="category_personal" msgid="6236798763159385225">"Προσωπικός"</string>
+ <string name="category_personal" msgid="6236798763159385225">"Προσωπικό"</string>
<string name="category_work" msgid="4014193632325996115">"Εργασίας"</string>
<string name="development_settings_title" msgid="140296922921597393">"Επιλογές για προγραμματιστές"</string>
<string name="development_settings_enable" msgid="4285094651288242183">"Ενεργοποίηση επιλογών για προγραμματιστές"</string>
diff --git a/packages/SettingsLib/res/values-en-rAU/strings.xml b/packages/SettingsLib/res/values-en-rAU/strings.xml
index 0ef8e0677d6d..0def17e1c21a 100644
--- a/packages/SettingsLib/res/values-en-rAU/strings.xml
+++ b/packages/SettingsLib/res/values-en-rAU/strings.xml
@@ -553,5 +553,5 @@
<string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"Disabled"</string>
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Enabled"</string>
<string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Your device must be rebooted for this change to apply. Reboot now or cancel."</string>
- <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Wired headphone"</string>
+ <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Wired headphones"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-en-rCA/strings.xml b/packages/SettingsLib/res/values-en-rCA/strings.xml
index 0ef8e0677d6d..0def17e1c21a 100644
--- a/packages/SettingsLib/res/values-en-rCA/strings.xml
+++ b/packages/SettingsLib/res/values-en-rCA/strings.xml
@@ -553,5 +553,5 @@
<string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"Disabled"</string>
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Enabled"</string>
<string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Your device must be rebooted for this change to apply. Reboot now or cancel."</string>
- <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Wired headphone"</string>
+ <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Wired headphones"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-en-rGB/strings.xml b/packages/SettingsLib/res/values-en-rGB/strings.xml
index 0ef8e0677d6d..0def17e1c21a 100644
--- a/packages/SettingsLib/res/values-en-rGB/strings.xml
+++ b/packages/SettingsLib/res/values-en-rGB/strings.xml
@@ -553,5 +553,5 @@
<string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"Disabled"</string>
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Enabled"</string>
<string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Your device must be rebooted for this change to apply. Reboot now or cancel."</string>
- <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Wired headphone"</string>
+ <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Wired headphones"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-en-rIN/strings.xml b/packages/SettingsLib/res/values-en-rIN/strings.xml
index 0ef8e0677d6d..0def17e1c21a 100644
--- a/packages/SettingsLib/res/values-en-rIN/strings.xml
+++ b/packages/SettingsLib/res/values-en-rIN/strings.xml
@@ -553,5 +553,5 @@
<string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"Disabled"</string>
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Enabled"</string>
<string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Your device must be rebooted for this change to apply. Reboot now or cancel."</string>
- <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Wired headphone"</string>
+ <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Wired headphones"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-et/strings.xml b/packages/SettingsLib/res/values-et/strings.xml
index 65f456e20e4e..d003ef0b9c71 100644
--- a/packages/SettingsLib/res/values-et/strings.xml
+++ b/packages/SettingsLib/res/values-et/strings.xml
@@ -449,7 +449,7 @@
<string name="power_charging_duration" msgid="5005740040558984057">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="TIME">%2$s</xliff:g> täislaadimiseni"</string>
<string name="battery_info_status_unknown" msgid="268625384868401114">"Tundmatu"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"Laadimine"</string>
- <string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Kiiresti laadimine"</string>
+ <string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Kiirlaadimine"</string>
<string name="battery_info_status_charging_slow" msgid="3190803837168962319">"Aeglaselt laadimine"</string>
<string name="battery_info_status_discharging" msgid="6962689305413556485">"Ei lae"</string>
<string name="battery_info_status_not_charging" msgid="8330015078868707899">"Vooluvõrgus, praegu ei saa laadida"</string>
diff --git a/packages/SettingsLib/res/values-in/arrays.xml b/packages/SettingsLib/res/values-in/arrays.xml
index e73febcb1aa4..d20bf38024ab 100644
--- a/packages/SettingsLib/res/values-in/arrays.xml
+++ b/packages/SettingsLib/res/values-in/arrays.xml
@@ -40,7 +40,7 @@
<item msgid="8339720953594087771">"Menyambung ke <xliff:g id="NETWORK_NAME">%1$s</xliff:g>…"</item>
<item msgid="3028983857109369308">"Mengautentikasi dengan <xliff:g id="NETWORK_NAME">%1$s</xliff:g>…"</item>
<item msgid="4287401332778341890">"Mendapatkan alamat IP dari <xliff:g id="NETWORK_NAME">%1$s</xliff:g>…"</item>
- <item msgid="1043944043827424501">"Tersambung ke <xliff:g id="NETWORK_NAME">%1$s</xliff:g>"</item>
+ <item msgid="1043944043827424501">"Terhubung ke <xliff:g id="NETWORK_NAME">%1$s</xliff:g>"</item>
<item msgid="7445993821842009653">"Ditangguhkan"</item>
<item msgid="1175040558087735707">"Diputus dari <xliff:g id="NETWORK_NAME">%1$s</xliff:g>…"</item>
<item msgid="699832486578171722">"Sambungan terputus"</item>
diff --git a/packages/SettingsLib/res/values-it/strings.xml b/packages/SettingsLib/res/values-it/strings.xml
index efc186aa24bb..24711ff92d05 100644
--- a/packages/SettingsLib/res/values-it/strings.xml
+++ b/packages/SettingsLib/res/values-it/strings.xml
@@ -64,10 +64,10 @@
<string name="wifi_passpoint_expired" msgid="6540867261754427561">"Scaduta"</string>
<string name="preference_summary_default_combination" msgid="2644094566845577901">"<xliff:g id="STATE">%1$s</xliff:g>/<xliff:g id="DESCRIPTION">%2$s</xliff:g>"</string>
<string name="bluetooth_disconnected" msgid="7739366554710388701">"Disconnesso"</string>
- <string name="bluetooth_disconnecting" msgid="7638892134401574338">"Disconnessione..."</string>
- <string name="bluetooth_connecting" msgid="5871702668260192755">"Connessione..."</string>
+ <string name="bluetooth_disconnecting" msgid="7638892134401574338">"Disconnessione…"</string>
+ <string name="bluetooth_connecting" msgid="5871702668260192755">"Connessione…"</string>
<string name="bluetooth_connected" msgid="8065345572198502293">"<xliff:g id="ACTIVE_DEVICE">%1$s</xliff:g> connesso"</string>
- <string name="bluetooth_pairing" msgid="4269046942588193600">"Accoppiamento..."</string>
+ <string name="bluetooth_pairing" msgid="4269046942588193600">"Accoppiamento…"</string>
<string name="bluetooth_connected_no_headset" msgid="2224101138659967604">"<xliff:g id="ACTIVE_DEVICE">%1$s</xliff:g> connesso (telefono escluso)"</string>
<string name="bluetooth_connected_no_a2dp" msgid="8566874395813947092">"<xliff:g id="ACTIVE_DEVICE">%1$s</xliff:g> connesso (contenuti multimediali esclusi)"</string>
<string name="bluetooth_connected_no_map" msgid="3381860077002724689">"<xliff:g id="ACTIVE_DEVICE">%1$s</xliff:g> connesso (nessun accesso ai messaggi)"</string>
@@ -406,11 +406,11 @@
<string name="select_webview_provider_dialog_title" msgid="2444261109877277714">"Imposta l\'implementazione di WebView"</string>
<string name="select_webview_provider_toast_text" msgid="8512254949169359848">"La selezione non è più valida. Riprova."</string>
<string name="convert_to_file_encryption" msgid="2828976934129751818">"Converti in crittografia basata su file"</string>
- <string name="convert_to_file_encryption_enabled" msgid="840757431284311754">"Converti..."</string>
+ <string name="convert_to_file_encryption_enabled" msgid="840757431284311754">"Converti…"</string>
<string name="convert_to_file_encryption_done" msgid="8965831011811180627">"Crittografia su base file già eseguita"</string>
<string name="title_convert_fbe" msgid="5780013350366495149">"Conversione in crittografia basata su file"</string>
- <string name="convert_to_fbe_warning" msgid="34294381569282109">"Converti la partizione di dati in crittografia basata su file.\n Attenzione. Questa operazione eliminerà tutti i tuoi dati.\n Questa funzione è in versione alpha, pertanto potrebbe non funzionare correttamente.\n Premi \"Cancella e converti...\" per continuare."</string>
- <string name="button_convert_fbe" msgid="1159861795137727671">"Cancella e converti..."</string>
+ <string name="convert_to_fbe_warning" msgid="34294381569282109">"Converti la partizione di dati in crittografia basata su file.\n Attenzione. Questa operazione eliminerà tutti i tuoi dati.\n Questa funzione è in versione alpha, pertanto potrebbe non funzionare correttamente.\n Premi \"Cancella e converti…\" per continuare."</string>
+ <string name="button_convert_fbe" msgid="1159861795137727671">"Cancella e converti…"</string>
<string name="picture_color_mode" msgid="1013807330552931903">"Modalità colori immagini"</string>
<string name="picture_color_mode_desc" msgid="151780973768136200">"Use sRGB"</string>
<string name="daltonizer_mode_disabled" msgid="403424372812399228">"Disattivato"</string>
diff --git a/packages/SettingsLib/res/values-vi/strings.xml b/packages/SettingsLib/res/values-vi/strings.xml
index b501c656a680..7e1b476b7a0c 100644
--- a/packages/SettingsLib/res/values-vi/strings.xml
+++ b/packages/SettingsLib/res/values-vi/strings.xml
@@ -195,7 +195,7 @@
</string-array>
<string name="choose_profile" msgid="343803890897657450">"Chọn hồ sơ"</string>
<string name="category_personal" msgid="6236798763159385225">"Cá nhân"</string>
- <string name="category_work" msgid="4014193632325996115">"Cơ quan"</string>
+ <string name="category_work" msgid="4014193632325996115">"Công việc"</string>
<string name="development_settings_title" msgid="140296922921597393">"Tùy chọn cho nhà phát triển"</string>
<string name="development_settings_enable" msgid="4285094651288242183">"Bật tùy chọn nhà phát triển"</string>
<string name="development_settings_summary" msgid="8718917813868735095">"Đặt tùy chọn cho phát triển ứng dụng"</string>
diff --git a/packages/SettingsLib/res/values/dimens.xml b/packages/SettingsLib/res/values/dimens.xml
index a5ec5e66f242..e552d78e1a45 100644
--- a/packages/SettingsLib/res/values/dimens.xml
+++ b/packages/SettingsLib/res/values/dimens.xml
@@ -94,4 +94,7 @@
<!-- Define minimal size of the tap area -->
<dimen name="min_tap_target_size">48dp</dimen>
+
+ <!-- Size of advanced icon -->
+ <dimen name="advanced_icon_size">18dp</dimen>
</resources>
diff --git a/packages/SettingsLib/src/com/android/settingslib/applications/AppUtils.java b/packages/SettingsLib/src/com/android/settingslib/applications/AppUtils.java
index a6202956efa5..38eeda245616 100644
--- a/packages/SettingsLib/src/com/android/settingslib/applications/AppUtils.java
+++ b/packages/SettingsLib/src/com/android/settingslib/applications/AppUtils.java
@@ -19,10 +19,13 @@ package com.android.settingslib.applications;
import android.app.Application;
import android.content.ComponentName;
import android.content.Context;
+import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
import android.hardware.usb.IUsbManager;
+import android.net.Uri;
import android.os.RemoteException;
import android.os.SystemProperties;
import android.os.UserHandle;
@@ -44,6 +47,15 @@ public class AppUtils {
*/
private static InstantAppDataProvider sInstantAppDataProvider = null;
+ private static final Intent sBrowserIntent;
+
+ static {
+ sBrowserIntent = new Intent()
+ .setAction(Intent.ACTION_VIEW)
+ .addCategory(Intent.CATEGORY_BROWSABLE)
+ .setData(Uri.parse("http:"));
+ }
+
public static CharSequence getLaunchByDefaultSummary(ApplicationsState.AppEntry appEntry,
IUsbManager usbManager, PackageManager pm, Context context) {
String packageName = appEntry.info.packageName;
@@ -153,4 +165,22 @@ public class AppUtils {
return com.android.settingslib.utils.applications.AppUtils.getAppContentDescription(context,
packageName, userId);
}
+
+ /**
+ * Returns a boolean indicating whether a given package is a browser app.
+ *
+ * An app is a "browser" if it has an activity resolution that wound up
+ * marked with the 'handleAllWebDataURI' flag.
+ */
+ public static boolean isBrowserApp(Context context, String packageName, int userId) {
+ sBrowserIntent.setPackage(packageName);
+ final List<ResolveInfo> list = context.getPackageManager().queryIntentActivitiesAsUser(
+ sBrowserIntent, PackageManager.MATCH_ALL, userId);
+ for (ResolveInfo info : list) {
+ if (info.activityInfo != null && info.handleAllWebDataURI) {
+ return true;
+ }
+ }
+ return false;
+ }
}
diff --git a/packages/SettingsLib/src/com/android/settingslib/applications/ApplicationsState.java b/packages/SettingsLib/src/com/android/settingslib/applications/ApplicationsState.java
index 1d4cfdc88ad5..a89cf37e2d06 100644
--- a/packages/SettingsLib/src/com/android/settingslib/applications/ApplicationsState.java
+++ b/packages/SettingsLib/src/com/android/settingslib/applications/ApplicationsState.java
@@ -60,6 +60,7 @@ import androidx.lifecycle.OnLifecycleEvent;
import com.android.internal.R;
import com.android.internal.util.ArrayUtils;
import com.android.settingslib.Utils;
+import com.android.settingslib.utils.ThreadUtils;
import java.io.File;
import java.io.IOException;
@@ -1588,6 +1589,15 @@ public class ApplicationsState {
this.size = SIZE_UNKNOWN;
this.sizeStale = true;
ensureLabel(context);
+ // Speed up the cache of the icon and label description if they haven't been created.
+ ThreadUtils.postOnBackgroundThread(() -> {
+ if (this.icon == null) {
+ this.ensureIconLocked(context);
+ }
+ if (this.labelDescription == null) {
+ this.ensureLabelDescriptionLocked(context);
+ }
+ });
}
public void ensureLabel(Context context) {
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothUtils.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothUtils.java
index 9d1b3cf116d9..95e916b9871a 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothUtils.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothUtils.java
@@ -1,5 +1,7 @@
package com.android.settingslib.bluetooth;
+import static com.android.settingslib.widget.AdaptiveOutlineDrawable.AdaptiveOutlineIconType.TYPE_ADVANCED;
+
import android.bluetooth.BluetoothClass;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothProfile;
@@ -7,6 +9,7 @@ import android.content.Context;
import android.content.Intent;
import android.content.res.Resources;
import android.graphics.Bitmap;
+import android.graphics.Canvas;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.net.Uri;
@@ -213,6 +216,46 @@ public class BluetoothUtils {
}
/**
+ * Build device icon with advanced outline
+ */
+ public static Drawable buildAdvancedDrawable(Context context, Drawable drawable) {
+ final int iconSize = context.getResources().getDimensionPixelSize(
+ R.dimen.advanced_icon_size);
+ final Resources resources = context.getResources();
+
+ Bitmap bitmap = null;
+ if (drawable instanceof BitmapDrawable) {
+ bitmap = ((BitmapDrawable) drawable).getBitmap();
+ } else {
+ final int width = drawable.getIntrinsicWidth();
+ final int height = drawable.getIntrinsicHeight();
+ bitmap = createBitmap(drawable,
+ width > 0 ? width : 1,
+ height > 0 ? height : 1);
+ }
+
+ if (bitmap != null) {
+ final Bitmap resizedBitmap = Bitmap.createScaledBitmap(bitmap, iconSize,
+ iconSize, false);
+ bitmap.recycle();
+ return new AdaptiveOutlineDrawable(resources, resizedBitmap, TYPE_ADVANCED);
+ }
+
+ return drawable;
+ }
+
+ /**
+ * Creates a drawable with specified width and height.
+ */
+ public static Bitmap createBitmap(Drawable drawable, int width, int height) {
+ final Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
+ final Canvas canvas = new Canvas(bitmap);
+ drawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight());
+ drawable.draw(canvas);
+ return bitmap;
+ }
+
+ /**
* Get boolean Bluetooth metadata
*
* @param bluetoothDevice the BluetoothDevice to get metadata
diff --git a/packages/SettingsLib/src/com/android/settingslib/media/BluetoothMediaDevice.java b/packages/SettingsLib/src/com/android/settingslib/media/BluetoothMediaDevice.java
index 40d80488af96..00f94f5c2e64 100644
--- a/packages/SettingsLib/src/com/android/settingslib/media/BluetoothMediaDevice.java
+++ b/packages/SettingsLib/src/com/android/settingslib/media/BluetoothMediaDevice.java
@@ -21,7 +21,6 @@ import android.content.Context;
import android.graphics.drawable.Drawable;
import android.media.MediaRoute2Info;
import android.media.MediaRouter2Manager;
-import android.util.Pair;
import com.android.settingslib.R;
import com.android.settingslib.bluetooth.BluetoothUtils;
@@ -57,13 +56,11 @@ public class BluetoothMediaDevice extends MediaDevice {
@Override
public Drawable getIcon() {
- final Pair<Drawable, String> pair = BluetoothUtils
- .getBtRainbowDrawableWithDescription(mContext, mCachedDevice);
- return isFastPairDevice()
- ? pair.first
- : BluetoothUtils.buildBtRainbowDrawable(mContext,
- mContext.getDrawable(R.drawable.ic_headphone),
- mCachedDevice.getAddress().hashCode());
+ final Drawable drawable = getIconWithoutBackground();
+ if (!isFastPairDevice()) {
+ setColorFilter(drawable);
+ }
+ return BluetoothUtils.buildAdvancedDrawable(mContext, drawable);
}
@Override
diff --git a/packages/SettingsLib/src/com/android/settingslib/media/InfoMediaDevice.java b/packages/SettingsLib/src/com/android/settingslib/media/InfoMediaDevice.java
index 8d6bc5c97228..ea71e52dc9c9 100644
--- a/packages/SettingsLib/src/com/android/settingslib/media/InfoMediaDevice.java
+++ b/packages/SettingsLib/src/com/android/settingslib/media/InfoMediaDevice.java
@@ -55,9 +55,9 @@ public class InfoMediaDevice extends MediaDevice {
@Override
public Drawable getIcon() {
- //TODO(b/120669861): Return remote device icon uri once api is ready.
- return BluetoothUtils.buildBtRainbowDrawable(mContext,
- mContext.getDrawable(getDrawableResId()), getId().hashCode());
+ final Drawable drawable = getIconWithoutBackground();
+ setColorFilter(drawable);
+ return BluetoothUtils.buildAdvancedDrawable(mContext, drawable);
}
@Override
diff --git a/packages/SettingsLib/src/com/android/settingslib/media/MediaDevice.java b/packages/SettingsLib/src/com/android/settingslib/media/MediaDevice.java
index 317077b14e30..126f9b91b0d2 100644
--- a/packages/SettingsLib/src/com/android/settingslib/media/MediaDevice.java
+++ b/packages/SettingsLib/src/com/android/settingslib/media/MediaDevice.java
@@ -31,6 +31,9 @@ import static android.media.MediaRoute2Info.TYPE_WIRED_HEADPHONES;
import static android.media.MediaRoute2Info.TYPE_WIRED_HEADSET;
import android.content.Context;
+import android.content.res.ColorStateList;
+import android.graphics.PorterDuff;
+import android.graphics.PorterDuffColorFilter;
import android.graphics.drawable.Drawable;
import android.media.MediaRoute2Info;
import android.media.MediaRouter2Manager;
@@ -39,6 +42,8 @@ import android.text.TextUtils;
import androidx.annotation.IntDef;
import androidx.annotation.VisibleForTesting;
+import com.android.settingslib.R;
+
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@@ -131,6 +136,14 @@ public abstract class MediaDevice implements Comparable<MediaDevice> {
getId());
}
+ void setColorFilter(Drawable drawable) {
+ final ColorStateList list =
+ mContext.getResources().getColorStateList(
+ R.color.advanced_icon_color, mContext.getTheme());
+ drawable.setColorFilter(new PorterDuffColorFilter(list.getDefaultColor(),
+ PorterDuff.Mode.SRC_IN));
+ }
+
/**
* Get name from MediaDevice.
*
diff --git a/packages/SettingsLib/src/com/android/settingslib/media/PhoneMediaDevice.java b/packages/SettingsLib/src/com/android/settingslib/media/PhoneMediaDevice.java
index c43a51246fb5..b6c0b30b3bd4 100644
--- a/packages/SettingsLib/src/com/android/settingslib/media/PhoneMediaDevice.java
+++ b/packages/SettingsLib/src/com/android/settingslib/media/PhoneMediaDevice.java
@@ -85,8 +85,9 @@ public class PhoneMediaDevice extends MediaDevice {
@Override
public Drawable getIcon() {
- return BluetoothUtils.buildBtRainbowDrawable(mContext,
- mContext.getDrawable(getDrawableResId()), getId().hashCode());
+ final Drawable drawable = getIconWithoutBackground();
+ setColorFilter(drawable);
+ return BluetoothUtils.buildAdvancedDrawable(mContext, drawable);
}
@Override
@@ -105,7 +106,7 @@ public class PhoneMediaDevice extends MediaDevice {
case TYPE_HDMI:
case TYPE_WIRED_HEADSET:
case TYPE_WIRED_HEADPHONES:
- resId = com.android.internal.R.drawable.ic_bt_headphones_a2dp;
+ resId = R.drawable.ic_headphone;
break;
case TYPE_BUILTIN_SPEAKER:
default:
diff --git a/packages/SettingsLib/src/com/android/settingslib/notification/ConversationIconFactory.java b/packages/SettingsLib/src/com/android/settingslib/notification/ConversationIconFactory.java
index d5f1ece5f83f..549bc8a455cf 100644
--- a/packages/SettingsLib/src/com/android/settingslib/notification/ConversationIconFactory.java
+++ b/packages/SettingsLib/src/com/android/settingslib/notification/ConversationIconFactory.java
@@ -86,7 +86,7 @@ public class ConversationIconFactory extends BaseIconFactory {
/**
* Returns the conversation info drawable
*/
- private Drawable getBaseIconDrawable(ShortcutInfo shortcutInfo) {
+ public Drawable getBaseIconDrawable(ShortcutInfo shortcutInfo) {
return mLauncherApps.getShortcutIconDrawable(shortcutInfo, mFillResIconDpi);
}
@@ -94,7 +94,7 @@ public class ConversationIconFactory extends BaseIconFactory {
* Get the {@link Drawable} that represents the app icon, badged with the work profile icon
* if appropriate.
*/
- private Drawable getAppBadge(String packageName, int userId) {
+ public Drawable getAppBadge(String packageName, int userId) {
Drawable badge = null;
try {
final ApplicationInfo appInfo = mPackageManager.getApplicationInfoAsUser(
diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java
index d1cd043352cb..3015397ff1a3 100644
--- a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java
+++ b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java
@@ -900,9 +900,7 @@ public class WifiTracker implements LifecycleObserver, OnStart, OnStop, OnDestro
updateNetworkInfo(info);
fetchScansAndConfigsAndUpdateAccessPoints();
} else if (WifiManager.RSSI_CHANGED_ACTION.equals(action)) {
- NetworkInfo info =
- mConnectivityManager.getNetworkInfo(mWifiManager.getCurrentNetwork());
- updateNetworkInfo(info);
+ updateNetworkInfo(/* networkInfo= */ null);
}
}
};
@@ -948,7 +946,7 @@ public class WifiTracker implements LifecycleObserver, OnStart, OnStop, OnDestro
// We don't send a NetworkInfo object along with this message, because even if we
// fetch one from ConnectivityManager, it might be older than the most recent
// NetworkInfo message we got via a WIFI_STATE_CHANGED broadcast.
- updateNetworkInfo(null);
+ updateNetworkInfo(/* networkInfo= */ null);
}
}
}
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/PhoneMediaDeviceTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/PhoneMediaDeviceTest.java
index 421e5c0db1a1..00d1f76f025f 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/PhoneMediaDeviceTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/PhoneMediaDeviceTest.java
@@ -79,13 +79,11 @@ public class PhoneMediaDeviceTest {
public void getDrawableResId_returnCorrectResId() {
when(mInfo.getType()).thenReturn(TYPE_WIRED_HEADPHONES);
- assertThat(mPhoneMediaDevice.getDrawableResId())
- .isEqualTo(com.android.internal.R.drawable.ic_bt_headphones_a2dp);
+ assertThat(mPhoneMediaDevice.getDrawableResId()).isEqualTo(R.drawable.ic_headphone);
when(mInfo.getType()).thenReturn(TYPE_WIRED_HEADSET);
- assertThat(mPhoneMediaDevice.getDrawableResId())
- .isEqualTo(com.android.internal.R.drawable.ic_bt_headphones_a2dp);
+ assertThat(mPhoneMediaDevice.getDrawableResId()).isEqualTo(R.drawable.ic_headphone);
when(mInfo.getType()).thenReturn(TYPE_BUILTIN_SPEAKER);
diff --git a/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java b/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
index fa87b62bd73a..eb7ad72eb1ba 100644
--- a/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
+++ b/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
@@ -316,7 +316,6 @@ public class SettingsBackupTest {
Settings.Global.KERNEL_CPU_THREAD_READER,
Settings.Global.LANG_ID_UPDATE_CONTENT_URL,
Settings.Global.LANG_ID_UPDATE_METADATA_URL,
- Settings.Global.LAST_ACTIVE_USER_ID,
Settings.Global.LOCATION_BACKGROUND_THROTTLE_INTERVAL_MS,
Settings.Global.LOCATION_BACKGROUND_THROTTLE_PROXIMITY_ALERT_INTERVAL_MS,
Settings.Global.LOCATION_BACKGROUND_THROTTLE_PACKAGE_WHITELIST,
diff --git a/packages/Shell/AndroidManifest.xml b/packages/Shell/AndroidManifest.xml
index ae8e8e82241d..4e17062fc52c 100644
--- a/packages/Shell/AndroidManifest.xml
+++ b/packages/Shell/AndroidManifest.xml
@@ -201,6 +201,9 @@
<uses-permission android:name="android.permission.MANAGE_APPOPS" />
+ <!-- Permission required for IncrementalLogCollectionTest -->
+ <uses-permission android:name="android.permission.LOADER_USAGE_STATS" />
+
<!-- Permission required for storage tests - FuseDaemonHostTest -->
<uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE"/>
@@ -306,6 +309,9 @@
<!-- Permission needed for CTS test - PrivilegedLocationPermissionTest -->
<uses-permission android:name="android.permission.LOCATION_HARDWARE" />
+ <!-- Permissions required for GTS test - GtsDialerAudioTestCases -->
+ <uses-permission android:name="android.permission.CAPTURE_AUDIO_OUTPUT" />
+
<application android:label="@string/app_label"
android:theme="@android:style/Theme.DeviceDefault.DayNight"
android:defaultToDeviceProtectedStorage="true"
diff --git a/packages/Shell/res/layout/dialog_bugreport_info.xml b/packages/Shell/res/layout/dialog_bugreport_info.xml
index 4bd871103193..ea2427920285 100644
--- a/packages/Shell/res/layout/dialog_bugreport_info.xml
+++ b/packages/Shell/res/layout/dialog_bugreport_info.xml
@@ -14,58 +14,63 @@
limitations under the License.
-->
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:orientation="vertical"
- android:paddingTop="15dp"
- android:paddingStart="24dp"
- android:paddingEnd="24dp"
- android:focusableInTouchMode="false"
- android:focusable="false"
- android:importantForAutofill="noExcludeDescendants"
- android:layout_width="wrap_content"
+<ScrollView
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
android:layout_height="wrap_content">
- <TextView
+ <LinearLayout
+ android:orientation="vertical"
+ android:paddingTop="15dp"
+ android:paddingStart="24dp"
+ android:paddingEnd="24dp"
android:focusableInTouchMode="false"
android:focusable="false"
- android:inputType="textNoSuggestions"
+ android:importantForAutofill="noExcludeDescendants"
android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:text="@string/bugreport_info_name"/>
- <EditText
- android:id="@+id/name"
- android:nextFocusDown="@+id/title"
- android:maxLength="30"
- android:singleLine="true"
- android:inputType="textNoSuggestions"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"/>
- <TextView
- android:focusableInTouchMode="false"
- android:focusable="false"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:text="@string/bugreport_info_title"/>
- <EditText
- android:id="@+id/title"
- android:nextFocusUp="@+id/name"
- android:nextFocusDown="@+id/description"
- android:maxLength="80"
- android:singleLine="true"
- android:inputType="textAutoCorrect|textCapSentences"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"/>
- <TextView
- android:focusableInTouchMode="false"
- android:focusable="false"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:editable="false"
- android:text="@string/bugreport_info_description"/>
- <EditText
- android:id="@+id/description"
- android:nextFocusUp="@+id/title"
- android:singleLine="false"
- android:inputType="textMultiLine|textAutoCorrect|textCapSentences"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"/>
-</LinearLayout>
+ android:layout_height="wrap_content">
+ <TextView
+ android:focusableInTouchMode="false"
+ android:focusable="false"
+ android:inputType="textNoSuggestions"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:text="@string/bugreport_info_name"/>
+ <EditText
+ android:id="@+id/name"
+ android:nextFocusDown="@+id/title"
+ android:maxLength="30"
+ android:singleLine="true"
+ android:inputType="textNoSuggestions"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"/>
+ <TextView
+ android:focusableInTouchMode="false"
+ android:focusable="false"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:text="@string/bugreport_info_title"/>
+ <EditText
+ android:id="@+id/title"
+ android:nextFocusUp="@+id/name"
+ android:nextFocusDown="@+id/description"
+ android:maxLength="80"
+ android:singleLine="true"
+ android:inputType="textAutoCorrect|textCapSentences"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"/>
+ <TextView
+ android:focusableInTouchMode="false"
+ android:focusable="false"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:editable="false"
+ android:text="@string/bugreport_info_description"/>
+ <EditText
+ android:id="@+id/description"
+ android:nextFocusUp="@+id/title"
+ android:singleLine="false"
+ android:inputType="textMultiLine|textAutoCorrect|textCapSentences"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"/>
+ </LinearLayout>
+</ScrollView>
diff --git a/packages/SystemUI/res-keyguard/values-ko/strings.xml b/packages/SystemUI/res-keyguard/values-ko/strings.xml
index 06074b2726c3..606bb5047245 100644
--- a/packages/SystemUI/res-keyguard/values-ko/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-ko/strings.xml
@@ -62,7 +62,7 @@
<string name="kg_forgot_pattern_button_text" msgid="3304688032024541260">"패턴을 잊음"</string>
<string name="kg_wrong_pattern" msgid="5907301342430102842">"잘못된 패턴"</string>
<string name="kg_wrong_password" msgid="4143127991071670512">"잘못된 비밀번호"</string>
- <string name="kg_wrong_pin" msgid="4160978845968732624">"잘못된 PIN"</string>
+ <string name="kg_wrong_pin" msgid="4160978845968732624">"PIN 오류"</string>
<plurals name="kg_too_many_failed_attempts_countdown" formatted="false" msgid="991400408675793914">
<item quantity="other"><xliff:g id="NUMBER">%d</xliff:g>초 후에 다시 시도하세요.</item>
<item quantity="one">1초 후에 다시 시도하세요.</item>
diff --git a/packages/SystemUI/res-keyguard/values-ur/strings.xml b/packages/SystemUI/res-keyguard/values-ur/strings.xml
index 981bc03387b5..22a477e3d63f 100644
--- a/packages/SystemUI/res-keyguard/values-ur/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-ur/strings.xml
@@ -71,7 +71,7 @@
<string name="kg_sim_pin_instructions" msgid="1942424305184242951">"‏SIM PIN درج کریں۔"</string>
<string name="kg_sim_pin_instructions_multi" msgid="3639863309953109649">"‏\"<xliff:g id="CARRIER">%1$s</xliff:g>\" کیلئے SIM PIN درج کریں۔"</string>
<string name="kg_sim_lock_esim_instructions" msgid="5577169988158738030">"‏<xliff:g id="PREVIOUS_MSG">%1$s</xliff:g> موبائل سروس کے بغیر آلہ کا استعمال کرنے کیلئے eSIM غیر فعال کریں۔"</string>
- <string name="kg_pin_instructions" msgid="822353548385014361">"‏PIN درج کریں"</string>
+ <string name="kg_pin_instructions" msgid="822353548385014361">"‏‫PIN درج کریں"</string>
<string name="kg_password_instructions" msgid="324455062831719903">"پاسورڈ درج کریں"</string>
<string name="kg_puk_enter_puk_hint" msgid="3005288372875367017">"‏SIM اب غیر فعال ہوگیا ہے۔ جاری رکھنے کیلئے PUK کوڈ درج کریں۔ تفصیلات کیلئے کیریئر سے رابطہ کریں۔"</string>
<string name="kg_puk_enter_puk_hint_multi" msgid="4876780689904862943">"‏SIM \"<xliff:g id="CARRIER">%1$s</xliff:g>\" اب غیر فعال ہے۔ جاری رکھنے کیلئے PUK کوڈ درج کریں۔ تفصیلات کیلئے کیریئر سے رابطہ کریں۔"</string>
diff --git a/packages/SystemUI/res-keyguard/values-uz/strings.xml b/packages/SystemUI/res-keyguard/values-uz/strings.xml
index 1905e64ea754..72d4fae575b8 100644
--- a/packages/SystemUI/res-keyguard/values-uz/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-uz/strings.xml
@@ -33,7 +33,7 @@
<string name="keyguard_enter_your_password" msgid="7225626204122735501">"Parolni kiriting"</string>
<string name="keyguard_password_wrong_pin_code" msgid="3514267777289393046">"PIN kodi xato."</string>
<string name="keyguard_sim_error_message_short" msgid="633630844240494070">"SIM karta yaroqsiz."</string>
- <string name="keyguard_charged" msgid="5478247181205188995">"Batareya quvvati to‘ldi"</string>
+ <string name="keyguard_charged" msgid="5478247181205188995">"Quvvat oldi"</string>
<string name="keyguard_plugged_in_wireless" msgid="2537874724955057383">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Simsiz quvvatlanyapti"</string>
<string name="keyguard_plugged_in" msgid="8169926454348380863">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Quvvat olmoqda"</string>
<string name="keyguard_plugged_in_charging_fast" msgid="4386594091107340426">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Tezkor quvvat olmoqda"</string>
diff --git a/packages/SystemUI/res-product/values-af/strings.xml b/packages/SystemUI/res-product/values-af/strings.xml
index 8c979b2fe397..1d335c3dff9b 100644
--- a/packages/SystemUI/res-product/values-af/strings.xml
+++ b/packages/SystemUI/res-product/values-af/strings.xml
@@ -40,10 +40,7 @@
<string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4682221342671290678">"Jy het die foon <xliff:g id="NUMBER">%d</xliff:g> keer verkeerd probeer ontsluit. Die werkprofiel sal verwyder word, wat alle profieldata sal uitvee."</string>
<string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="1860049973474855672">"Jy het jou ontsluitpatroon <xliff:g id="NUMBER_0">%1$d</xliff:g> keer verkeerd geteken. Na nóg <xliff:g id="NUMBER_1">%2$d</xliff:g> onsuksesvolle pogings sal jy gevra word om jou e-posrekening te gebruik om jou tablet te ontsluit.\n\n Probeer weer oor <xliff:g id="NUMBER_2">%3$d</xliff:g> sekondes."</string>
<string name="kg_failed_attempts_almost_at_login" product="default" msgid="44112553371516141">"Jy het jou ontsluitpatroon <xliff:g id="NUMBER_0">%1$d</xliff:g> keer verkeerd geteken. Na nóg <xliff:g id="NUMBER_1">%2$d</xliff:g> onsuksesvolle pogings sal jy gevra word om jou e-posrekening te gebruik om jou foon te ontsluit.\n\n Probeer weer oor <xliff:g id="NUMBER_2">%3$d</xliff:g> sekondes."</string>
- <!-- no translation found for global_action_lock_message (7092460751050168771) -->
- <skip />
- <!-- no translation found for global_action_lock_message (1024230056230539493) -->
- <skip />
- <!-- no translation found for global_action_lock_message (3165224897120346096) -->
- <skip />
+ <string name="global_action_lock_message" product="default" msgid="7092460751050168771">"Ontsluit jou foon vir meer opsies"</string>
+ <string name="global_action_lock_message" product="tablet" msgid="1024230056230539493">"Ontsluit jou tablet vir meer opsies"</string>
+ <string name="global_action_lock_message" product="device" msgid="3165224897120346096">"Ontsluit jou toestel vir meer opsies"</string>
</resources>
diff --git a/packages/SystemUI/res-product/values-am/strings.xml b/packages/SystemUI/res-product/values-am/strings.xml
index 4e483a50035b..c11e85689f69 100644
--- a/packages/SystemUI/res-product/values-am/strings.xml
+++ b/packages/SystemUI/res-product/values-am/strings.xml
@@ -40,10 +40,7 @@
<string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4682221342671290678">"ስልኩን <xliff:g id="NUMBER">%d</xliff:g> ጊዜ ትክክል ባልሆነ መልኩ ለመክፈት ሞክረዋል። የስራ መገለጫው ይወገዳል፣ ይህም ሁሉንም የመገለጫ ውሂብ ይሰርዛል።"</string>
<string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="1860049973474855672">"የመክፈቻ ስርዓተ ጥለቱን <xliff:g id="NUMBER_0">%1$d</xliff:g> ጊዜ በትክክል አልሳሉትም። ከ<xliff:g id="NUMBER_1">%2$d</xliff:g> ተጨማሪ ያልተሳኩ ሙከራዎች በኋላ የኢሜይል መለያ ተጠቅመው ጡባዊዎን እንዲከፍቱ ይጠየቃሉ።\n\n ከ<xliff:g id="NUMBER_2">%3$d</xliff:g> ከሰከንዶች በኋላ እንደገና ይሞክሩ።"</string>
<string name="kg_failed_attempts_almost_at_login" product="default" msgid="44112553371516141">"የመክፈቻ ስርዓተ ጥለቱን <xliff:g id="NUMBER_0">%1$d</xliff:g> ጊዜ በትክክል አልሳሉትም። ከ<xliff:g id="NUMBER_1">%2$d</xliff:g> ተጨማሪ ያልተሳኩ ሙከራዎች በኋላ የኢሜይል መለያ ተጠቅመው ስልክዎን እንዲከፍቱ ይጠየቃሉ።\n\nእባክዎ ከ<xliff:g id="NUMBER_2">%3$d</xliff:g> ሰከንዶች በኋላ እንደገና ይሞክሩ።"</string>
- <!-- no translation found for global_action_lock_message (7092460751050168771) -->
- <skip />
- <!-- no translation found for global_action_lock_message (1024230056230539493) -->
- <skip />
- <!-- no translation found for global_action_lock_message (3165224897120346096) -->
- <skip />
+ <string name="global_action_lock_message" product="default" msgid="7092460751050168771">"ለተጨማሪ አማራጮች የእርስዎን ስልክ ይክፈቱ"</string>
+ <string name="global_action_lock_message" product="tablet" msgid="1024230056230539493">"ለተጨማሪ አማራጮች የእርስዎን ጡባዊ ይክፈቱ"</string>
+ <string name="global_action_lock_message" product="device" msgid="3165224897120346096">"ለተጨማሪ አማራጮች የእርስዎን መሣሪያ ይክፈቱ"</string>
</resources>
diff --git a/packages/SystemUI/res-product/values-ar/strings.xml b/packages/SystemUI/res-product/values-ar/strings.xml
index 8e56636a5fd6..a13136fbd1e2 100644
--- a/packages/SystemUI/res-product/values-ar/strings.xml
+++ b/packages/SystemUI/res-product/values-ar/strings.xml
@@ -40,10 +40,7 @@
<string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4682221342671290678">"أخطأت في محاولة فتح قفل الهاتف <xliff:g id="NUMBER">%d</xliff:g> مرة. ستتم إزالة الملف الشخصي للعمل، ومن ثم يتم حذف جميع بياناته."</string>
<string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="1860049973474855672">"رسمت نقش فتح القفل بشكل غير صحيح <xliff:g id="NUMBER_0">%1$d</xliff:g> مرة. بعد إجراء <xliff:g id="NUMBER_1">%2$d</xliff:g> محاولة غير ناجحة أخرى، ستُطالَب بفتح قفل الجهاز اللوحي باستخدام معلومات حساب بريد إلكتروني.\n\n يُرجى إعادة المحاولة خلال <xliff:g id="NUMBER_2">%3$d</xliff:g> ثانية."</string>
<string name="kg_failed_attempts_almost_at_login" product="default" msgid="44112553371516141">"رسمت نقش فتح القفل بشكل غير صحيح <xliff:g id="NUMBER_0">%1$d</xliff:g> مرة. بعد إجراء <xliff:g id="NUMBER_1">%2$d</xliff:g> محاولة غير ناجحة أخرى، ستُطالَب بفتح قفل الهاتف باستخدام حساب بريد إلكتروني.\n\n يُرجى إعادة المحاولة خلال <xliff:g id="NUMBER_2">%3$d</xliff:g> ثانية."</string>
- <!-- no translation found for global_action_lock_message (7092460751050168771) -->
- <skip />
- <!-- no translation found for global_action_lock_message (1024230056230539493) -->
- <skip />
- <!-- no translation found for global_action_lock_message (3165224897120346096) -->
- <skip />
+ <string name="global_action_lock_message" product="default" msgid="7092460751050168771">"يمكنك فتح قفل هاتفك للوصول إلى مزيد من الخيارات."</string>
+ <string name="global_action_lock_message" product="tablet" msgid="1024230056230539493">"يمكنك فتح قفل جهازك اللوحي للوصول إلى مزيد من الخيارات."</string>
+ <string name="global_action_lock_message" product="device" msgid="3165224897120346096">"يمكنك فتح قفل جهازك للوصول إلى مزيد من الخيارات."</string>
</resources>
diff --git a/packages/SystemUI/res-product/values-as/strings.xml b/packages/SystemUI/res-product/values-as/strings.xml
index a6a35f398e3b..c3e965c8d316 100644
--- a/packages/SystemUI/res-product/values-as/strings.xml
+++ b/packages/SystemUI/res-product/values-as/strings.xml
@@ -40,10 +40,7 @@
<string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4682221342671290678">"আপুনি ফ’নটো আনলক কৰিবলৈ <xliff:g id="NUMBER">%d</xliff:g> বাৰ ভুলকৈ প্ৰয়াস কৰিছে। কৰ্মস্থানৰ প্ৰ’ফাইলটো আঁতৰোৱা হ’ব, যিয়ে প্ৰ’ফাইলটোৰ সকলো ডেটা মচি পেলাব।"</string>
<string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="1860049973474855672">"আপুনি নিজৰ আনলক কৰা আৰ্হিটো <xliff:g id="NUMBER_0">%1$d</xliff:g> বাৰ ভুলকৈ আঁকিছে। আৰু <xliff:g id="NUMBER_1">%2$d</xliff:g> বাৰ ভুলকৈ প্ৰয়াস কৰাৰ পাছত আপোনাক নিজৰ টেবলেটটো এটা ইমেইল একাউণ্টৰ জৰিয়তে আনলক কৰিবলৈ কোৱা হ’ব।\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> ছেকেণ্ডৰ পাছত পুনৰ চেষ্টা কৰক।"</string>
<string name="kg_failed_attempts_almost_at_login" product="default" msgid="44112553371516141">"আপুনি নিজৰ আনলক কৰা আৰ্হিটো <xliff:g id="NUMBER_0">%1$d</xliff:g> বাৰ ভুলকৈ আঁকিছে। আৰু <xliff:g id="NUMBER_1">%2$d</xliff:g> বাৰ ভুলকৈ প্ৰয়াস কৰাৰ পাছত আপোনাক নিজৰ ফ’নটো এটা ইমেইল একাউণ্টৰ জৰিয়তে আনলক কৰিবলৈ কোৱা হ’ব।\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> ছেকেণ্ডৰ পাছত পুনৰ চেষ্টা কৰক।"</string>
- <!-- no translation found for global_action_lock_message (7092460751050168771) -->
- <skip />
- <!-- no translation found for global_action_lock_message (1024230056230539493) -->
- <skip />
- <!-- no translation found for global_action_lock_message (3165224897120346096) -->
- <skip />
+ <string name="global_action_lock_message" product="default" msgid="7092460751050168771">"অধিক বিকল্পৰ বাবে আপোনাৰ ফ’নটো আনলক কৰক"</string>
+ <string name="global_action_lock_message" product="tablet" msgid="1024230056230539493">"অধিক বিকল্পৰ বাবে আপোনাৰ টেবলেটটো আনলক কৰক"</string>
+ <string name="global_action_lock_message" product="device" msgid="3165224897120346096">"অধিক বিকল্পৰ বাবে আপোনাৰ ডিভাইচটো আনলক কৰক"</string>
</resources>
diff --git a/packages/SystemUI/res-product/values-az/strings.xml b/packages/SystemUI/res-product/values-az/strings.xml
index 1db1503525e9..ee86ae23d48f 100644
--- a/packages/SystemUI/res-product/values-az/strings.xml
+++ b/packages/SystemUI/res-product/values-az/strings.xml
@@ -40,10 +40,7 @@
<string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4682221342671290678">"Telefonun kilidini açmaq üçün <xliff:g id="NUMBER">%d</xliff:g> dəfə yanlış cəhd etmisiniz. İş profili silinəcək və bütün data ləğv ediləcək."</string>
<string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="1860049973474855672">"Kilid açma modelini <xliff:g id="NUMBER_0">%1$d</xliff:g> dəfə yanlış çəkmisiniz. Daha <xliff:g id="NUMBER_1">%2$d</xliff:g> uğursuz cəhddən sonra planşet kilidini e-poçt hesabınızla açmaq tələb olunacaq.\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> saniyə sonra yenidən cəhd edin."</string>
<string name="kg_failed_attempts_almost_at_login" product="default" msgid="44112553371516141">"Kilid açma modelini artıq <xliff:g id="NUMBER_0">%1$d</xliff:g> dəfə yanlış çəkmisiniz. Daha <xliff:g id="NUMBER_1">%2$d</xliff:g> uğursuz cəhddən sonra telefon kilidini e-poçt hesabınızla açmaq tələb olunacaq.\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> saniyə sonra yenidən cəhd edin."</string>
- <!-- no translation found for global_action_lock_message (7092460751050168771) -->
- <skip />
- <!-- no translation found for global_action_lock_message (1024230056230539493) -->
- <skip />
- <!-- no translation found for global_action_lock_message (3165224897120346096) -->
- <skip />
+ <string name="global_action_lock_message" product="default" msgid="7092460751050168771">"Daha çox seçim üçün telefonu kiliddən çıxarın"</string>
+ <string name="global_action_lock_message" product="tablet" msgid="1024230056230539493">"Daha çox seçim üçün planşeti kiliddən çıxarın"</string>
+ <string name="global_action_lock_message" product="device" msgid="3165224897120346096">"Daha çox seçim üçün cihazı kiliddən çıxarın"</string>
</resources>
diff --git a/packages/SystemUI/res-product/values-b+sr+Latn/strings.xml b/packages/SystemUI/res-product/values-b+sr+Latn/strings.xml
index 3a2482607fd6..7a27dd0fd9b6 100644
--- a/packages/SystemUI/res-product/values-b+sr+Latn/strings.xml
+++ b/packages/SystemUI/res-product/values-b+sr+Latn/strings.xml
@@ -40,10 +40,7 @@
<string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4682221342671290678">"Pogrešno ste pokušali da otključate telefon <xliff:g id="NUMBER">%d</xliff:g> puta. Uklonićemo poslovni profil, čime se brišu svi podaci sa profila."</string>
<string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="1860049973474855672">"Netačno ste nacrtali šablon za otključavanje <xliff:g id="NUMBER_0">%1$d</xliff:g> puta. Ako pogrešno pokušate još <xliff:g id="NUMBER_1">%2$d</xliff:g> puta, zatražićemo da otključate tablet pomoću imejl naloga.\n\n Probajte ponovo za <xliff:g id="NUMBER_2">%3$d</xliff:g> sek."</string>
<string name="kg_failed_attempts_almost_at_login" product="default" msgid="44112553371516141">"Netačno ste nacrtali šablon za otključavanje <xliff:g id="NUMBER_0">%1$d</xliff:g> puta. Ako pogrešno pokušate još <xliff:g id="NUMBER_1">%2$d</xliff:g> puta, zatražićemo da otključate telefon pomoću imejl naloga.\n\n Probajte ponovo za <xliff:g id="NUMBER_2">%3$d</xliff:g> sek."</string>
- <!-- no translation found for global_action_lock_message (7092460751050168771) -->
- <skip />
- <!-- no translation found for global_action_lock_message (1024230056230539493) -->
- <skip />
- <!-- no translation found for global_action_lock_message (3165224897120346096) -->
- <skip />
+ <string name="global_action_lock_message" product="default" msgid="7092460751050168771">"Otključajte telefon za još opcija"</string>
+ <string name="global_action_lock_message" product="tablet" msgid="1024230056230539493">"Otključajte tablet za još opcija"</string>
+ <string name="global_action_lock_message" product="device" msgid="3165224897120346096">"Otključajte uređaj za još opcija"</string>
</resources>
diff --git a/packages/SystemUI/res-product/values-be/strings.xml b/packages/SystemUI/res-product/values-be/strings.xml
index a1b941fc6978..4fd7cc047246 100644
--- a/packages/SystemUI/res-product/values-be/strings.xml
+++ b/packages/SystemUI/res-product/values-be/strings.xml
@@ -40,10 +40,7 @@
<string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4682221342671290678">"Вы не змаглі разблакіраваць тэлефон столькі разоў: <xliff:g id="NUMBER">%d</xliff:g>. Працоўны профіль будзе выдалены, і гэта прывядзе да выдалення ўсіх даных у профілі."</string>
<string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="1860049973474855672">"Вы няправільна ўвялі ўзор разблакіроўкі столькі разоў: <xliff:g id="NUMBER_0">%1$d</xliff:g>. Пасля яшчэ некалькіх няўдалых спроб (<xliff:g id="NUMBER_1">%2$d</xliff:g>) вам будзе прапанавана разблакіраваць планшэт, увайшоўшы ва ўліковы запіс электроннай пошты.\n\n Паўтарыце спробу праз <xliff:g id="NUMBER_2">%3$d</xliff:g> с."</string>
<string name="kg_failed_attempts_almost_at_login" product="default" msgid="44112553371516141">"Вы няправільна ўвялі ўзор разблакіроўкі столькі разоў: <xliff:g id="NUMBER_0">%1$d</xliff:g>. Пасля яшчэ некалькіх няўдалых спроб (<xliff:g id="NUMBER_1">%2$d</xliff:g>) вам будзе прапанавана разблакіраваць тэлефон, увайшоўшы ва ўліковы запіс электроннай пошты.\n\n Паўтарыце спробу праз <xliff:g id="NUMBER_2">%3$d</xliff:g> с."</string>
- <!-- no translation found for global_action_lock_message (7092460751050168771) -->
- <skip />
- <!-- no translation found for global_action_lock_message (1024230056230539493) -->
- <skip />
- <!-- no translation found for global_action_lock_message (3165224897120346096) -->
- <skip />
+ <string name="global_action_lock_message" product="default" msgid="7092460751050168771">"Каб адкрыць іншыя параметры, разблакіруйце тэлефон"</string>
+ <string name="global_action_lock_message" product="tablet" msgid="1024230056230539493">"Каб адкрыць іншыя параметры, разблакіруйце планшэт"</string>
+ <string name="global_action_lock_message" product="device" msgid="3165224897120346096">"Каб адкрыць іншыя параметры, разблакіруйце прыладу"</string>
</resources>
diff --git a/packages/SystemUI/res-product/values-bg/strings.xml b/packages/SystemUI/res-product/values-bg/strings.xml
index cce012e2bf8a..cfdab241f45f 100644
--- a/packages/SystemUI/res-product/values-bg/strings.xml
+++ b/packages/SystemUI/res-product/values-bg/strings.xml
@@ -40,10 +40,7 @@
<string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4682221342671290678">"Опитахте да отключите телефона и сбъркахте <xliff:g id="NUMBER">%d</xliff:g> пъти. Служебният потребителски профил ще бъде премахнат, при което ще се изтрият всички данни за него."</string>
<string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="1860049973474855672">"Начертахте неправилно фигурата си за отключване <xliff:g id="NUMBER_0">%1$d</xliff:g> пъти. След още <xliff:g id="NUMBER_1">%2$d</xliff:g> неуспешни опита ще бъдете помолени да отключите таблета си посредством имейл адрес.\n\n Опитайте отново след <xliff:g id="NUMBER_2">%3$d</xliff:g> секунди."</string>
<string name="kg_failed_attempts_almost_at_login" product="default" msgid="44112553371516141">"Начертахте неправилно фигурата си за отключване <xliff:g id="NUMBER_0">%1$d</xliff:g> пъти. След още <xliff:g id="NUMBER_1">%2$d</xliff:g> неуспешни опита ще бъдете помолени да отключите телефона посредством имейл адрес.\n\n Опитайте отново след <xliff:g id="NUMBER_2">%3$d</xliff:g> секунди."</string>
- <!-- no translation found for global_action_lock_message (7092460751050168771) -->
- <skip />
- <!-- no translation found for global_action_lock_message (1024230056230539493) -->
- <skip />
- <!-- no translation found for global_action_lock_message (3165224897120346096) -->
- <skip />
+ <string name="global_action_lock_message" product="default" msgid="7092460751050168771">"Отключете телефона си за още опции"</string>
+ <string name="global_action_lock_message" product="tablet" msgid="1024230056230539493">"Отключете таблета си за още опции"</string>
+ <string name="global_action_lock_message" product="device" msgid="3165224897120346096">"Отключете устройството си за още опции"</string>
</resources>
diff --git a/packages/SystemUI/res-product/values-bn/strings.xml b/packages/SystemUI/res-product/values-bn/strings.xml
index 8c36fcb088e9..214dd45040fc 100644
--- a/packages/SystemUI/res-product/values-bn/strings.xml
+++ b/packages/SystemUI/res-product/values-bn/strings.xml
@@ -40,10 +40,7 @@
<string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4682221342671290678">"আপনি <xliff:g id="NUMBER">%d</xliff:g> বার ভুল পদ্ধতিতে ফোন আনলক করার চেষ্টা করেছেন। অফিস প্রোফাইলটি সরিয়ে দেওয়া হবে, যার ফলে প্রোফাইলের সমস্ত ডেটা মুছে যাবে।"</string>
<string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="1860049973474855672">"আপনি <xliff:g id="NUMBER_0">%1$d</xliff:g> বার ভুল পদ্ধতিতে প্যাটার্ন আনলক করার চেষ্টা করেছেন। আরও <xliff:g id="NUMBER_1">%2$d</xliff:g> বার এটি করলে আপনাকে প্যাটার্ন আনলক করতে একটি ইমেল অ্যাকাউন্ট ব্যবহার করতে বলা হবে।\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> সেকেন্ড পরে আবার চেষ্টা করুন।"</string>
<string name="kg_failed_attempts_almost_at_login" product="default" msgid="44112553371516141">"আপনি <xliff:g id="NUMBER_0">%1$d</xliff:g> বার ভুল পদ্ধতিতে প্যাটার্ন আনলক করার চেষ্টা করেছেন। আরও <xliff:g id="NUMBER_1">%2$d</xliff:g> বার এটি করলে আপনাকে প্যাটার্ন আনলক করতে একটি ইমেল অ্যাকাউন্ট ব্যবহারের করতে বলা হবে।\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> সেকেন্ড পরে আবার চেষ্টা করুন।"</string>
- <!-- no translation found for global_action_lock_message (7092460751050168771) -->
- <skip />
- <!-- no translation found for global_action_lock_message (1024230056230539493) -->
- <skip />
- <!-- no translation found for global_action_lock_message (3165224897120346096) -->
- <skip />
+ <string name="global_action_lock_message" product="default" msgid="7092460751050168771">"আরও বিকল্প দেখতে আপনার ফোন আনলক করুন"</string>
+ <string name="global_action_lock_message" product="tablet" msgid="1024230056230539493">"আরও বিকল্প দেখতে আপনার ট্যাবলেট আনলক করুন"</string>
+ <string name="global_action_lock_message" product="device" msgid="3165224897120346096">"আরও বিকল্প দেখতে আপনার ডিভাইস আনলক করুন"</string>
</resources>
diff --git a/packages/SystemUI/res-product/values-bs/strings.xml b/packages/SystemUI/res-product/values-bs/strings.xml
index c512f5580ad2..ed5caae511fa 100644
--- a/packages/SystemUI/res-product/values-bs/strings.xml
+++ b/packages/SystemUI/res-product/values-bs/strings.xml
@@ -40,10 +40,7 @@
<string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4682221342671290678">"Pokušali ste neispravno otključati telefon <xliff:g id="NUMBER">%d</xliff:g> puta. Radni profil će se ukloniti i svi podaci s profila će se izbrisati."</string>
<string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="1860049973474855672">"Pogrešno ste nacrtali uzorak za otključavanje <xliff:g id="NUMBER_0">%1$d</xliff:g> puta. U slučaju još <xliff:g id="NUMBER_1">%2$d</xliff:g> pokušaja bez uspjeha, od vas će se tražiti da otključate tablet pomoću računa e-pošte. \n\n Pokušajte ponovo za <xliff:g id="NUMBER_2">%3$d</xliff:g> s."</string>
<string name="kg_failed_attempts_almost_at_login" product="default" msgid="44112553371516141">"Pogrešno ste nacrtali uzorak za otključavanje <xliff:g id="NUMBER_0">%1$d</xliff:g> puta. U slučaju još <xliff:g id="NUMBER_1">%2$d</xliff:g> pokušaja bez uspjeha, od vas će se tražiti da otključate telefon pomoću računa e-pošte. \n\n Pokušajte ponovo za <xliff:g id="NUMBER_2">%3$d</xliff:g> s."</string>
- <!-- no translation found for global_action_lock_message (7092460751050168771) -->
- <skip />
- <!-- no translation found for global_action_lock_message (1024230056230539493) -->
- <skip />
- <!-- no translation found for global_action_lock_message (3165224897120346096) -->
- <skip />
+ <string name="global_action_lock_message" product="default" msgid="7092460751050168771">"Otključajte telefon za više opcija"</string>
+ <string name="global_action_lock_message" product="tablet" msgid="1024230056230539493">"Otključajte tablet za više opcija"</string>
+ <string name="global_action_lock_message" product="device" msgid="3165224897120346096">"Otključajte uređaj za više opcija"</string>
</resources>
diff --git a/packages/SystemUI/res-product/values-ca/strings.xml b/packages/SystemUI/res-product/values-ca/strings.xml
index 5bb73e44f2f7..44417927a1dd 100644
--- a/packages/SystemUI/res-product/values-ca/strings.xml
+++ b/packages/SystemUI/res-product/values-ca/strings.xml
@@ -40,10 +40,7 @@
<string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4682221342671290678">"Has provat de desbloquejar el telèfon <xliff:g id="NUMBER">%d</xliff:g> vegades de manera incorrecta. El perfil de treball se suprimirà, juntament amb totes les dades que contingui."</string>
<string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="1860049973474855672">"Has dibuixat el patró de desbloqueig <xliff:g id="NUMBER_0">%1$d</xliff:g> vegades de manera incorrecta. Si falles <xliff:g id="NUMBER_1">%2$d</xliff:g> vegades més, se\'t demanarà que desbloquegis la tauleta amb un compte de correu electrònic.\n\n Torna-ho a provar d\'aquí a <xliff:g id="NUMBER_2">%3$d</xliff:g> segons."</string>
<string name="kg_failed_attempts_almost_at_login" product="default" msgid="44112553371516141">"Has dibuixat el patró de desbloqueig <xliff:g id="NUMBER_0">%1$d</xliff:g> vegades de manera incorrecta. Si falles <xliff:g id="NUMBER_1">%2$d</xliff:g> vegades més, se\'t demanarà que desbloquegis el telèfon amb un compte de correu electrònic.\n\n Torna-ho a provar d\'aquí a <xliff:g id="NUMBER_2">%3$d</xliff:g> segons."</string>
- <!-- no translation found for global_action_lock_message (7092460751050168771) -->
- <skip />
- <!-- no translation found for global_action_lock_message (1024230056230539493) -->
- <skip />
- <!-- no translation found for global_action_lock_message (3165224897120346096) -->
- <skip />
+ <string name="global_action_lock_message" product="default" msgid="7092460751050168771">"Desbloqueja el teu telèfon per veure més opcions"</string>
+ <string name="global_action_lock_message" product="tablet" msgid="1024230056230539493">"Desbloqueja la teva tauleta per veure més opcions"</string>
+ <string name="global_action_lock_message" product="device" msgid="3165224897120346096">"Desbloqueja el teu dispositiu per veure més opcions"</string>
</resources>
diff --git a/packages/SystemUI/res-product/values-cs/strings.xml b/packages/SystemUI/res-product/values-cs/strings.xml
index bd0b66a99591..aa6ba7212e9c 100644
--- a/packages/SystemUI/res-product/values-cs/strings.xml
+++ b/packages/SystemUI/res-product/values-cs/strings.xml
@@ -40,10 +40,7 @@
<string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4682221342671290678">"Již <xliff:g id="NUMBER">%d</xliff:g>krát jste se pokusili odemknout telefon nesprávným způsobem. Pracovní profil bude odstraněn, čímž budou smazána všechna jeho data."</string>
<string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="1860049973474855672">"Již <xliff:g id="NUMBER_0">%1$d</xliff:g>krát jste nesprávně zadali své bezpečnostní gesto. Po <xliff:g id="NUMBER_1">%2$d</xliff:g>dalších neúspěšných pokusech budete požádáni o odemčení tabletu pomocí e-mailového účtu.\n\n Zkuste to znovu za <xliff:g id="NUMBER_2">%3$d</xliff:g> s."</string>
<string name="kg_failed_attempts_almost_at_login" product="default" msgid="44112553371516141">"Již <xliff:g id="NUMBER_0">%1$d</xliff:g>krát jste nesprávně zadali své bezpečnostní gesto. Po <xliff:g id="NUMBER_1">%2$d</xliff:g> dalších neúspěšných pokusech budete požádáni o odemčení telefonu pomocí e-mailového účtu.\n\n Zkuste to znovu za <xliff:g id="NUMBER_2">%3$d</xliff:g> s."</string>
- <!-- no translation found for global_action_lock_message (7092460751050168771) -->
- <skip />
- <!-- no translation found for global_action_lock_message (1024230056230539493) -->
- <skip />
- <!-- no translation found for global_action_lock_message (3165224897120346096) -->
- <skip />
+ <string name="global_action_lock_message" product="default" msgid="7092460751050168771">"Chcete-li zobrazit další možnosti, odemkněte telefon"</string>
+ <string name="global_action_lock_message" product="tablet" msgid="1024230056230539493">"Chcete-li zobrazit další možnosti, odemkněte tablet"</string>
+ <string name="global_action_lock_message" product="device" msgid="3165224897120346096">"Chcete-li zobrazit další možnosti, odemkněte zařízení"</string>
</resources>
diff --git a/packages/SystemUI/res-product/values-da/strings.xml b/packages/SystemUI/res-product/values-da/strings.xml
index 7777bd5881e9..5b2112ec7d70 100644
--- a/packages/SystemUI/res-product/values-da/strings.xml
+++ b/packages/SystemUI/res-product/values-da/strings.xml
@@ -40,10 +40,7 @@
<string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4682221342671290678">"Du har forsøgt at låse telefonen op med den forkerte adgangskode <xliff:g id="NUMBER">%d</xliff:g> gange. Arbejdsprofilen fjernes, hvilket sletter alle profildata."</string>
<string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="1860049973474855672">"Du har tegnet dit oplåsningsmønster forkert <xliff:g id="NUMBER_0">%1$d</xliff:g> gange. Efter endnu <xliff:g id="NUMBER_1">%2$d</xliff:g> mislykkede forsøg bliver du bedt om at låse din tablet op ved hjælp af en mailkonto.\n\n Prøv igen om <xliff:g id="NUMBER_2">%3$d</xliff:g> sekunder."</string>
<string name="kg_failed_attempts_almost_at_login" product="default" msgid="44112553371516141">"Du har tegnet dit oplåsningsmønster forkert <xliff:g id="NUMBER_0">%1$d</xliff:g> gange. Efter endnu <xliff:g id="NUMBER_1">%2$d</xliff:g> mislykkede forsøg bliver du bedt om at låse din telefon op ved hjælp af en mailkonto.\n\n Prøv igen om <xliff:g id="NUMBER_2">%3$d</xliff:g> sekunder."</string>
- <!-- no translation found for global_action_lock_message (7092460751050168771) -->
- <skip />
- <!-- no translation found for global_action_lock_message (1024230056230539493) -->
- <skip />
- <!-- no translation found for global_action_lock_message (3165224897120346096) -->
- <skip />
+ <string name="global_action_lock_message" product="default" msgid="7092460751050168771">"Lås din telefon op for at se flere valgmuligheder"</string>
+ <string name="global_action_lock_message" product="tablet" msgid="1024230056230539493">"Lås din tablet op for at se flere valgmuligheder"</string>
+ <string name="global_action_lock_message" product="device" msgid="3165224897120346096">"Lås din enhed op for at se flere valgmuligheder"</string>
</resources>
diff --git a/packages/SystemUI/res-product/values-de/strings.xml b/packages/SystemUI/res-product/values-de/strings.xml
index 78b902324a0b..5c8f842fa2d3 100644
--- a/packages/SystemUI/res-product/values-de/strings.xml
+++ b/packages/SystemUI/res-product/values-de/strings.xml
@@ -40,10 +40,7 @@
<string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4682221342671290678">"Du hast <xliff:g id="NUMBER">%d</xliff:g>-mal erfolglos versucht, das Smartphone zu entsperren. Das Arbeitsprofil wird nun entfernt und alle Profildaten werden gelöscht."</string>
<string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="1860049973474855672">"Du hast dein Entsperrungsmuster <xliff:g id="NUMBER_0">%1$d</xliff:g>-mal falsch gezeichnet. Nach <xliff:g id="NUMBER_1">%2$d</xliff:g> weiteren erfolglosen Versuchen wirst du aufgefordert, dein Tablet mithilfe eines E-Mail-Kontos zu entsperren.\n\n Versuche es in <xliff:g id="NUMBER_2">%3$d</xliff:g> Sekunden noch einmal."</string>
<string name="kg_failed_attempts_almost_at_login" product="default" msgid="44112553371516141">"Du hast dein Entsperrungsmuster <xliff:g id="NUMBER_0">%1$d</xliff:g>-mal falsch gezeichnet. Nach <xliff:g id="NUMBER_1">%2$d</xliff:g> weiteren erfolglosen Versuchen wirst du aufgefordert, dein Smartphone mithilfe eines E-Mail-Kontos zu entsperren.\n\n Versuche es in <xliff:g id="NUMBER_2">%3$d</xliff:g> Sekunden noch einmal."</string>
- <!-- no translation found for global_action_lock_message (7092460751050168771) -->
- <skip />
- <!-- no translation found for global_action_lock_message (1024230056230539493) -->
- <skip />
- <!-- no translation found for global_action_lock_message (3165224897120346096) -->
- <skip />
+ <string name="global_action_lock_message" product="default" msgid="7092460751050168771">"Entsperre dein Smartphone für weitere Optionen"</string>
+ <string name="global_action_lock_message" product="tablet" msgid="1024230056230539493">"Entsperre dein Tablet für weitere Optionen"</string>
+ <string name="global_action_lock_message" product="device" msgid="3165224897120346096">"Entsperre dein Gerät für weitere Optionen"</string>
</resources>
diff --git a/packages/SystemUI/res-product/values-el/strings.xml b/packages/SystemUI/res-product/values-el/strings.xml
index 9eb7307c0399..8dd9ec25ccb1 100644
--- a/packages/SystemUI/res-product/values-el/strings.xml
+++ b/packages/SystemUI/res-product/values-el/strings.xml
@@ -40,10 +40,7 @@
<string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4682221342671290678">"Δοκιμάσατε να ξεκλειδώσετε το τηλέφωνο <xliff:g id="NUMBER">%d</xliff:g> φορές χωρίς επιτυχία. Το προφίλ εργασίας θα καταργηθεί και θα διαγραφούν όλα τα δεδομένα προφίλ."</string>
<string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="1860049973474855672">"Σχεδιάσατε το μοτίβο ξεκλειδώματος εσφαλμένα <xliff:g id="NUMBER_0">%1$d</xliff:g> φορές. Μετά από <xliff:g id="NUMBER_1">%2$d</xliff:g> ακόμα ανεπιτυχείς προσπάθειες, θα σας ζητηθεί να ξεκλειδώσετε το tablet με τη χρήση ενός λογαριασμού ηλεκτρονικού ταχυδρομείου.\n\n Δοκιμάστε να συνδεθείτε ξανά σε <xliff:g id="NUMBER_2">%3$d</xliff:g> δευτερόλεπτα."</string>
<string name="kg_failed_attempts_almost_at_login" product="default" msgid="44112553371516141">"Σχεδιάσατε το μοτίβο ξεκλειδώματος εσφαλμένα <xliff:g id="NUMBER_0">%1$d</xliff:g> φορές. Μετά από <xliff:g id="NUMBER_1">%2$d</xliff:g> ακόμα ανεπιτυχείς προσπάθειες, θα σας ζητηθεί να ξεκλειδώσετε το τηλέφωνό σας με τη χρήση ενός λογαριασμού ηλεκτρονικού ταχυδρομείου.\n\n Δοκιμάστε ξανά σε <xliff:g id="NUMBER_2">%3$d</xliff:g> δευτερόλεπτα."</string>
- <!-- no translation found for global_action_lock_message (7092460751050168771) -->
- <skip />
- <!-- no translation found for global_action_lock_message (1024230056230539493) -->
- <skip />
- <!-- no translation found for global_action_lock_message (3165224897120346096) -->
- <skip />
+ <string name="global_action_lock_message" product="default" msgid="7092460751050168771">"Ξεκλειδώστε το τηλέφωνό σας για περισσότερες επιλογές"</string>
+ <string name="global_action_lock_message" product="tablet" msgid="1024230056230539493">"Ξεκλειδώστε το tablet για περισσότερες επιλογές"</string>
+ <string name="global_action_lock_message" product="device" msgid="3165224897120346096">"Ξεκλειδώστε τη συσκευή σας για περισσότερες επιλογές"</string>
</resources>
diff --git a/packages/SystemUI/res-product/values-en-rAU/strings.xml b/packages/SystemUI/res-product/values-en-rAU/strings.xml
index c0a535ce5f4b..3de7b654ead0 100644
--- a/packages/SystemUI/res-product/values-en-rAU/strings.xml
+++ b/packages/SystemUI/res-product/values-en-rAU/strings.xml
@@ -40,10 +40,7 @@
<string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4682221342671290678">"You have incorrectly attempted to unlock the phone <xliff:g id="NUMBER">%d</xliff:g> times. The work profile will be removed, which will delete all profile data."</string>
<string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="1860049973474855672">"You have incorrectly drawn your unlock pattern <xliff:g id="NUMBER_0">%1$d</xliff:g> times. After <xliff:g id="NUMBER_1">%2$d</xliff:g> more unsuccessful attempts, you will be asked to unlock your tablet using an email account.\n\n Try again in <xliff:g id="NUMBER_2">%3$d</xliff:g> seconds."</string>
<string name="kg_failed_attempts_almost_at_login" product="default" msgid="44112553371516141">"You have incorrectly drawn your unlock pattern <xliff:g id="NUMBER_0">%1$d</xliff:g> times. After <xliff:g id="NUMBER_1">%2$d</xliff:g> more unsuccessful attempts, you will be asked to unlock your phone using an email account.\n\n Try again in <xliff:g id="NUMBER_2">%3$d</xliff:g> seconds."</string>
- <!-- no translation found for global_action_lock_message (7092460751050168771) -->
- <skip />
- <!-- no translation found for global_action_lock_message (1024230056230539493) -->
- <skip />
- <!-- no translation found for global_action_lock_message (3165224897120346096) -->
- <skip />
+ <string name="global_action_lock_message" product="default" msgid="7092460751050168771">"Unlock your phone for more options"</string>
+ <string name="global_action_lock_message" product="tablet" msgid="1024230056230539493">"Unlock your tablet for more options"</string>
+ <string name="global_action_lock_message" product="device" msgid="3165224897120346096">"Unlock your device for more options"</string>
</resources>
diff --git a/packages/SystemUI/res-product/values-en-rCA/strings.xml b/packages/SystemUI/res-product/values-en-rCA/strings.xml
index c0a535ce5f4b..3de7b654ead0 100644
--- a/packages/SystemUI/res-product/values-en-rCA/strings.xml
+++ b/packages/SystemUI/res-product/values-en-rCA/strings.xml
@@ -40,10 +40,7 @@
<string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4682221342671290678">"You have incorrectly attempted to unlock the phone <xliff:g id="NUMBER">%d</xliff:g> times. The work profile will be removed, which will delete all profile data."</string>
<string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="1860049973474855672">"You have incorrectly drawn your unlock pattern <xliff:g id="NUMBER_0">%1$d</xliff:g> times. After <xliff:g id="NUMBER_1">%2$d</xliff:g> more unsuccessful attempts, you will be asked to unlock your tablet using an email account.\n\n Try again in <xliff:g id="NUMBER_2">%3$d</xliff:g> seconds."</string>
<string name="kg_failed_attempts_almost_at_login" product="default" msgid="44112553371516141">"You have incorrectly drawn your unlock pattern <xliff:g id="NUMBER_0">%1$d</xliff:g> times. After <xliff:g id="NUMBER_1">%2$d</xliff:g> more unsuccessful attempts, you will be asked to unlock your phone using an email account.\n\n Try again in <xliff:g id="NUMBER_2">%3$d</xliff:g> seconds."</string>
- <!-- no translation found for global_action_lock_message (7092460751050168771) -->
- <skip />
- <!-- no translation found for global_action_lock_message (1024230056230539493) -->
- <skip />
- <!-- no translation found for global_action_lock_message (3165224897120346096) -->
- <skip />
+ <string name="global_action_lock_message" product="default" msgid="7092460751050168771">"Unlock your phone for more options"</string>
+ <string name="global_action_lock_message" product="tablet" msgid="1024230056230539493">"Unlock your tablet for more options"</string>
+ <string name="global_action_lock_message" product="device" msgid="3165224897120346096">"Unlock your device for more options"</string>
</resources>
diff --git a/packages/SystemUI/res-product/values-en-rGB/strings.xml b/packages/SystemUI/res-product/values-en-rGB/strings.xml
index c0a535ce5f4b..3de7b654ead0 100644
--- a/packages/SystemUI/res-product/values-en-rGB/strings.xml
+++ b/packages/SystemUI/res-product/values-en-rGB/strings.xml
@@ -40,10 +40,7 @@
<string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4682221342671290678">"You have incorrectly attempted to unlock the phone <xliff:g id="NUMBER">%d</xliff:g> times. The work profile will be removed, which will delete all profile data."</string>
<string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="1860049973474855672">"You have incorrectly drawn your unlock pattern <xliff:g id="NUMBER_0">%1$d</xliff:g> times. After <xliff:g id="NUMBER_1">%2$d</xliff:g> more unsuccessful attempts, you will be asked to unlock your tablet using an email account.\n\n Try again in <xliff:g id="NUMBER_2">%3$d</xliff:g> seconds."</string>
<string name="kg_failed_attempts_almost_at_login" product="default" msgid="44112553371516141">"You have incorrectly drawn your unlock pattern <xliff:g id="NUMBER_0">%1$d</xliff:g> times. After <xliff:g id="NUMBER_1">%2$d</xliff:g> more unsuccessful attempts, you will be asked to unlock your phone using an email account.\n\n Try again in <xliff:g id="NUMBER_2">%3$d</xliff:g> seconds."</string>
- <!-- no translation found for global_action_lock_message (7092460751050168771) -->
- <skip />
- <!-- no translation found for global_action_lock_message (1024230056230539493) -->
- <skip />
- <!-- no translation found for global_action_lock_message (3165224897120346096) -->
- <skip />
+ <string name="global_action_lock_message" product="default" msgid="7092460751050168771">"Unlock your phone for more options"</string>
+ <string name="global_action_lock_message" product="tablet" msgid="1024230056230539493">"Unlock your tablet for more options"</string>
+ <string name="global_action_lock_message" product="device" msgid="3165224897120346096">"Unlock your device for more options"</string>
</resources>
diff --git a/packages/SystemUI/res-product/values-en-rIN/strings.xml b/packages/SystemUI/res-product/values-en-rIN/strings.xml
index c0a535ce5f4b..3de7b654ead0 100644
--- a/packages/SystemUI/res-product/values-en-rIN/strings.xml
+++ b/packages/SystemUI/res-product/values-en-rIN/strings.xml
@@ -40,10 +40,7 @@
<string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4682221342671290678">"You have incorrectly attempted to unlock the phone <xliff:g id="NUMBER">%d</xliff:g> times. The work profile will be removed, which will delete all profile data."</string>
<string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="1860049973474855672">"You have incorrectly drawn your unlock pattern <xliff:g id="NUMBER_0">%1$d</xliff:g> times. After <xliff:g id="NUMBER_1">%2$d</xliff:g> more unsuccessful attempts, you will be asked to unlock your tablet using an email account.\n\n Try again in <xliff:g id="NUMBER_2">%3$d</xliff:g> seconds."</string>
<string name="kg_failed_attempts_almost_at_login" product="default" msgid="44112553371516141">"You have incorrectly drawn your unlock pattern <xliff:g id="NUMBER_0">%1$d</xliff:g> times. After <xliff:g id="NUMBER_1">%2$d</xliff:g> more unsuccessful attempts, you will be asked to unlock your phone using an email account.\n\n Try again in <xliff:g id="NUMBER_2">%3$d</xliff:g> seconds."</string>
- <!-- no translation found for global_action_lock_message (7092460751050168771) -->
- <skip />
- <!-- no translation found for global_action_lock_message (1024230056230539493) -->
- <skip />
- <!-- no translation found for global_action_lock_message (3165224897120346096) -->
- <skip />
+ <string name="global_action_lock_message" product="default" msgid="7092460751050168771">"Unlock your phone for more options"</string>
+ <string name="global_action_lock_message" product="tablet" msgid="1024230056230539493">"Unlock your tablet for more options"</string>
+ <string name="global_action_lock_message" product="device" msgid="3165224897120346096">"Unlock your device for more options"</string>
</resources>
diff --git a/packages/SystemUI/res-product/values-en-rXC/strings.xml b/packages/SystemUI/res-product/values-en-rXC/strings.xml
index 33a0e9da8871..022c5b390e7b 100644
--- a/packages/SystemUI/res-product/values-en-rXC/strings.xml
+++ b/packages/SystemUI/res-product/values-en-rXC/strings.xml
@@ -40,10 +40,7 @@
<string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4682221342671290678">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‎‎‎‎‏‏‏‏‏‎‏‎‏‎‎‏‎‏‏‏‏‎‎‎‎‎‎‎‏‏‏‏‎‎‎‏‏‎‏‎‏‏‎‎‏‏‎‎‎‎‎‏‎‎‏‏‎‏‏‎‎You have incorrectly attempted to unlock the phone ‎‏‎‎‏‏‎<xliff:g id="NUMBER">%d</xliff:g>‎‏‎‎‏‏‏‎ times. The work profile will be removed, which will delete all profile data.‎‏‎‎‏‎"</string>
<string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="1860049973474855672">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‏‎‎‏‏‏‎‏‎‎‎‎‎‎‏‏‏‎‎‏‏‎‎‏‏‎‎‎‏‎‎‎‏‏‎‏‎‏‏‏‎‎‎‏‏‎‎‎‏‎‏‎‏‏‏‏‏‎‎‎‎You have incorrectly drawn your unlock pattern ‎‏‎‎‏‏‎<xliff:g id="NUMBER_0">%1$d</xliff:g>‎‏‎‎‏‏‏‎ times. After ‎‏‎‎‏‏‎<xliff:g id="NUMBER_1">%2$d</xliff:g>‎‏‎‎‏‏‏‎ more unsuccessful attempts, you will be asked to unlock your tablet using an email account.‎‏‎‎‏‏‎\n‎‏‎‎‏‏‏‎‎‏‎‎‏‏‎\n‎‏‎‎‏‏‏‎ Try again in ‎‏‎‎‏‏‎<xliff:g id="NUMBER_2">%3$d</xliff:g>‎‏‎‎‏‏‏‎ seconds.‎‏‎‎‏‎"</string>
<string name="kg_failed_attempts_almost_at_login" product="default" msgid="44112553371516141">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‎‎‎‏‎‎‏‏‏‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‎‏‎‎‎‏‏‎‎‎‏‏‏‎‏‏‎‎‎‎‎‏‏‏‏‎‎‏‏‏‎‏‏‎‏‎You have incorrectly drawn your unlock pattern ‎‏‎‎‏‏‎<xliff:g id="NUMBER_0">%1$d</xliff:g>‎‏‎‎‏‏‏‎ times. After ‎‏‎‎‏‏‎<xliff:g id="NUMBER_1">%2$d</xliff:g>‎‏‎‎‏‏‏‎ more unsuccessful attempts, you will be asked to unlock your phone using an email account.‎‏‎‎‏‏‎\n‎‏‎‎‏‏‏‎‎‏‎‎‏‏‎\n‎‏‎‎‏‏‏‎ Try again in ‎‏‎‎‏‏‎<xliff:g id="NUMBER_2">%3$d</xliff:g>‎‏‎‎‏‏‏‎ seconds.‎‏‎‎‏‎"</string>
- <!-- no translation found for global_action_lock_message (7092460751050168771) -->
- <skip />
- <!-- no translation found for global_action_lock_message (1024230056230539493) -->
- <skip />
- <!-- no translation found for global_action_lock_message (3165224897120346096) -->
- <skip />
+ <string name="global_action_lock_message" product="default" msgid="7092460751050168771">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‎‎‏‎‎‏‏‎‏‏‎‏‎‏‏‏‏‎‏‏‎‏‏‏‏‎‎‏‏‏‎‎‎‎‎‏‏‎‏‏‏‏‏‎‏‏‎‏‏‎‎‏‏‏‎‎‎‎‏‏‎Unlock your phone for more options‎‏‎‎‏‎"</string>
+ <string name="global_action_lock_message" product="tablet" msgid="1024230056230539493">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‎‏‏‏‎‎‎‏‏‎‏‏‎‏‏‎‎‏‎‏‏‏‏‎‎‏‏‏‏‎‎‏‏‏‏‎‏‏‏‏‎‎‏‏‎‎‏‎‏‎‎‎‎‏‏‏‎‎‏‎‏‎Unlock your tablet for more options‎‏‎‎‏‎"</string>
+ <string name="global_action_lock_message" product="device" msgid="3165224897120346096">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‏‎‏‏‏‏‏‎‏‏‎‏‎‎‏‎‎‎‏‏‎‏‎‎‎‏‏‎‎‎‎‏‏‎‏‏‎‎‎‏‎‏‎‎‏‎‎‏‏‏‏‏‏‏‏‏‎‎‎‎‎Unlock your device for more options‎‏‎‎‏‎"</string>
</resources>
diff --git a/packages/SystemUI/res-product/values-es-rUS/strings.xml b/packages/SystemUI/res-product/values-es-rUS/strings.xml
index fe081eafd1bd..b333479ad264 100644
--- a/packages/SystemUI/res-product/values-es-rUS/strings.xml
+++ b/packages/SystemUI/res-product/values-es-rUS/strings.xml
@@ -40,10 +40,7 @@
<string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4682221342671290678">"Intentaste desbloquear el teléfono <xliff:g id="NUMBER">%d</xliff:g> veces de manera incorrecta. Se quitará el perfil de trabajo, lo que borrará todos los datos asociados."</string>
<string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="1860049973474855672">"Dibujaste el patrón de desbloqueo <xliff:g id="NUMBER_0">%1$d</xliff:g> veces de manera incorrecta. Después de <xliff:g id="NUMBER_1">%2$d</xliff:g> intentos incorrectos más, se te solicitará que desbloquees la tablet mediante una cuenta de correo electrónico.\n\n Vuelve a intentarlo en <xliff:g id="NUMBER_2">%3$d</xliff:g> segundos."</string>
<string name="kg_failed_attempts_almost_at_login" product="default" msgid="44112553371516141">"Dibujaste el patrón de desbloqueo <xliff:g id="NUMBER_0">%1$d</xliff:g> veces de manera incorrecta. Después de <xliff:g id="NUMBER_1">%2$d</xliff:g> intentos incorrectos más, se te solicitará que desbloquees el dispositivo mediante una cuenta de correo electrónico.\n\n Vuelve a intentarlo en <xliff:g id="NUMBER_2">%3$d</xliff:g> segundos."</string>
- <!-- no translation found for global_action_lock_message (7092460751050168771) -->
- <skip />
- <!-- no translation found for global_action_lock_message (1024230056230539493) -->
- <skip />
- <!-- no translation found for global_action_lock_message (3165224897120346096) -->
- <skip />
+ <string name="global_action_lock_message" product="default" msgid="7092460751050168771">"Desbloquea el teléfono para ver más opciones"</string>
+ <string name="global_action_lock_message" product="tablet" msgid="1024230056230539493">"Desbloquea la tablet para ver más opciones"</string>
+ <string name="global_action_lock_message" product="device" msgid="3165224897120346096">"Desbloquea el dispositivo para ver más opciones"</string>
</resources>
diff --git a/packages/SystemUI/res-product/values-es/strings.xml b/packages/SystemUI/res-product/values-es/strings.xml
index f170c1275daa..03ff2ff8a2d9 100644
--- a/packages/SystemUI/res-product/values-es/strings.xml
+++ b/packages/SystemUI/res-product/values-es/strings.xml
@@ -40,10 +40,7 @@
<string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4682221342671290678">"Has intentado desbloquear el teléfono de forma incorrecta <xliff:g id="NUMBER">%d</xliff:g> veces. Se quitará este perfil de trabajo y se eliminarán todos sus datos."</string>
<string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="1860049973474855672">"Has dibujado un patrón de desbloqueo incorrecto <xliff:g id="NUMBER_0">%1$d</xliff:g> veces. Si se producen <xliff:g id="NUMBER_1">%2$d</xliff:g> intentos incorrectos más, se te pedirá que desbloquees el tablet con una cuenta de correo electrónico.\n\n Vuelve a intentarlo en <xliff:g id="NUMBER_2">%3$d</xliff:g> segundos."</string>
<string name="kg_failed_attempts_almost_at_login" product="default" msgid="44112553371516141">"Has dibujado un patrón de desbloqueo incorrecto <xliff:g id="NUMBER_0">%1$d</xliff:g> veces. Si se producen <xliff:g id="NUMBER_1">%2$d</xliff:g> intentos incorrectos más, se te pedirá que desbloquees el teléfono con una cuenta de correo electrónico.\n\n Vuelve a intentarlo en <xliff:g id="NUMBER_2">%3$d</xliff:g> segundos."</string>
- <!-- no translation found for global_action_lock_message (7092460751050168771) -->
- <skip />
- <!-- no translation found for global_action_lock_message (1024230056230539493) -->
- <skip />
- <!-- no translation found for global_action_lock_message (3165224897120346096) -->
- <skip />
+ <string name="global_action_lock_message" product="default" msgid="7092460751050168771">"Desbloquea el teléfono para ver más opciones"</string>
+ <string name="global_action_lock_message" product="tablet" msgid="1024230056230539493">"Desbloquea el tablet para ver más opciones"</string>
+ <string name="global_action_lock_message" product="device" msgid="3165224897120346096">"Desbloquea el dispositivo para ver más opciones"</string>
</resources>
diff --git a/packages/SystemUI/res-product/values-et/strings.xml b/packages/SystemUI/res-product/values-et/strings.xml
index f64be8fd810f..01060cb6dc9b 100644
--- a/packages/SystemUI/res-product/values-et/strings.xml
+++ b/packages/SystemUI/res-product/values-et/strings.xml
@@ -40,10 +40,7 @@
<string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4682221342671290678">"Olete püüdnud <xliff:g id="NUMBER">%d</xliff:g> korda telefoni valesti avada. Tööprofiil eemaldatakse ja kõik profiiliandmed kustutatakse."</string>
<string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="1860049973474855672">"Joonistasite oma avamismustri <xliff:g id="NUMBER_0">%1$d</xliff:g> korda valesti. Pärast veel <xliff:g id="NUMBER_1">%2$d</xliff:g> ebaõnnestunud katset palutakse teil tahvelarvuti avada meilikontoga.\n\n Proovige uuesti <xliff:g id="NUMBER_2">%3$d</xliff:g> sekundi pärast."</string>
<string name="kg_failed_attempts_almost_at_login" product="default" msgid="44112553371516141">"Joonistasite oma avamismustri <xliff:g id="NUMBER_0">%1$d</xliff:g> korda valesti. Pärast veel <xliff:g id="NUMBER_1">%2$d</xliff:g> ebaõnnestunud katset palutakse teil telefon avada meilikontoga.\n\n Proovige uuesti <xliff:g id="NUMBER_2">%3$d</xliff:g> sekundi pärast."</string>
- <!-- no translation found for global_action_lock_message (7092460751050168771) -->
- <skip />
- <!-- no translation found for global_action_lock_message (1024230056230539493) -->
- <skip />
- <!-- no translation found for global_action_lock_message (3165224897120346096) -->
- <skip />
+ <string name="global_action_lock_message" product="default" msgid="7092460751050168771">"Lisavalikute nägemiseks avage oma telefon"</string>
+ <string name="global_action_lock_message" product="tablet" msgid="1024230056230539493">"Lisavalikute nägemiseks avage oma tahvelarvuti"</string>
+ <string name="global_action_lock_message" product="device" msgid="3165224897120346096">"Lisavalikute nägemiseks avage oma seade"</string>
</resources>
diff --git a/packages/SystemUI/res-product/values-eu/strings.xml b/packages/SystemUI/res-product/values-eu/strings.xml
index 2feed17c1f90..e6cf28d2fac0 100644
--- a/packages/SystemUI/res-product/values-eu/strings.xml
+++ b/packages/SystemUI/res-product/values-eu/strings.xml
@@ -40,10 +40,7 @@
<string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4682221342671290678">"<xliff:g id="NUMBER">%d</xliff:g> aldiz saiatu zara telefonoa desblokeatzen, baina huts egin duzu denetan. Laneko profila kendu egingo da eta, ondorioz, profileko datu guztiak ezabatuko dira."</string>
<string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="1860049973474855672">"Desblokeatzeko eredua oker marraztu duzu <xliff:g id="NUMBER_0">%1$d</xliff:g> aldiz. Beste <xliff:g id="NUMBER_1">%2$d</xliff:g> aldiz oker marrazten baduzu, tableta posta-kontu baten bidez desblokeatzeko eskatuko dizugu.\n\n Saiatu berriro <xliff:g id="NUMBER_2">%3$d</xliff:g> segundo barru."</string>
<string name="kg_failed_attempts_almost_at_login" product="default" msgid="44112553371516141">"Desblokeatzeko eredua oker marraztu duzu <xliff:g id="NUMBER_0">%1$d</xliff:g> aldiz. Beste <xliff:g id="NUMBER_1">%2$d</xliff:g> aldiz oker marrazten baduzu, telefonoa posta-kontu baten bidez desblokeatzeko eskatuko dizugu.\n\n Saiatu berriro <xliff:g id="NUMBER_2">%3$d</xliff:g> segundo barru."</string>
- <!-- no translation found for global_action_lock_message (7092460751050168771) -->
- <skip />
- <!-- no translation found for global_action_lock_message (1024230056230539493) -->
- <skip />
- <!-- no translation found for global_action_lock_message (3165224897120346096) -->
- <skip />
+ <string name="global_action_lock_message" product="default" msgid="7092460751050168771">"Desblokeatu telefonoa aukera gehiago ikusteko"</string>
+ <string name="global_action_lock_message" product="tablet" msgid="1024230056230539493">"Desblokeatu tableta aukera gehiago ikusteko"</string>
+ <string name="global_action_lock_message" product="device" msgid="3165224897120346096">"Desblokeatu gailua aukera gehiago ikusteko"</string>
</resources>
diff --git a/packages/SystemUI/res-product/values-fa/strings.xml b/packages/SystemUI/res-product/values-fa/strings.xml
index b55743046e07..52fa2d85d074 100644
--- a/packages/SystemUI/res-product/values-fa/strings.xml
+++ b/packages/SystemUI/res-product/values-fa/strings.xml
@@ -40,10 +40,7 @@
<string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4682221342671290678">"<xliff:g id="NUMBER">%d</xliff:g> تلاش ناموفق برای باز کردن قفل تلفن داشته‌اید. نمایه کاری پاک می‌شود که با آن همه داده‌های نمایه حذف می‌شود."</string>
<string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="1860049973474855672">"‏شما الگوی باز کردن قفل را <xliff:g id="NUMBER_0">%1$d</xliff:g> بار اشتباه کشیده‌اید. بعد از <xliff:g id="NUMBER_1">%2$d</xliff:g> تلاش ناموفق، از شما خواسته می‎شود که با استفاده از یک حساب ایمیل قفل رایانه لوحی خود را باز کنید.\n\n لطفاً پس از <xliff:g id="NUMBER_2">%3$d</xliff:g> ثانیه دوباره امتحان کنید."</string>
<string name="kg_failed_attempts_almost_at_login" product="default" msgid="44112553371516141">"شما الگوی باز کردن قفل را <xliff:g id="NUMBER_0">%1$d</xliff:g> بار اشتباه کشیده‌اید. پس از <xliff:g id="NUMBER_1">%2$d</xliff:g> تلاش ناموفق، از شما خواسته می‌شود که با استفاده از یک حساب ایمیل قفل تلفن را باز کنید.\n\n لطفاً پس از <xliff:g id="NUMBER_2">%3$d</xliff:g> ثانیه دوباره امتحان کنید."</string>
- <!-- no translation found for global_action_lock_message (7092460751050168771) -->
- <skip />
- <!-- no translation found for global_action_lock_message (1024230056230539493) -->
- <skip />
- <!-- no translation found for global_action_lock_message (3165224897120346096) -->
- <skip />
+ <string name="global_action_lock_message" product="default" msgid="7092460751050168771">"برای گزینه‌های بیشتر، قفل تلفن را باز کنید"</string>
+ <string name="global_action_lock_message" product="tablet" msgid="1024230056230539493">"برای گزینه‌های بیشتر، قفل رایانه لوحی را باز کنید"</string>
+ <string name="global_action_lock_message" product="device" msgid="3165224897120346096">"برای گزینه‌های بیشتر، قفل دستگاه را باز کنید"</string>
</resources>
diff --git a/packages/SystemUI/res-product/values-fi/strings.xml b/packages/SystemUI/res-product/values-fi/strings.xml
index 815a8ac3acb4..4001b30eb4d9 100644
--- a/packages/SystemUI/res-product/values-fi/strings.xml
+++ b/packages/SystemUI/res-product/values-fi/strings.xml
@@ -40,10 +40,7 @@
<string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4682221342671290678">"Yritit avata puhelimen lukituksen virheellisillä tiedoilla <xliff:g id="NUMBER">%d</xliff:g> kertaa. Työprofiili ja kaikki sen data poistetaan."</string>
<string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="1860049973474855672">"Piirsit lukituksenpoistokuvion väärin <xliff:g id="NUMBER_0">%1$d</xliff:g> kertaa. Jos piirrät kuvion väärin vielä <xliff:g id="NUMBER_1">%2$d</xliff:g> kertaa, sinua pyydetään avaamaan tabletin lukitus sähköpostitilin avulla.\n\n Yritä uudelleen <xliff:g id="NUMBER_2">%3$d</xliff:g> sekunnin kuluttua."</string>
<string name="kg_failed_attempts_almost_at_login" product="default" msgid="44112553371516141">"Piirsit lukituksenpoistokuvion väärin <xliff:g id="NUMBER_0">%1$d</xliff:g> kertaa. Jos piirrät kuvion väärin vielä <xliff:g id="NUMBER_1">%2$d</xliff:g> kertaa, sinua pyydetään avaamaan puhelimesi lukitus sähköpostitilin avulla.\n\n Yritä uudelleen <xliff:g id="NUMBER_2">%3$d</xliff:g> sekunnin kuluttua."</string>
- <!-- no translation found for global_action_lock_message (7092460751050168771) -->
- <skip />
- <!-- no translation found for global_action_lock_message (1024230056230539493) -->
- <skip />
- <!-- no translation found for global_action_lock_message (3165224897120346096) -->
- <skip />
+ <string name="global_action_lock_message" product="default" msgid="7092460751050168771">"Avaa puhelimen lukitus, niin näet enemmän vaihtoehtoja"</string>
+ <string name="global_action_lock_message" product="tablet" msgid="1024230056230539493">"Avaa tabletin lukitus, niin näet enemmän vaihtoehtoja"</string>
+ <string name="global_action_lock_message" product="device" msgid="3165224897120346096">"Avaa laitteen lukitus, niin näet enemmän vaihtoehtoja"</string>
</resources>
diff --git a/packages/SystemUI/res-product/values-fr-rCA/strings.xml b/packages/SystemUI/res-product/values-fr-rCA/strings.xml
index 6490511cfaa4..0849256bb53a 100644
--- a/packages/SystemUI/res-product/values-fr-rCA/strings.xml
+++ b/packages/SystemUI/res-product/values-fr-rCA/strings.xml
@@ -40,10 +40,7 @@
<string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4682221342671290678">"Vous avez tenté de déverrouiller ce téléphone à <xliff:g id="NUMBER">%d</xliff:g> reprises. Le profil professionnel sera supprimé, ce qui entraîne la suppression de toutes ses données."</string>
<string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="1860049973474855672">"Vous avez dessiné un schéma de déverrouillage incorrect à <xliff:g id="NUMBER_0">%1$d</xliff:g> reprises. Si vous échouez encore <xliff:g id="NUMBER_1">%2$d</xliff:g> fois, vous devrez déverrouiller votre tablette à l\'aide d\'un compte de courriel.\n\nVeuillez réessayer dans <xliff:g id="NUMBER_2">%3$d</xliff:g> secondes."</string>
<string name="kg_failed_attempts_almost_at_login" product="default" msgid="44112553371516141">"Vous avez dessiné un schéma de déverrouillage incorrect à <xliff:g id="NUMBER_0">%1$d</xliff:g> reprises. Si vous échouez encore <xliff:g id="NUMBER_1">%2$d</xliff:g> fois, vous devrez déverrouiller votre téléphone à l\'aide d\'un compte de courriel.\n\nVeuillez réessayer dans <xliff:g id="NUMBER_2">%3$d</xliff:g> secondes."</string>
- <!-- no translation found for global_action_lock_message (7092460751050168771) -->
- <skip />
- <!-- no translation found for global_action_lock_message (1024230056230539493) -->
- <skip />
- <!-- no translation found for global_action_lock_message (3165224897120346096) -->
- <skip />
+ <string name="global_action_lock_message" product="default" msgid="7092460751050168771">"Déverrouillez votre téléphone pour afficher davantage d\'options"</string>
+ <string name="global_action_lock_message" product="tablet" msgid="1024230056230539493">"Déverrouillez votre tablette pour afficher davantage d\'options"</string>
+ <string name="global_action_lock_message" product="device" msgid="3165224897120346096">"Déverrouillez votre appareil pour afficher davantage d\'options"</string>
</resources>
diff --git a/packages/SystemUI/res-product/values-fr/strings.xml b/packages/SystemUI/res-product/values-fr/strings.xml
index c92fbec96267..1bbb759046e1 100644
--- a/packages/SystemUI/res-product/values-fr/strings.xml
+++ b/packages/SystemUI/res-product/values-fr/strings.xml
@@ -40,10 +40,7 @@
<string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4682221342671290678">"Vous avez tenté de déverrouiller le téléphone à <xliff:g id="NUMBER">%d</xliff:g> reprises. Le profil professionnel et toutes les données associées vont être supprimés."</string>
<string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="1860049973474855672">"Vous avez dessiné un schéma de déverrouillage incorrect à <xliff:g id="NUMBER_0">%1$d</xliff:g> reprises. Si vous échouez encore <xliff:g id="NUMBER_1">%2$d</xliff:g> fois, vous devrez déverrouiller votre tablette à l\'aide d\'un compte de messagerie électronique.\n\nRéessayez dans <xliff:g id="NUMBER_2">%3$d</xliff:g> secondes."</string>
<string name="kg_failed_attempts_almost_at_login" product="default" msgid="44112553371516141">"Vous avez dessiné un schéma de déverrouillage incorrect à <xliff:g id="NUMBER_0">%1$d</xliff:g> reprises. Si vous échouez encore <xliff:g id="NUMBER_1">%2$d</xliff:g> fois, vous devrez déverrouiller votre téléphone à l\'aide d\'un compte de messagerie électronique.\n\nRéessayez dans <xliff:g id="NUMBER_2">%3$d</xliff:g> secondes."</string>
- <!-- no translation found for global_action_lock_message (7092460751050168771) -->
- <skip />
- <!-- no translation found for global_action_lock_message (1024230056230539493) -->
- <skip />
- <!-- no translation found for global_action_lock_message (3165224897120346096) -->
- <skip />
+ <string name="global_action_lock_message" product="default" msgid="7092460751050168771">"Déverrouillez votre téléphone pour obtenir plus d\'options"</string>
+ <string name="global_action_lock_message" product="tablet" msgid="1024230056230539493">"Déverrouillez votre tablette pour obtenir plus d\'options"</string>
+ <string name="global_action_lock_message" product="device" msgid="3165224897120346096">"Déverrouillez votre appareil pour obtenir plus d\'options"</string>
</resources>
diff --git a/packages/SystemUI/res-product/values-gl/strings.xml b/packages/SystemUI/res-product/values-gl/strings.xml
index eb2681c193c1..6f034fb369d9 100644
--- a/packages/SystemUI/res-product/values-gl/strings.xml
+++ b/packages/SystemUI/res-product/values-gl/strings.xml
@@ -40,10 +40,7 @@
<string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4682221342671290678">"Tentaches desbloquear o teléfono <xliff:g id="NUMBER">%d</xliff:g> veces de forma incorrecta. Quitarase o perfil de traballo e, por conseguinte, todos os seus datos."</string>
<string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="1860049973474855672">"Debuxaches o padrón de desbloqueo <xliff:g id="NUMBER_0">%1$d</xliff:g> veces de forma incorrecta. Se realizas <xliff:g id="NUMBER_1">%2$d</xliff:g> intentos incorrectos máis, terás que desbloquear a tableta a través dunha conta de correo electrónico.\n\n Téntao de novo en <xliff:g id="NUMBER_2">%3$d</xliff:g> segundos."</string>
<string name="kg_failed_attempts_almost_at_login" product="default" msgid="44112553371516141">"Debuxaches o padrón de desbloqueo <xliff:g id="NUMBER_0">%1$d</xliff:g> veces de forma incorrecta. Se realizas <xliff:g id="NUMBER_1">%2$d</xliff:g> intentos incorrectos máis, terás que desbloquear o teléfono a través dunha conta de correo electrónico.\n\n Téntao de novo en <xliff:g id="NUMBER_2">%3$d</xliff:g> segundos."</string>
- <!-- no translation found for global_action_lock_message (7092460751050168771) -->
- <skip />
- <!-- no translation found for global_action_lock_message (1024230056230539493) -->
- <skip />
- <!-- no translation found for global_action_lock_message (3165224897120346096) -->
- <skip />
+ <string name="global_action_lock_message" product="default" msgid="7092460751050168771">"Desbloquea o teléfono para ver máis opcións"</string>
+ <string name="global_action_lock_message" product="tablet" msgid="1024230056230539493">"Desbloquea a tableta para ver máis opcións"</string>
+ <string name="global_action_lock_message" product="device" msgid="3165224897120346096">"Desbloquea o dispositivo para ver máis opcións"</string>
</resources>
diff --git a/packages/SystemUI/res-product/values-gu/strings.xml b/packages/SystemUI/res-product/values-gu/strings.xml
index 3fffab621f3c..9839b42919e4 100644
--- a/packages/SystemUI/res-product/values-gu/strings.xml
+++ b/packages/SystemUI/res-product/values-gu/strings.xml
@@ -40,10 +40,7 @@
<string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4682221342671290678">"તમે ફોનને <xliff:g id="NUMBER">%d</xliff:g> વખત ખોટી રીતે અનલૉક કરવાનો પ્રયાસ કર્યો છે. આ કાર્યાલયની પ્રોફાઇલ કાઢી નાખવામાં આવશે, જે તમામ પ્રોફાઇલ ડેટાને ડિલીટ કરી દેશે."</string>
<string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="1860049973474855672">"તમે તમારી અનલૉક પૅટર્ન <xliff:g id="NUMBER_0">%1$d</xliff:g> વખત ખોટી રીતે દોરી છે. વધુ <xliff:g id="NUMBER_1">%2$d</xliff:g> અસફળ પ્રયાસો પછી, તમને એક ઇમેઇલ એકાઉન્ટનો ઉપયોગ કરીને તમારા ટૅબ્લેટને અનલૉક કરવાનું કહેવામાં આવશે.\n\n<xliff:g id="NUMBER_2">%3$d</xliff:g> સેકન્ડમાં ફરી પ્રયાસ કરો."</string>
<string name="kg_failed_attempts_almost_at_login" product="default" msgid="44112553371516141">"તમે તમારી અનલૉક પૅટર્ન <xliff:g id="NUMBER_0">%1$d</xliff:g> વખત ખોટી રીતે દોરી છે. વધુ <xliff:g id="NUMBER_1">%2$d</xliff:g> અસફળ પ્રયાસો પછી, તમને ઇમેઇલ એકાઉન્ટનો ઉપયોગ કરીને તમારા ફોનને અનલૉક કરવાનું કહેવામાં આવશે.\n\n<xliff:g id="NUMBER_2">%3$d</xliff:g> સેકન્ડમાં ફરીથી પ્રયાસ કરો."</string>
- <!-- no translation found for global_action_lock_message (7092460751050168771) -->
- <skip />
- <!-- no translation found for global_action_lock_message (1024230056230539493) -->
- <skip />
- <!-- no translation found for global_action_lock_message (3165224897120346096) -->
- <skip />
+ <string name="global_action_lock_message" product="default" msgid="7092460751050168771">"વધુ વિકલ્પો માટે તમારા ફોનને અનલૉક કરો"</string>
+ <string name="global_action_lock_message" product="tablet" msgid="1024230056230539493">"વધુ વિકલ્પો માટે તમારા ટૅબ્લેટને અનલૉક કરો"</string>
+ <string name="global_action_lock_message" product="device" msgid="3165224897120346096">"વધુ વિકલ્પો માટે તમારા ડિવાઇસને અનલૉક કરો"</string>
</resources>
diff --git a/packages/SystemUI/res-product/values-hi/strings.xml b/packages/SystemUI/res-product/values-hi/strings.xml
index 7d7b8299f4fc..83c67e2fc724 100644
--- a/packages/SystemUI/res-product/values-hi/strings.xml
+++ b/packages/SystemUI/res-product/values-hi/strings.xml
@@ -40,10 +40,7 @@
<string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4682221342671290678">"आप फ़ोन को अनलॉक करने के लिए <xliff:g id="NUMBER">%d</xliff:g> बार गलत पासवर्ड डाल चुके हैं. इसकी वजह से वर्क प्रोफ़ाइल को हटा दिया जाएगा जिससे उपयोगकर्ता की प्रोफ़ाइल का सारा डेटा मिट जाएगा."</string>
<string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="1860049973474855672">"आपने लॉक खोलने के पैटर्न को <xliff:g id="NUMBER_0">%1$d</xliff:g> बार गलत तरीके से बनाया है. इसलिए, <xliff:g id="NUMBER_1">%2$d</xliff:g> और गलत पैटर्न बनाने के बाद, टैबलेट को अनलॉक करने के लिए आपसे ईमेल खाते का इस्तेमाल करने को कहा जाएगा.\n\n अनलॉक करने के लिए <xliff:g id="NUMBER_2">%3$d</xliff:g> सेकंड में फिर से कोशिश करें."</string>
<string name="kg_failed_attempts_almost_at_login" product="default" msgid="44112553371516141">"आपने लॉक खोलने के पैटर्न को <xliff:g id="NUMBER_0">%1$d</xliff:g> बार गलत तरीके से बनाया है. इसलिए, <xliff:g id="NUMBER_1">%2$d</xliff:g> और गलत पैटर्न बनाने के बाद, आपसे फ़ोन को अनलॉक करने के लिए ईमेल खाते का इस्तेमाल करने को कहा जाएगा.\n\n अनलॉक करने के लिए <xliff:g id="NUMBER_2">%3$d</xliff:g> सेकंड में फिर से कोशिश करें."</string>
- <!-- no translation found for global_action_lock_message (7092460751050168771) -->
- <skip />
- <!-- no translation found for global_action_lock_message (1024230056230539493) -->
- <skip />
- <!-- no translation found for global_action_lock_message (3165224897120346096) -->
- <skip />
+ <string name="global_action_lock_message" product="default" msgid="7092460751050168771">"ज़्यादा विकल्प देखने के लिए, अपना फ़ोन अनलॉक करें"</string>
+ <string name="global_action_lock_message" product="tablet" msgid="1024230056230539493">"ज़्यादा विकल्प देखने के लिए, अपना टैबलेट अनलॉक करें"</string>
+ <string name="global_action_lock_message" product="device" msgid="3165224897120346096">"ज़्यादा विकल्प देखने के लिए, अपना डिवाइस अनलॉक करें"</string>
</resources>
diff --git a/packages/SystemUI/res-product/values-hr/strings.xml b/packages/SystemUI/res-product/values-hr/strings.xml
index 7ad09d05dcc0..13f0023deac4 100644
--- a/packages/SystemUI/res-product/values-hr/strings.xml
+++ b/packages/SystemUI/res-product/values-hr/strings.xml
@@ -40,10 +40,7 @@
<string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4682221342671290678">"Neuspješno ste pokušali otključati telefon <xliff:g id="NUMBER">%d</xliff:g> put/a. Radni će se profil ukloniti, a time će se izbrisati i svi njegovi podaci."</string>
<string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="1860049973474855672">"Netočno ste iscrtali uzorak za otključavanje <xliff:g id="NUMBER_0">%1$d</xliff:g> put/a. Nakon još <xliff:g id="NUMBER_1">%2$d</xliff:g> pokušaja morat ćete otključati tablet pomoću računa e-pošte.\n\n Pokušajte ponovo za <xliff:g id="NUMBER_2">%3$d</xliff:g> s."</string>
<string name="kg_failed_attempts_almost_at_login" product="default" msgid="44112553371516141">"Netočno ste iscrtali uzorak za otključavanje <xliff:g id="NUMBER_0">%1$d</xliff:g> put/a. Nakon još <xliff:g id="NUMBER_1">%2$d</xliff:g> pokušaja morat ćete otključati telefon pomoću računa e-pošte.\n\n Pokušajte ponovo za <xliff:g id="NUMBER_2">%3$d</xliff:g> s."</string>
- <!-- no translation found for global_action_lock_message (7092460751050168771) -->
- <skip />
- <!-- no translation found for global_action_lock_message (1024230056230539493) -->
- <skip />
- <!-- no translation found for global_action_lock_message (3165224897120346096) -->
- <skip />
+ <string name="global_action_lock_message" product="default" msgid="7092460751050168771">"Za više opcija otključajte telefon"</string>
+ <string name="global_action_lock_message" product="tablet" msgid="1024230056230539493">"Za više opcija otključajte tablet"</string>
+ <string name="global_action_lock_message" product="device" msgid="3165224897120346096">"Za više opcija otključajte uređaj"</string>
</resources>
diff --git a/packages/SystemUI/res-product/values-hu/strings.xml b/packages/SystemUI/res-product/values-hu/strings.xml
index ffcaa8d7b698..743e2082dd81 100644
--- a/packages/SystemUI/res-product/values-hu/strings.xml
+++ b/packages/SystemUI/res-product/values-hu/strings.xml
@@ -40,10 +40,7 @@
<string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4682221342671290678">"<xliff:g id="NUMBER">%d</xliff:g> alkalommal próbálkozott sikertelenül a telefon zárolásának feloldásával. A rendszer eltávolítja a munkaprofilt, és ezzel a profil összes adata törlődik."</string>
<string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="1860049973474855672">"<xliff:g id="NUMBER_0">%1$d</xliff:g> alkalommal helytelenül rajzolta le a feloldási mintát. További <xliff:g id="NUMBER_1">%2$d</xliff:g> sikertelen kísérlet után e-mail-fiók használatával kell feloldania táblagépét.\n\nPróbálja újra <xliff:g id="NUMBER_2">%3$d</xliff:g> másodperc múlva."</string>
<string name="kg_failed_attempts_almost_at_login" product="default" msgid="44112553371516141">"<xliff:g id="NUMBER_0">%1$d</xliff:g> alkalommal helytelenül rajzolta le a feloldási mintát. További <xliff:g id="NUMBER_1">%2$d</xliff:g> sikertelen kísérlet után e-mail-fiók használatával kell feloldania telefonját.\n\nPróbálja újra <xliff:g id="NUMBER_2">%3$d</xliff:g> másodperc múlva."</string>
- <!-- no translation found for global_action_lock_message (7092460751050168771) -->
- <skip />
- <!-- no translation found for global_action_lock_message (1024230056230539493) -->
- <skip />
- <!-- no translation found for global_action_lock_message (3165224897120346096) -->
- <skip />
+ <string name="global_action_lock_message" product="default" msgid="7092460751050168771">"További lehetőségekért oldja fel a telefont"</string>
+ <string name="global_action_lock_message" product="tablet" msgid="1024230056230539493">"További lehetőségekért oldja fel a táblagépet"</string>
+ <string name="global_action_lock_message" product="device" msgid="3165224897120346096">"További lehetőségekért oldja fel az eszközt"</string>
</resources>
diff --git a/packages/SystemUI/res-product/values-hy/strings.xml b/packages/SystemUI/res-product/values-hy/strings.xml
index 6633ec825535..f245562d541a 100644
--- a/packages/SystemUI/res-product/values-hy/strings.xml
+++ b/packages/SystemUI/res-product/values-hy/strings.xml
@@ -40,10 +40,7 @@
<string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4682221342671290678">"Դուք կատարել եք հեռախոսն ապակողպելու <xliff:g id="NUMBER">%d</xliff:g> անհաջող փորձ: Աշխատանքային պրոֆիլը կհեռացվի, և պրոֆիլի բոլոր տվյալները կջնջվեն:"</string>
<string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="1860049973474855672">"Դուք կատարել եք ապակողպման նախշը մուտքագրելու <xliff:g id="NUMBER_0">%1$d</xliff:g> անհաջող փորձ: Եվս <xliff:g id="NUMBER_1">%2$d</xliff:g> անհաջող փորձից հետո ձեզանից կպահանջվի ապակողպել պլանշետը էլփոստի հաշվի միջոցով։\n\n Խնդրում ենք կրկին փորձել <xliff:g id="NUMBER_2">%3$d</xliff:g> վայրկյանից:"</string>
<string name="kg_failed_attempts_almost_at_login" product="default" msgid="44112553371516141">"Դուք <xliff:g id="NUMBER_0">%1$d</xliff:g> անգամ սխալ եք հավաքել ձեր ապակողպման նմուշը: Եվս <xliff:g id="NUMBER_1">%2$d</xliff:g> անհաջող փորձից հետո ձեզ կառաջարկվի ապակողպել հեռախոսը` օգտագործելով էլփոստի հաշիվ:\n\n Կրկին փորձեք <xliff:g id="NUMBER_2">%3$d</xliff:g> վայրկյանից:"</string>
- <!-- no translation found for global_action_lock_message (7092460751050168771) -->
- <skip />
- <!-- no translation found for global_action_lock_message (1024230056230539493) -->
- <skip />
- <!-- no translation found for global_action_lock_message (3165224897120346096) -->
- <skip />
+ <string name="global_action_lock_message" product="default" msgid="7092460751050168771">"Ապակողպեք ձեր հեռախոսը՝ լրացուցիչ կարգավորումները տեսնելու համար"</string>
+ <string name="global_action_lock_message" product="tablet" msgid="1024230056230539493">"Ապակողպեք ձեր պլանշետը՝ լրացուցիչ կարգավորումները տեսնելու համար"</string>
+ <string name="global_action_lock_message" product="device" msgid="3165224897120346096">"Ապակողպեք ձեր սարքը՝ լրացուցիչ կարգավորումները տեսնելու համար"</string>
</resources>
diff --git a/packages/SystemUI/res-product/values-in/strings.xml b/packages/SystemUI/res-product/values-in/strings.xml
index 7037aa150c64..2e0580f568f9 100644
--- a/packages/SystemUI/res-product/values-in/strings.xml
+++ b/packages/SystemUI/res-product/values-in/strings.xml
@@ -40,10 +40,7 @@
<string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4682221342671290678">"Anda telah <xliff:g id="NUMBER">%d</xliff:g> kali berupaya membuka kunci ponsel dengan tidak benar. Profil kerja akan dihapus, sehingga semua data profil akan dihapus."</string>
<string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="1860049973474855672">"Anda telah <xliff:g id="NUMBER_0">%1$d</xliff:g> kali salah menggambar pola pembuka kunci. Setelah <xliff:g id="NUMBER_1">%2$d</xliff:g> lagi upaya yang tidak berhasil, Anda akan diminta membuka kunci tablet menggunakan akun email.\n\n Coba lagi dalam <xliff:g id="NUMBER_2">%3$d</xliff:g> detik."</string>
<string name="kg_failed_attempts_almost_at_login" product="default" msgid="44112553371516141">"Anda telah <xliff:g id="NUMBER_0">%1$d</xliff:g> kali salah menggambar pola pembuka kunci. Setelah <xliff:g id="NUMBER_1">%2$d</xliff:g> lagi upaya yang tidak berhasil, Anda akan diminta membuka kunci ponsel menggunakan akun email.\n\n Coba lagi dalam <xliff:g id="NUMBER_2">%3$d</xliff:g> detik."</string>
- <!-- no translation found for global_action_lock_message (7092460751050168771) -->
- <skip />
- <!-- no translation found for global_action_lock_message (1024230056230539493) -->
- <skip />
- <!-- no translation found for global_action_lock_message (3165224897120346096) -->
- <skip />
+ <string name="global_action_lock_message" product="default" msgid="7092460751050168771">"Buka kunci ponsel untuk melihat opsi lainnya"</string>
+ <string name="global_action_lock_message" product="tablet" msgid="1024230056230539493">"Buka kunci tablet untuk melihat opsi lainnya"</string>
+ <string name="global_action_lock_message" product="device" msgid="3165224897120346096">"Buka kunci perangkat untuk melihat opsi lainnya"</string>
</resources>
diff --git a/packages/SystemUI/res-product/values-is/strings.xml b/packages/SystemUI/res-product/values-is/strings.xml
index 2ae3e088361e..32f6e21e124f 100644
--- a/packages/SystemUI/res-product/values-is/strings.xml
+++ b/packages/SystemUI/res-product/values-is/strings.xml
@@ -40,10 +40,7 @@
<string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4682221342671290678">"Þú hefur gert <xliff:g id="NUMBER">%d</xliff:g> árangurslausar tilraunir til að opna símann. Vinnusniðið verður fjarlægt, með þeim afleiðingum að öllum gögnum þess verður eytt."</string>
<string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="1860049973474855672">"Þú hefur teiknað rangt opnunarmynstur <xliff:g id="NUMBER_0">%1$d</xliff:g> sinnum. Eftir <xliff:g id="NUMBER_1">%2$d</xliff:g> árangurslausar tilraunir í viðbót verðurðu beðin(n) um að opna spjaldtölvuna með tölvupóstreikningi.\n\n Reyndu aftur eftir <xliff:g id="NUMBER_2">%3$d</xliff:g> sekúndur."</string>
<string name="kg_failed_attempts_almost_at_login" product="default" msgid="44112553371516141">"Þú hefur teiknað rangt opnunarmynstur <xliff:g id="NUMBER_0">%1$d</xliff:g> sinnum. Eftir <xliff:g id="NUMBER_1">%2$d</xliff:g> árangurslausar tilraunir í viðbót verðurðu beðin(n) um að opna símann með tölvupóstreikningi.\n\n Reyndu aftur eftir <xliff:g id="NUMBER_2">%3$d</xliff:g> sekúndur."</string>
- <!-- no translation found for global_action_lock_message (7092460751050168771) -->
- <skip />
- <!-- no translation found for global_action_lock_message (1024230056230539493) -->
- <skip />
- <!-- no translation found for global_action_lock_message (3165224897120346096) -->
- <skip />
+ <string name="global_action_lock_message" product="default" msgid="7092460751050168771">"Taktu símann úr lás til að fá fleiri valkosti"</string>
+ <string name="global_action_lock_message" product="tablet" msgid="1024230056230539493">"Taktu spjaldtölvuna úr lás til að fá fleiri valkosti"</string>
+ <string name="global_action_lock_message" product="device" msgid="3165224897120346096">"Taktu tækið úr lás til að fá fleiri valkosti"</string>
</resources>
diff --git a/packages/SystemUI/res-product/values-it/strings.xml b/packages/SystemUI/res-product/values-it/strings.xml
index 8598fbb3cf6d..3403f3106678 100644
--- a/packages/SystemUI/res-product/values-it/strings.xml
+++ b/packages/SystemUI/res-product/values-it/strings.xml
@@ -40,10 +40,7 @@
<string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4682221342671290678">"Hai tentato di sbloccare il telefono senza riuscirci per <xliff:g id="NUMBER">%d</xliff:g> volte. Il profilo di lavoro verrà rimosso e verranno quindi eliminati tutti i dati associati."</string>
<string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="1860049973474855672">"<xliff:g id="NUMBER_0">%1$d</xliff:g> tentativi errati di inserimento della sequenza di sblocco. Dopo altri <xliff:g id="NUMBER_1">%2$d</xliff:g> tentativi falliti, ti verrà chiesto di sbloccare il tablet con un account email.\n\n Riprova tra <xliff:g id="NUMBER_2">%3$d</xliff:g> secondi."</string>
<string name="kg_failed_attempts_almost_at_login" product="default" msgid="44112553371516141">"<xliff:g id="NUMBER_0">%1$d</xliff:g> tentativi errati di inserimento della sequenza di sblocco. Dopo altri <xliff:g id="NUMBER_1">%2$d</xliff:g> tentativi falliti, ti verrà chiesto di sbloccare il telefono con un account email.\n\n Riprova tra <xliff:g id="NUMBER_2">%3$d</xliff:g> secondi."</string>
- <!-- no translation found for global_action_lock_message (7092460751050168771) -->
- <skip />
- <!-- no translation found for global_action_lock_message (1024230056230539493) -->
- <skip />
- <!-- no translation found for global_action_lock_message (3165224897120346096) -->
- <skip />
+ <string name="global_action_lock_message" product="default" msgid="7092460751050168771">"Sblocca il telefono per visualizzare altre opzioni"</string>
+ <string name="global_action_lock_message" product="tablet" msgid="1024230056230539493">"Sblocca il tablet per visualizzare altre opzioni"</string>
+ <string name="global_action_lock_message" product="device" msgid="3165224897120346096">"Sblocca il dispositivo per visualizzare altre opzioni"</string>
</resources>
diff --git a/packages/SystemUI/res-product/values-iw/strings.xml b/packages/SystemUI/res-product/values-iw/strings.xml
index 305b3ef92893..4ba8657a77e3 100644
--- a/packages/SystemUI/res-product/values-iw/strings.xml
+++ b/packages/SystemUI/res-product/values-iw/strings.xml
@@ -40,10 +40,7 @@
<string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4682221342671290678">"ניסית לבטל את נעילת הטלפון <xliff:g id="NUMBER">%d</xliff:g> פעמים. פרופיל העבודה יוסר וכל נתוני הפרופיל יימחקו."</string>
<string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="1860049973474855672">"שרטטת קו ביטול נעילה שגוי <xliff:g id="NUMBER_0">%1$d</xliff:g> פעמים. לאחר <xliff:g id="NUMBER_1">%2$d</xliff:g> ניסיונות כושלים נוספים, ,תישלח אליך בקשה לבטל את נעילת הטאבלט באמצעות חשבון אימייל‏.\n\n יש לנסות שוב בעוד <xliff:g id="NUMBER_2">%3$d</xliff:g> שניות."</string>
<string name="kg_failed_attempts_almost_at_login" product="default" msgid="44112553371516141">"שרטטת קו ביטול נעילה שגוי <xliff:g id="NUMBER_0">%1$d</xliff:g> פעמים. לאחר <xliff:g id="NUMBER_1">%2$d</xliff:g> ניסיונות כושלים נוספים, תשילח אליך בקשה לבטל את נעילת הטלפון באמצעות חשבון אימייל‏.\n\n יש לנסות שוב בעוד <xliff:g id="NUMBER_2">%3$d</xliff:g> שניות."</string>
- <!-- no translation found for global_action_lock_message (7092460751050168771) -->
- <skip />
- <!-- no translation found for global_action_lock_message (1024230056230539493) -->
- <skip />
- <!-- no translation found for global_action_lock_message (3165224897120346096) -->
- <skip />
+ <string name="global_action_lock_message" product="default" msgid="7092460751050168771">"לאפשרויות נוספות, יש לבטל את נעילת הטלפון"</string>
+ <string name="global_action_lock_message" product="tablet" msgid="1024230056230539493">"לאפשרויות נוספות, יש לבטל את נעילת הטאבלט"</string>
+ <string name="global_action_lock_message" product="device" msgid="3165224897120346096">"לאפשרויות נוספות, יש לבטל את נעילת המכשיר"</string>
</resources>
diff --git a/packages/SystemUI/res-product/values-ja/strings.xml b/packages/SystemUI/res-product/values-ja/strings.xml
index bc611d182191..0e7497aaa354 100644
--- a/packages/SystemUI/res-product/values-ja/strings.xml
+++ b/packages/SystemUI/res-product/values-ja/strings.xml
@@ -40,10 +40,7 @@
<string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4682221342671290678">"スマートフォンのロック解除に <xliff:g id="NUMBER">%d</xliff:g> 回失敗しました。仕事用プロファイルは削除され、プロファイルのデータはすべて消去されます。"</string>
<string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="1860049973474855672">"ロック解除パターンの入力を <xliff:g id="NUMBER_0">%1$d</xliff:g> 回間違えました。あと <xliff:g id="NUMBER_1">%2$d</xliff:g> 回間違えると、タブレットのロック解除にメール アカウントが必要になります。\n\n<xliff:g id="NUMBER_2">%3$d</xliff:g> 秒後にもう一度お試しください。"</string>
<string name="kg_failed_attempts_almost_at_login" product="default" msgid="44112553371516141">"ロック解除パターンの入力を <xliff:g id="NUMBER_0">%1$d</xliff:g> 回間違えました。あと <xliff:g id="NUMBER_1">%2$d</xliff:g> 回間違えると、スマートフォンのロック解除にメール アカウントが必要になります。\n\n<xliff:g id="NUMBER_2">%3$d</xliff:g> 秒後にもう一度お試しください。"</string>
- <!-- no translation found for global_action_lock_message (7092460751050168771) -->
- <skip />
- <!-- no translation found for global_action_lock_message (1024230056230539493) -->
- <skip />
- <!-- no translation found for global_action_lock_message (3165224897120346096) -->
- <skip />
+ <string name="global_action_lock_message" product="default" msgid="7092460751050168771">"スマートフォンのロックを解除してその他のオプションを表示する"</string>
+ <string name="global_action_lock_message" product="tablet" msgid="1024230056230539493">"タブレットのロックを解除してその他のオプションを表示する"</string>
+ <string name="global_action_lock_message" product="device" msgid="3165224897120346096">"デバイスのロックを解除してその他のオプションを表示する"</string>
</resources>
diff --git a/packages/SystemUI/res-product/values-ka/strings.xml b/packages/SystemUI/res-product/values-ka/strings.xml
index 0d47bed9b721..3d04a3c73a01 100644
--- a/packages/SystemUI/res-product/values-ka/strings.xml
+++ b/packages/SystemUI/res-product/values-ka/strings.xml
@@ -40,10 +40,7 @@
<string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4682221342671290678">"თქვენ არასწორად ცადეთ ტელეფონის განბლოკვა <xliff:g id="NUMBER">%d</xliff:g>-ჯერ. ამის გამო, სამსახურის პროფილი ამოიშლება, რაც პროფილის ყველა მონაცემის წაშლას გამოიწვევს."</string>
<string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="1860049973474855672">"თქვენ არასწორად დახატეთ თქვენი განბლოკვის ნიმუში <xliff:g id="NUMBER_0">%1$d</xliff:g>-ჯერ. კიდევ <xliff:g id="NUMBER_1">%2$d</xliff:g> წარუმატებელი მცდელობის შემდეგ მოგთხოვთ, ტაბლეტი თქვენი ელფოსტის ანგარიშის მეშვეობით განბლოკოთ.\n\n ცადეთ ხელახლა <xliff:g id="NUMBER_2">%3$d</xliff:g> წამში."</string>
<string name="kg_failed_attempts_almost_at_login" product="default" msgid="44112553371516141">"თქვენ არასწორად დახატეთ თქვენი განბლოკვის ნიმუში <xliff:g id="NUMBER_0">%1$d</xliff:g>-ჯერ. კიდევ <xliff:g id="NUMBER_1">%2$d</xliff:g> წარუმატებელი მცდელობის შემდეგ მოგთხოვთ, ტელეფონი თქვენი ელფოსტის ანგარიშის მეშვეობით განბლოკოთ.\n\n ცადეთ ხელახლა <xliff:g id="NUMBER_2">%3$d</xliff:g> წამში."</string>
- <!-- no translation found for global_action_lock_message (7092460751050168771) -->
- <skip />
- <!-- no translation found for global_action_lock_message (1024230056230539493) -->
- <skip />
- <!-- no translation found for global_action_lock_message (3165224897120346096) -->
- <skip />
+ <string name="global_action_lock_message" product="default" msgid="7092460751050168771">"მეტი ვარიანტის სანახავად განბლოკეთ თქვენი ტელეფონი"</string>
+ <string name="global_action_lock_message" product="tablet" msgid="1024230056230539493">"მეტი ვარიანტის სანახავად განბლოკეთ თქვენი ტაბლეტი"</string>
+ <string name="global_action_lock_message" product="device" msgid="3165224897120346096">"მეტი ვარიანტის სანახავად განბლოკეთ თქვენი მოწყობილობა"</string>
</resources>
diff --git a/packages/SystemUI/res-product/values-kk/strings.xml b/packages/SystemUI/res-product/values-kk/strings.xml
index 73c02d09c610..d2aec4bdccde 100644
--- a/packages/SystemUI/res-product/values-kk/strings.xml
+++ b/packages/SystemUI/res-product/values-kk/strings.xml
@@ -40,10 +40,7 @@
<string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4682221342671290678">"Телефон құлпын ашуға <xliff:g id="NUMBER">%d</xliff:g> рет сәтсіз әрекет жасалды. Жұмыс профилі өшіріліп, оның бүкіл деректері жойылады."</string>
<string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="1860049973474855672">"Құлыпты ашу өрнегі <xliff:g id="NUMBER_0">%1$d</xliff:g> рет қате енгізілді. <xliff:g id="NUMBER_1">%2$d</xliff:g> әрекет қалды. Одан кейін планшетті есептік жазба арқылы ашу сұралады. \n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> секундтан кейін әрекетті қайталаңыз."</string>
<string name="kg_failed_attempts_almost_at_login" product="default" msgid="44112553371516141">"Құлыпты ашу өрнегі <xliff:g id="NUMBER_0">%1$d</xliff:g> рет қате енгізілді. <xliff:g id="NUMBER_1">%2$d</xliff:g> әрекет қалды. Одан кейін телефонды есептік жазба арқылы ашу сұралады. \n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> секундтан кейін әрекетті қайталаңыз."</string>
- <!-- no translation found for global_action_lock_message (7092460751050168771) -->
- <skip />
- <!-- no translation found for global_action_lock_message (1024230056230539493) -->
- <skip />
- <!-- no translation found for global_action_lock_message (3165224897120346096) -->
- <skip />
+ <string name="global_action_lock_message" product="default" msgid="7092460751050168771">"Басқа опцияларды көру үшін телефон құлпын ашыңыз."</string>
+ <string name="global_action_lock_message" product="tablet" msgid="1024230056230539493">"Басқа опцияларды көру үшін планшет құлпын ашыңыз."</string>
+ <string name="global_action_lock_message" product="device" msgid="3165224897120346096">"Басқа опцияларды көру үшін құрылғы құлпын ашыңыз."</string>
</resources>
diff --git a/packages/SystemUI/res-product/values-km/strings.xml b/packages/SystemUI/res-product/values-km/strings.xml
index 5449a5b94866..0a840edc9503 100644
--- a/packages/SystemUI/res-product/values-km/strings.xml
+++ b/packages/SystemUI/res-product/values-km/strings.xml
@@ -40,10 +40,7 @@
<string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4682221342671290678">"អ្នក​បាន​ព្យាយាម​ដោះសោ​ទូរសព្ទ​នេះ​មិន​ត្រឹមត្រូវ​ចំនួន <xliff:g id="NUMBER">%d</xliff:g> ដង​ហើយ។ កម្រង​ព័ត៌មាន​ការងារ​នេះ​នឹង​ត្រូវ​បាន​លុប ហើយ​វា​នឹង​លុប​ទិន្នន័យ​កម្រង​ព័ត៌មាន​ទាំងអស់។"</string>
<string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="1860049973474855672">"អ្នក​បាន​គូរ​លំនាំ​ដោះ​សោ​របស់​អ្នក​មិន​ត្រឹមត្រូវ​ចំនួន <xliff:g id="NUMBER_0">%1$d</xliff:g> ដង​ហើយ។ បន្ទាប់ពីមានការ​ព្យាយាម​ដោះ​សោ​ចំនួន <xliff:g id="NUMBER_1">%2$d</xliff:g> ដងទៀត​មិន​ទទួល​បាន​ជោគជ័យ អ្នក​នឹង​ត្រូវ​បាន​ស្នើ​ឱ្យ​ដោះ​សោ​ថេប្លេត​របស់​អ្នក​ ដោយ​ប្រើ​គណនី​អ៊ីមែល។\n\n សូមព្យាយាម​ម្ដង​ទៀត​ក្នុង​រយៈ​ពេល <xliff:g id="NUMBER_2">%3$d</xliff:g> វិនាទី​ទៀត។"</string>
<string name="kg_failed_attempts_almost_at_login" product="default" msgid="44112553371516141">"អ្នកបានគូរលំនាំ​ដោះសោ​របស់អ្នក​មិន​ត្រឹមត្រូវចំនួន <xliff:g id="NUMBER_0">%1$d</xliff:g> ដងហើយ។ បន្ទាប់ពីមាន​ការព្យាយាម​ដោះសោចំនួន <xliff:g id="NUMBER_1">%2$d</xliff:g> ដងទៀតមិនទទួលបាន​ជោគជ័យ អ្នកនឹង​ត្រូវបាន​ស្នើឱ្យ​ដោះសោ​ទូរសព្ទ​របស់​អ្នកដោយ​ប្រើគណនី​អ៊ីមែល។\n\n សូមព្យាយាម​ម្ដងទៀតក្នុង​រយៈពេល <xliff:g id="NUMBER_2">%3$d</xliff:g> វិនាទីទៀត។"</string>
- <!-- no translation found for global_action_lock_message (7092460751050168771) -->
- <skip />
- <!-- no translation found for global_action_lock_message (1024230056230539493) -->
- <skip />
- <!-- no translation found for global_action_lock_message (3165224897120346096) -->
- <skip />
+ <string name="global_action_lock_message" product="default" msgid="7092460751050168771">"ដោះសោ​ទូរសព្ទរបស់អ្នក​សម្រាប់​ជម្រើសច្រើនទៀត"</string>
+ <string name="global_action_lock_message" product="tablet" msgid="1024230056230539493">"ដោះសោ​ថេប្លេតរបស់អ្នក​សម្រាប់​ជម្រើសច្រើនទៀត"</string>
+ <string name="global_action_lock_message" product="device" msgid="3165224897120346096">"ដោះសោ​ឧបករណ៍របស់អ្នក​សម្រាប់​ជម្រើសច្រើនទៀត"</string>
</resources>
diff --git a/packages/SystemUI/res-product/values-kn/strings.xml b/packages/SystemUI/res-product/values-kn/strings.xml
index 7b195ce5c086..1b0f8bd127aa 100644
--- a/packages/SystemUI/res-product/values-kn/strings.xml
+++ b/packages/SystemUI/res-product/values-kn/strings.xml
@@ -40,10 +40,7 @@
<string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4682221342671290678">"ಫೋನ್ ಅನ್ನು ಅನ್‌ಲಾಕ್ ಮಾಡಲು ನೀವು <xliff:g id="NUMBER">%d</xliff:g> ಬಾರಿ ತಪ್ಪಾಗಿ ಪ್ರಯತ್ನಿಸಿದ್ದೀರಿ. ಉದ್ಯೋಗ ಪ್ರೊಫೈಲ್ ಅನ್ನು ತೆಗೆದುಹಾಕಲಾಗುತ್ತದೆ, ಇದು ಪ್ರೊಫೈಲ್‌ನ ಎಲ್ಲಾ ಡೇಟಾವನ್ನು ಅಳಿಸುತ್ತದೆ."</string>
<string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="1860049973474855672">"ನಿಮ್ಮ ಅನ್‍‍ಲಾಕ್ ಪ್ಯಾಟರ್ನ್ ಅನ್ನು ನೀವು <xliff:g id="NUMBER_0">%1$d</xliff:g> ಬಾರಿ ತಪ್ಪಾಗಿ ಡ್ರಾ ಮಾಡಿರುವಿರಿ. <xliff:g id="NUMBER_1">%2$d</xliff:g> ಕ್ಕೂ ಹೆಚ್ಚಿನ ವಿಫಲ ಪ್ರಯತ್ನಗಳ ಬಳಿಕ, ನಿಮ್ಮ ಇಮೇಲ್ ಖಾತೆಯನ್ನು ಬಳಸಿ ಟ್ಯಾಬ್ಲೆಟ್ ಅನ್‌ಲಾಕ್ ಮಾಡಲು ನಿಮ್ಮನ್ನು ಕೇಳಲಾಗುತ್ತದೆ.\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> ಸೆಕೆಂಡ್‌ಗಳಲ್ಲಿ ಪುನಃ ಪ್ರಯತ್ನಿಸಿ."</string>
<string name="kg_failed_attempts_almost_at_login" product="default" msgid="44112553371516141">"ನಿಮ್ಮ ಅನ್‍‍ಲಾಕ್ ಪ್ಯಾಟರ್ನ್ ಅನ್ನು ನೀವು <xliff:g id="NUMBER_0">%1$d</xliff:g> ಬಾರಿ ತಪ್ಪಾಗಿ ಡ್ರಾ ಮಾಡಿರುವಿರಿ. <xliff:g id="NUMBER_1">%2$d</xliff:g> ಕ್ಕೂ ಹೆಚ್ಚಿನ ವಿಫಲ ಪ್ರಯತ್ನಗಳ ಬಳಿಕ, ಇಮೇಲ್ ಖಾತೆಯನ್ನು ಬಳಸಿ ನಿಮ್ಮ ಫೋನ್ ಅನ್‌ಲಾಕ್ ಮಾಡಲು ನಿಮ್ಮನ್ನು ಕೇಳಲಾಗುತ್ತದೆ.\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> ಸೆಕೆಂಡ್‌ಗಳಲ್ಲಿ ಪುನಃ ಪ್ರಯತ್ನಿಸಿ."</string>
- <!-- no translation found for global_action_lock_message (7092460751050168771) -->
- <skip />
- <!-- no translation found for global_action_lock_message (1024230056230539493) -->
- <skip />
- <!-- no translation found for global_action_lock_message (3165224897120346096) -->
- <skip />
+ <string name="global_action_lock_message" product="default" msgid="7092460751050168771">"ಹೆಚ್ಚಿನ ಆಯ್ಕೆಗಳಿಗಾಗಿ ನಿಮ್ಮ ಫೋನ್ ಅನ್ನು ಅನ್‌ಲಾಕ್ ಮಾಡಿ"</string>
+ <string name="global_action_lock_message" product="tablet" msgid="1024230056230539493">"ಹೆಚ್ಚಿನ ಆಯ್ಕೆಗಳಿಗಾಗಿ ನಿಮ್ಮ ಟ್ಯಾಬ್ಲೆಟ್ ಅನ್ನು ಅನ್‌ಲಾಕ್ ಮಾಡಿ"</string>
+ <string name="global_action_lock_message" product="device" msgid="3165224897120346096">"ಹೆಚ್ಚಿನ ಆಯ್ಕೆಗಳಿಗಾಗಿ ನಿಮ್ಮ ಸಾಧನವನ್ನು ಅನ್‌ಲಾಕ್ ಮಾಡಿ"</string>
</resources>
diff --git a/packages/SystemUI/res-product/values-ko/strings.xml b/packages/SystemUI/res-product/values-ko/strings.xml
index cb2dc008f6ac..3629f2f3761b 100644
--- a/packages/SystemUI/res-product/values-ko/strings.xml
+++ b/packages/SystemUI/res-product/values-ko/strings.xml
@@ -40,10 +40,7 @@
<string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4682221342671290678">"휴대전화 잠금 해제에 <xliff:g id="NUMBER">%d</xliff:g>번 실패했습니다. 직장 프로필과 모든 프로필 데이터가 삭제됩니다."</string>
<string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="1860049973474855672">"잠금 해제 패턴을 <xliff:g id="NUMBER_0">%1$d</xliff:g>회 잘못 그렸습니다. <xliff:g id="NUMBER_1">%2$d</xliff:g>회 더 실패하면 이메일 계정을 사용하여 태블릿을 잠금 해제해야 합니다.\n\n<xliff:g id="NUMBER_2">%3$d</xliff:g>초 후에 다시 시도해 주세요."</string>
<string name="kg_failed_attempts_almost_at_login" product="default" msgid="44112553371516141">"잠금 해제 패턴을 <xliff:g id="NUMBER_0">%1$d</xliff:g>회 잘못 그렸습니다. <xliff:g id="NUMBER_1">%2$d</xliff:g>회 더 실패하면 이메일 계정을 사용하여 휴대전화를 잠금 해제해야 합니다.\n\n<xliff:g id="NUMBER_2">%3$d</xliff:g>초 후에 다시 시도해 주세요."</string>
- <!-- no translation found for global_action_lock_message (7092460751050168771) -->
- <skip />
- <!-- no translation found for global_action_lock_message (1024230056230539493) -->
- <skip />
- <!-- no translation found for global_action_lock_message (3165224897120346096) -->
- <skip />
+ <string name="global_action_lock_message" product="default" msgid="7092460751050168771">"더 많은 옵션을 확인하려면 휴대전화를 잠금 해제하세요."</string>
+ <string name="global_action_lock_message" product="tablet" msgid="1024230056230539493">"더 많은 옵션을 확인하려면 태블릿을 잠금 해제하세요."</string>
+ <string name="global_action_lock_message" product="device" msgid="3165224897120346096">"더 많은 옵션을 확인하려면 기기를 잠금 해제하세요."</string>
</resources>
diff --git a/packages/SystemUI/res-product/values-ky/strings.xml b/packages/SystemUI/res-product/values-ky/strings.xml
index 7bdcb55cefe0..4eb90caa4391 100644
--- a/packages/SystemUI/res-product/values-ky/strings.xml
+++ b/packages/SystemUI/res-product/values-ky/strings.xml
@@ -40,10 +40,7 @@
<string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4682221342671290678">"Телефондун кулпусун <xliff:g id="NUMBER">%d</xliff:g> жолу туура эмес ачууга аракет жасадыңыз. Жумуш профили өчүрүлүп, андагы бардык маалымат өчүрүлөт."</string>
<string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="1860049973474855672">"Графикалык ачкычты <xliff:g id="NUMBER_0">%1$d</xliff:g> жолу туура эмес тарттыңыз. Дагы <xliff:g id="NUMBER_1">%2$d</xliff:g> ийгиликсиз аракеттен кийин планшетиңизди бөгөттөн электрондук почтаңыз аркылуу чыгаруу талап кылынат.\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> секунддан кийин кайра аракеттениңиз."</string>
<string name="kg_failed_attempts_almost_at_login" product="default" msgid="44112553371516141">"Графикалык ачкычты <xliff:g id="NUMBER_0">%1$d</xliff:g> жолу туура эмес тарттыңыз. Дагы <xliff:g id="NUMBER_1">%2$d</xliff:g> ийгиликсиз аракеттен кийин телефонуңузду бөгөттөн электрондук почтаңыз аркылуу чыгаруу талап кылынат.\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> секунддан кийин кайра аракеттениңиз."</string>
- <!-- no translation found for global_action_lock_message (7092460751050168771) -->
- <skip />
- <!-- no translation found for global_action_lock_message (1024230056230539493) -->
- <skip />
- <!-- no translation found for global_action_lock_message (3165224897120346096) -->
- <skip />
+ <string name="global_action_lock_message" product="default" msgid="7092460751050168771">"Дагы башка параметрлерди көрүү үчүн телефонуңуздун кулпусун ачыңыз"</string>
+ <string name="global_action_lock_message" product="tablet" msgid="1024230056230539493">"Дагы башка параметрлерди көрүү үчүн планшетиңиздин кулпусун ачыңыз"</string>
+ <string name="global_action_lock_message" product="device" msgid="3165224897120346096">"Дагы башка параметрлерди көрүү үчүн түзмөгүңүздүн кулпусун ачыңыз"</string>
</resources>
diff --git a/packages/SystemUI/res-product/values-lo/strings.xml b/packages/SystemUI/res-product/values-lo/strings.xml
index c66059c4ecab..2b262e7008f5 100644
--- a/packages/SystemUI/res-product/values-lo/strings.xml
+++ b/packages/SystemUI/res-product/values-lo/strings.xml
@@ -40,10 +40,7 @@
<string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4682221342671290678">"ທ່ານພະຍາຍາມປົດລັອກໂທລະສັບຜິດ <xliff:g id="NUMBER">%d</xliff:g> ເທື່ອແລ້ວ. ໂປຣໄຟລ໌ບ່ອນເຮັດວຽກຈະຖືກລຶບອອກ, ເຊິ່ງຈະລຶບຂໍ້ມູນໂປຣໄຟລ໌ທັງໝົດອອກນຳ."</string>
<string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="1860049973474855672">"ທ່ານແຕ້ມຮູບແບບປົດລັອກຜິດ <xliff:g id="NUMBER_0">%1$d</xliff:g> ເທື່ອແລ້ວ. ຫຼັງຈາກແຕ້ມຜິດອີກ <xliff:g id="NUMBER_1">%2$d</xliff:g> ເທື່ອ, ທ່ານຈະຖືກຖາມໃຫ້ປົດລັອກແທັບເລັດຂອງທ່ານດ້ວຍການເຂົ້າສູ່ລະບົບໂດຍໃຊ້ອີເມວຂອງທ່ານ.\n\n ກະລຸນາລອງໃໝ່ໃນອີກ <xliff:g id="NUMBER_2">%3$d</xliff:g> ວິນາທີ."</string>
<string name="kg_failed_attempts_almost_at_login" product="default" msgid="44112553371516141">"ທ່ານແຕ້ມຮູບແບບປົດລັອກຜິດ <xliff:g id="NUMBER_0">%1$d</xliff:g> ເທື່ອແລ້ວ. ຫຼັງຈາກແຕ້ມຜິດອີກ <xliff:g id="NUMBER_1">%2$d</xliff:g> ເທື່ອ, ທ່ານຈະຖືກຖາມໃຫ້ປົດໂທລະສັບຂອງທ່ານດ້ວຍການເຂົ້າສູ່ລະບົບໂດຍໃຊ້ບັນຊີອີເມວ.\n\n ກະລຸນາລອງໃໝ່ໃນອີກ <xliff:g id="NUMBER_2">%3$d</xliff:g> ວິນາທີ."</string>
- <!-- no translation found for global_action_lock_message (7092460751050168771) -->
- <skip />
- <!-- no translation found for global_action_lock_message (1024230056230539493) -->
- <skip />
- <!-- no translation found for global_action_lock_message (3165224897120346096) -->
- <skip />
+ <string name="global_action_lock_message" product="default" msgid="7092460751050168771">"ປົດລັອກໂທລະສັບຂອງທ່ານເພື່ອໃຊ້ຕົວເລືອກເພີ່ມເຕີມ"</string>
+ <string name="global_action_lock_message" product="tablet" msgid="1024230056230539493">"ປົດລັອກແທັບເລັດຂອງທ່ານເພື່ອໃຊ້ຕົວເລືອກເພີ່ມເຕີມ"</string>
+ <string name="global_action_lock_message" product="device" msgid="3165224897120346096">"ປົດລັອກອຸປະກອນຂອງທ່ານເພື່ອໃຊ້ຕົວເລືອກເພີ່ມເຕີມ"</string>
</resources>
diff --git a/packages/SystemUI/res-product/values-lt/strings.xml b/packages/SystemUI/res-product/values-lt/strings.xml
index 3771d4386c8d..8ac5895ce065 100644
--- a/packages/SystemUI/res-product/values-lt/strings.xml
+++ b/packages/SystemUI/res-product/values-lt/strings.xml
@@ -40,10 +40,7 @@
<string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4682221342671290678">"<xliff:g id="NUMBER">%d</xliff:g> kart. nesėkmingai bandėte atrakinti telefoną. Darbo profilis bus pašalintas ir visi profilio duomenys bus ištrinti."</string>
<string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="1860049973474855672">"<xliff:g id="NUMBER_0">%1$d</xliff:g> kart. netinkamai nupiešėte atrakinimo piešinį. Po dar <xliff:g id="NUMBER_1">%2$d</xliff:g> nesėkm. band. būsite paprašyti atrakinti planšetinį kompiuterį naudodami el. pašto paskyrą.\n\n Bandykite dar kartą po <xliff:g id="NUMBER_2">%3$d</xliff:g> sek."</string>
<string name="kg_failed_attempts_almost_at_login" product="default" msgid="44112553371516141">"<xliff:g id="NUMBER_0">%1$d</xliff:g> kart. netinkamai nupiešėte atrakinimo piešinį. Po dar <xliff:g id="NUMBER_1">%2$d</xliff:g> nesėkm. band. būsite paprašyti atrakinti telefoną naudodami el. pašto paskyrą.\n\n Bandykite dar kartą po <xliff:g id="NUMBER_2">%3$d</xliff:g> sek."</string>
- <!-- no translation found for global_action_lock_message (7092460751050168771) -->
- <skip />
- <!-- no translation found for global_action_lock_message (1024230056230539493) -->
- <skip />
- <!-- no translation found for global_action_lock_message (3165224897120346096) -->
- <skip />
+ <string name="global_action_lock_message" product="default" msgid="7092460751050168771">"Atrakinkite telefoną, kad galėtumėte naudoti daugiau parinkčių"</string>
+ <string name="global_action_lock_message" product="tablet" msgid="1024230056230539493">"Atrakinkite planšetinį kompiuterį, kad galėtumėte naudoti daugiau parinkčių"</string>
+ <string name="global_action_lock_message" product="device" msgid="3165224897120346096">"Atrakinkite įrenginį, kad galėtumėte naudoti daugiau parinkčių"</string>
</resources>
diff --git a/packages/SystemUI/res-product/values-lv/strings.xml b/packages/SystemUI/res-product/values-lv/strings.xml
index 65f757f57bac..174f5d215634 100644
--- a/packages/SystemUI/res-product/values-lv/strings.xml
+++ b/packages/SystemUI/res-product/values-lv/strings.xml
@@ -40,10 +40,7 @@
<string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4682221342671290678">"Jūs <xliff:g id="NUMBER">%d</xliff:g> reizi(-es) nesekmīgi mēģinājāt atbloķēt tālruni. Darba profils tiks noņemts, kā arī visi profila dati tiks dzēsti."</string>
<string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="1860049973474855672">"Jūs <xliff:g id="NUMBER_0">%1$d</xliff:g> reizi(-es) nepareizi norādījāt atbloķēšanas kombināciju. Pēc vēl <xliff:g id="NUMBER_1">%2$d</xliff:g> neveiksmīga(-iem) mēģinājuma(-iem) planšetdators būs jāatbloķē, izmantojot e-pasta kontu.\n\nMēģiniet vēlreiz pēc <xliff:g id="NUMBER_2">%3$d</xliff:g> sekundes(-ēm)."</string>
<string name="kg_failed_attempts_almost_at_login" product="default" msgid="44112553371516141">"Jūs <xliff:g id="NUMBER_0">%1$d</xliff:g> reizi(-es) nepareizi norādījāt atbloķēšanas kombināciju. Pēc vēl <xliff:g id="NUMBER_1">%2$d</xliff:g> nesekmīga(-iem) mēģinājuma(-iem) tālrunis būs jāatbloķē, izmantojot e-pasta kontu.\n\nMēģiniet vēlreiz pēc <xliff:g id="NUMBER_2">%3$d</xliff:g> sekundes(-ēm)."</string>
- <!-- no translation found for global_action_lock_message (7092460751050168771) -->
- <skip />
- <!-- no translation found for global_action_lock_message (1024230056230539493) -->
- <skip />
- <!-- no translation found for global_action_lock_message (3165224897120346096) -->
- <skip />
+ <string name="global_action_lock_message" product="default" msgid="7092460751050168771">"Atbloķējiet tālruni, lai skatītu citas opcijas."</string>
+ <string name="global_action_lock_message" product="tablet" msgid="1024230056230539493">"Atbloķējiet planšetdatoru, lai skatītu citas opcijas."</string>
+ <string name="global_action_lock_message" product="device" msgid="3165224897120346096">"Atbloķējiet ierīci, lai skatītu citas opcijas."</string>
</resources>
diff --git a/packages/SystemUI/res-product/values-mk/strings.xml b/packages/SystemUI/res-product/values-mk/strings.xml
index 7df263429a53..86ff8d1c9c7a 100644
--- a/packages/SystemUI/res-product/values-mk/strings.xml
+++ b/packages/SystemUI/res-product/values-mk/strings.xml
@@ -40,10 +40,7 @@
<string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4682221342671290678">"Погрешно се обидовте да го отклучите телефонот <xliff:g id="NUMBER">%d</xliff:g> пати. Работниот профил ќе се отстрани, со што ќе се избришат сите податоци на профилот."</string>
<string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="1860049973474855672">"Погрешно ја употребивте вашата шема на отклучување <xliff:g id="NUMBER_0">%1$d</xliff:g> пати. По уште <xliff:g id="NUMBER_1">%2$d</xliff:g> неуспешни обиди, ќе побараме да го отклучите таблетот со сметка на е-пошта.\n\n Обидете се повторно за <xliff:g id="NUMBER_2">%3$d</xliff:g> секунди."</string>
<string name="kg_failed_attempts_almost_at_login" product="default" msgid="44112553371516141">"Погрешно ја употребивте вашата шема на отклучување <xliff:g id="NUMBER_0">%1$d</xliff:g> пати. По уште <xliff:g id="NUMBER_1">%2$d</xliff:g> неуспешни обиди, ќе побараме да го отклучите телефонот со сметка на е-пошта.\n\n Обидете се повторно за <xliff:g id="NUMBER_2">%3$d</xliff:g> секунди."</string>
- <!-- no translation found for global_action_lock_message (7092460751050168771) -->
- <skip />
- <!-- no translation found for global_action_lock_message (1024230056230539493) -->
- <skip />
- <!-- no translation found for global_action_lock_message (3165224897120346096) -->
- <skip />
+ <string name="global_action_lock_message" product="default" msgid="7092460751050168771">"Отклучето го вашиот телефон за повеќе опции"</string>
+ <string name="global_action_lock_message" product="tablet" msgid="1024230056230539493">"Отклучето го вашиот таблет за повеќе опции"</string>
+ <string name="global_action_lock_message" product="device" msgid="3165224897120346096">"Отклучето го вашиот уред за повеќе опции"</string>
</resources>
diff --git a/packages/SystemUI/res-product/values-ml/strings.xml b/packages/SystemUI/res-product/values-ml/strings.xml
index 3cf933cfc3f2..284f55264909 100644
--- a/packages/SystemUI/res-product/values-ml/strings.xml
+++ b/packages/SystemUI/res-product/values-ml/strings.xml
@@ -40,10 +40,7 @@
<string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4682221342671290678">"നിങ്ങൾ <xliff:g id="NUMBER">%d</xliff:g> തവണ തെറ്റായ രീതിയിൽ ഫോൺ അൺലോക്ക് ചെയ്യാൻ ശ്രമിച്ചു. ഔദ്യോഗിക പ്രൊഫൈൽ നീക്കം ചെയ്യപ്പെടുകയും, അതുവഴി എല്ലാ പ്രൊഫൈൽ ഡാറ്റയും ഇല്ലാതാകുകയും ചെയ്യും."</string>
<string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="1860049973474855672">"നിങ്ങൾ <xliff:g id="NUMBER_0">%1$d</xliff:g> തവണ തെറ്റായ രീതിയിൽ അൺലോക്ക് പാറ്റേൺ വരച്ചു. <xliff:g id="NUMBER_1">%2$d</xliff:g> ശ്രമങ്ങൾ കൂടി പരാജയപ്പെട്ടാൽ, ഒരു ഇമെയിൽ അക്കൗണ്ടുപയോഗിച്ച് ടാബ്‌ലെറ്റ് അൺലോക്ക് ചെയ്യാൻ നിങ്ങളോട് ആവശ്യപ്പെടും.\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> സെക്കന്റ് കഴിഞ്ഞ് വീണ്ടും ശ്രമിക്കുക."</string>
<string name="kg_failed_attempts_almost_at_login" product="default" msgid="44112553371516141">"നിങ്ങൾ <xliff:g id="NUMBER_0">%1$d</xliff:g> തവണ തെറ്റായ രീതിയിൽ അൺലോക്ക് പാറ്റേൺ വരച്ചു. <xliff:g id="NUMBER_1">%2$d</xliff:g> ശ്രമങ്ങൾ കൂടി പരാജയപ്പെട്ടാൽ, ഒരു ഇമെയിൽ അക്കൗണ്ടുപയോഗിച്ച് ഫോൺ അൺലോക്ക് ചെയ്യാൻ നിങ്ങളോട് ആവശ്യപ്പെടും.\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> സെക്കന്റ് കഴിഞ്ഞ് വീണ്ടും ശ്രമിക്കുക."</string>
- <!-- no translation found for global_action_lock_message (7092460751050168771) -->
- <skip />
- <!-- no translation found for global_action_lock_message (1024230056230539493) -->
- <skip />
- <!-- no translation found for global_action_lock_message (3165224897120346096) -->
- <skip />
+ <string name="global_action_lock_message" product="default" msgid="7092460751050168771">"കൂടുതൽ ഓപ്ഷനുകൾക്ക് നിങ്ങളുടെ ഫോൺ അൺലോക്ക് ചെയ്യുക"</string>
+ <string name="global_action_lock_message" product="tablet" msgid="1024230056230539493">"കൂടുതൽ ഓപ്ഷനുകൾക്ക് നിങ്ങളുടെ ടാബ്‌ലെറ്റ് അൺലോക്ക് ചെയ്യുക"</string>
+ <string name="global_action_lock_message" product="device" msgid="3165224897120346096">"കൂടുതൽ ഓപ്ഷനുകൾക്ക് നിങ്ങളുടെ ഉപകരണം അൺലോക്ക് ചെയ്യുക"</string>
</resources>
diff --git a/packages/SystemUI/res-product/values-mn/strings.xml b/packages/SystemUI/res-product/values-mn/strings.xml
index cb6448a01132..6a0f668986f8 100644
--- a/packages/SystemUI/res-product/values-mn/strings.xml
+++ b/packages/SystemUI/res-product/values-mn/strings.xml
@@ -40,10 +40,7 @@
<string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4682221342671290678">"Та утасны түгжээг тайлах оролдлогыг <xliff:g id="NUMBER">%d</xliff:g> удаа буруу хийсэн байна. Ажлын профайлыг устгах бөгөөд ингэснээр профайлын бүх өгөгдлийг устгах болно."</string>
<string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="1860049973474855672">"Та тайлах хээгээ <xliff:g id="NUMBER_0">%1$d</xliff:g> удаа буруу зурсан байна. Дахин <xliff:g id="NUMBER_1">%2$d</xliff:g> удаа буруу зурсны дараа та имэйл бүртгэл ашиглан таблетынхаа түгжээг тайлах шаардлагатай болно.\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> секундийн дараа дахин оролдоно уу."</string>
<string name="kg_failed_attempts_almost_at_login" product="default" msgid="44112553371516141">"Та тайлах хээгээ <xliff:g id="NUMBER_0">%1$d</xliff:g> удаа буруу зурсан байна. Дахин <xliff:g id="NUMBER_1">%2$d</xliff:g> удаа буруу зурсны дараа та имэйл бүртгэл ашиглан утасныхаа түгжээг тайлах шаардлагатай болно.\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> секундийн дараа дахин оролдоно уу."</string>
- <!-- no translation found for global_action_lock_message (7092460751050168771) -->
- <skip />
- <!-- no translation found for global_action_lock_message (1024230056230539493) -->
- <skip />
- <!-- no translation found for global_action_lock_message (3165224897120346096) -->
- <skip />
+ <string name="global_action_lock_message" product="default" msgid="7092460751050168771">"Бусад сонголтыг харахын тулд утасныхаа түгжээг тайлна уу"</string>
+ <string name="global_action_lock_message" product="tablet" msgid="1024230056230539493">"Бусад сонголтыг харахын тулд таблетынхаа түгжээг тайлна уу"</string>
+ <string name="global_action_lock_message" product="device" msgid="3165224897120346096">"Бусад сонголтыг харахын тулд төхөөрөмжийнхөө түгжээг тайлна уу"</string>
</resources>
diff --git a/packages/SystemUI/res-product/values-mr/strings.xml b/packages/SystemUI/res-product/values-mr/strings.xml
index 4854a8285664..c9cd4ba8442b 100644
--- a/packages/SystemUI/res-product/values-mr/strings.xml
+++ b/packages/SystemUI/res-product/values-mr/strings.xml
@@ -40,10 +40,7 @@
<string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4682221342671290678">"तुम्ही फोन अनलॉक करण्याचा <xliff:g id="NUMBER">%d</xliff:g> वेळा चुकीच्या पद्धतीने प्रयत्न केला आहे. कार्य प्रोफाइल काढली जाईल, त्यामुळे सर्व प्रोफाइल डेटा हटवला जाईल."</string>
<string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="1860049973474855672">"तुम्ही तुमचा अनलॉक पॅटर्न <xliff:g id="NUMBER_0">%1$d</xliff:g> वेळा चुकीच्या पद्धतीने काढला आहे. आणखी <xliff:g id="NUMBER_1">%2$d</xliff:g> अयशस्वी प्रयत्नांनंतर, तुम्हाला ईमेल खाते वापरून तुमचा टॅबलेट अनलॉक करण्यास सांगितले जाईल.\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> सेकंदांमध्ये पुन्हा प्रयत्न करा."</string>
<string name="kg_failed_attempts_almost_at_login" product="default" msgid="44112553371516141">"तुम्ही तुमचा अनलॉक पॅटर्न <xliff:g id="NUMBER_0">%1$d</xliff:g> वेळा चुकीच्या पद्धतीने काढला आहे. आणखी <xliff:g id="NUMBER_1">%2$d</xliff:g> अयशस्वी प्रयत्नांनंतर, तुम्हाला ईमेल खाते वापरून तुमचा फोन अनलॉक करण्यास सांगितले जाईल.\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> सेकंदांमध्ये पुन्हा प्रयत्न करा."</string>
- <!-- no translation found for global_action_lock_message (7092460751050168771) -->
- <skip />
- <!-- no translation found for global_action_lock_message (1024230056230539493) -->
- <skip />
- <!-- no translation found for global_action_lock_message (3165224897120346096) -->
- <skip />
+ <string name="global_action_lock_message" product="default" msgid="7092460751050168771">"आणखी पर्यायांसाठी तुमचा फोन अनलॉक करा"</string>
+ <string name="global_action_lock_message" product="tablet" msgid="1024230056230539493">"आणखी पर्यायांसाठी तुमचा टॅबलेट अनलॉक करा"</string>
+ <string name="global_action_lock_message" product="device" msgid="3165224897120346096">"आणखी पर्यायांसाठी तुमचे डिव्हाइस अनलॉक करा"</string>
</resources>
diff --git a/packages/SystemUI/res-product/values-ms/strings.xml b/packages/SystemUI/res-product/values-ms/strings.xml
index e93d394a5a6e..ded2b3d1f89d 100644
--- a/packages/SystemUI/res-product/values-ms/strings.xml
+++ b/packages/SystemUI/res-product/values-ms/strings.xml
@@ -40,10 +40,7 @@
<string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4682221342671290678">"Anda telah salah membuka kunci telefon sebanyak <xliff:g id="NUMBER">%d</xliff:g> kali. Profil kerja ini akan dialih keluar sekali gus memadamkan semua data profil."</string>
<string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="1860049973474855672">"Anda telah tersilap lukis corak buka kunci sebanyak <xliff:g id="NUMBER_0">%1$d</xliff:g> kali. Selepas <xliff:g id="NUMBER_1">%2$d</xliff:g> lagi percubaan yang gagal, anda akan diminta membuka kunci tablet anda menggunakan akaun e-mel.\n\n Cuba lagi dalam <xliff:g id="NUMBER_2">%3$d</xliff:g> saat."</string>
<string name="kg_failed_attempts_almost_at_login" product="default" msgid="44112553371516141">"Anda telah tersilap lukis corak buka kunci sebanyak <xliff:g id="NUMBER_0">%1$d</xliff:g> kali. Selepas <xliff:g id="NUMBER_1">%2$d</xliff:g> lagi percubaan yang gagal, anda akan diminta membuka kunci telefon anda menggunakan akaun e-mel.\n\n Cuba lagi dalam <xliff:g id="NUMBER_2">%3$d</xliff:g> saat."</string>
- <!-- no translation found for global_action_lock_message (7092460751050168771) -->
- <skip />
- <!-- no translation found for global_action_lock_message (1024230056230539493) -->
- <skip />
- <!-- no translation found for global_action_lock_message (3165224897120346096) -->
- <skip />
+ <string name="global_action_lock_message" product="default" msgid="7092460751050168771">"Buka kunci telefon anda untuk mendapatkan lagi pilihan"</string>
+ <string name="global_action_lock_message" product="tablet" msgid="1024230056230539493">"Buka kunci tablet anda untuk mendapatkan lagi pilihan"</string>
+ <string name="global_action_lock_message" product="device" msgid="3165224897120346096">"Buka kunci peranti anda untuk mendapatkan lagi pilihan"</string>
</resources>
diff --git a/packages/SystemUI/res-product/values-my/strings.xml b/packages/SystemUI/res-product/values-my/strings.xml
index 8ff643c837b6..43c2aca274ee 100644
--- a/packages/SystemUI/res-product/values-my/strings.xml
+++ b/packages/SystemUI/res-product/values-my/strings.xml
@@ -40,10 +40,7 @@
<string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4682221342671290678">"ဖုန်းကို <xliff:g id="NUMBER">%d</xliff:g> ကြိမ် မှားယွင်းစွာ လော့ခ်ဖွင့်ရန် ကြိုးစားခဲ့ပါသည်။ အလုပ်ပရိုဖိုင်ကို ဖယ်ရှားလိုက်မည်ဖြစ်ပြီး ပရိုဖိုင်ဒေတာ အားလုံးကိုလည်း ဖျက်လိုက်ပါမည်။"</string>
<string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="1860049973474855672">"သင်သည် သင်၏ လော့ခ်ဖွင့်ခြင်းပုံစံကို <xliff:g id="NUMBER_0">%1$d</xliff:g> ကြိမ် မှားယွင်းစွာ ဆွဲခဲ့ပါသည်။ <xliff:g id="NUMBER_1">%2$d</xliff:g> ကြိမ် ထပ်မံမှားယွင်းပြီးသည့်နောက်တွင် သင့်အီးမေးလ်အကောင့်အား အသုံးပြု၍ တက်ဘလက်ကို လော့ခ်ဖွင့်ရန် တောင်းဆိုသွားပါမည်။\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> စက္ကန့်အကြာတွင် ထပ်စမ်းကြည့်ပါ။"</string>
<string name="kg_failed_attempts_almost_at_login" product="default" msgid="44112553371516141">"သင်သည် သင်၏ လော့ခ်ဖွင့်ခြင်းပုံစံကို <xliff:g id="NUMBER_0">%1$d</xliff:g> ကြိမ် မှားယွင်းစွာ ဆွဲခဲ့ပါသည်။ <xliff:g id="NUMBER_1">%2$d</xliff:g> ကြိမ် ထပ်မံမှားယွင်းပြီးသည့်နောက်တွင် သင့်အီးမေးလ်အကောင့်အား အသုံးပြု၍ ဖုန်းကို လော့ခ်ဖွင့်ရန် တောင်းဆိုသွားပါမည်။\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> စက္ကန့်အကြာတွင် ထပ်စမ်းကြည့်ပါ။"</string>
- <!-- no translation found for global_action_lock_message (7092460751050168771) -->
- <skip />
- <!-- no translation found for global_action_lock_message (1024230056230539493) -->
- <skip />
- <!-- no translation found for global_action_lock_message (3165224897120346096) -->
- <skip />
+ <string name="global_action_lock_message" product="default" msgid="7092460751050168771">"နောက်ထပ် ထိန်းချုပ်မှုများအတွက် သင့်ဖုန်းကို လော့ခ်ဖွင့်ပါ"</string>
+ <string name="global_action_lock_message" product="tablet" msgid="1024230056230539493">"နောက်ထပ် ထိန်းချုပ်မှုများအတွက် သင့်တက်ဘလက်ကို လော့ခ်ဖွင့်ပါ"</string>
+ <string name="global_action_lock_message" product="device" msgid="3165224897120346096">"နောက်ထပ် ထိန်းချုပ်မှုများအတွက် သင့်စက်ကို လော့ခ်ဖွင့်ပါ"</string>
</resources>
diff --git a/packages/SystemUI/res-product/values-nb/strings.xml b/packages/SystemUI/res-product/values-nb/strings.xml
index 56817f5a3307..c7d5bb1263db 100644
--- a/packages/SystemUI/res-product/values-nb/strings.xml
+++ b/packages/SystemUI/res-product/values-nb/strings.xml
@@ -40,10 +40,7 @@
<string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4682221342671290678">"Du har gjort feil i forsøket på å låse opp telefonen <xliff:g id="NUMBER">%d</xliff:g> ganger. Jobbprofilen blir fjernet, og alle profildataene blir slettet."</string>
<string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="1860049973474855672">"Du har tegnet opplåsingsmønsteret feil <xliff:g id="NUMBER_0">%1$d</xliff:g> ganger. Etter ytterligere <xliff:g id="NUMBER_1">%2$d</xliff:g> nye mislykkede forsøk blir du bedt om å låse opp nettbrettet via en e-postkonto.\n\n Prøv på nytt om <xliff:g id="NUMBER_2">%3$d</xliff:g> sekunder."</string>
<string name="kg_failed_attempts_almost_at_login" product="default" msgid="44112553371516141">"Du har tegnet opplåsingsmønsteret feil <xliff:g id="NUMBER_0">%1$d</xliff:g> ganger. Etter ytterligere <xliff:g id="NUMBER_1">%2$d</xliff:g> nye mislykkede forsøk blir du bedt om å låse opp telefonen via en e-postkonto.\n\n Prøv på nytt om <xliff:g id="NUMBER_2">%3$d</xliff:g> sekunder."</string>
- <!-- no translation found for global_action_lock_message (7092460751050168771) -->
- <skip />
- <!-- no translation found for global_action_lock_message (1024230056230539493) -->
- <skip />
- <!-- no translation found for global_action_lock_message (3165224897120346096) -->
- <skip />
+ <string name="global_action_lock_message" product="default" msgid="7092460751050168771">"Lås opp telefonen din for å få flere alternativer"</string>
+ <string name="global_action_lock_message" product="tablet" msgid="1024230056230539493">"Lås opp nettbrettet ditt for å få flere alternativer"</string>
+ <string name="global_action_lock_message" product="device" msgid="3165224897120346096">"Lås opp enheten din for å få flere alternativer"</string>
</resources>
diff --git a/packages/SystemUI/res-product/values-ne/strings.xml b/packages/SystemUI/res-product/values-ne/strings.xml
index 17492be59b0b..81a063c721cf 100644
--- a/packages/SystemUI/res-product/values-ne/strings.xml
+++ b/packages/SystemUI/res-product/values-ne/strings.xml
@@ -40,10 +40,7 @@
<string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4682221342671290678">"तपाईंले <xliff:g id="NUMBER">%d</xliff:g> पटक गलत तरिकाले फोन अनलक गर्ने प्रयास गर्नुभएको छ। कार्य प्रोफाइललाई यसका सबै डेटा मेटिने गरी हटाइने छ।"</string>
<string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="1860049973474855672">"तपाईंले <xliff:g id="NUMBER_0">%1$d</xliff:g> पटक आफ्नो अनलक गर्ने ढाँचा गलत रूपमा कोर्नुभयो। थप <xliff:g id="NUMBER_1">%2$d</xliff:g> पटक असफल प्रयास गरेपछि, तपाईंलाई एउटा इमेल खाता प्रयोग गरेर आफ्नो ट्याब्लेट अनलक गर्न आग्रह गरिने छ।\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> सेकेन्डमा फेरि प्रयास गर्नुहोस्।"</string>
<string name="kg_failed_attempts_almost_at_login" product="default" msgid="44112553371516141">"तपाईंले <xliff:g id="NUMBER_0">%1$d</xliff:g> पटक आफ्नो अनलक गर्ने ढाँचा गलत रूपमा कोर्नुभयो। थप <xliff:g id="NUMBER_1">%2$d</xliff:g> पटक असफल प्रयास गरेपछि, तपाईंलाई एउटा इमेल खाता प्रयोग गरेर आफ्नो फोन अनलक गर्न आग्रह गरिने छ।\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> सेकेन्डमा फेरि प्रयास गर्नुहोस्।"</string>
- <!-- no translation found for global_action_lock_message (7092460751050168771) -->
- <skip />
- <!-- no translation found for global_action_lock_message (1024230056230539493) -->
- <skip />
- <!-- no translation found for global_action_lock_message (3165224897120346096) -->
- <skip />
+ <string name="global_action_lock_message" product="default" msgid="7092460751050168771">"थप विकल्पहरू हेर्न आफ्नो फोन अनलक गर्नुहोस्"</string>
+ <string name="global_action_lock_message" product="tablet" msgid="1024230056230539493">"थप विकल्पहरू हेर्न आफ्नो ट्याब्लेट अनलक गर्नुहोस्"</string>
+ <string name="global_action_lock_message" product="device" msgid="3165224897120346096">"थप विकल्पहरू हेर्न आफ्नो यन्त्र अनलक गर्नुहोस्"</string>
</resources>
diff --git a/packages/SystemUI/res-product/values-nl/strings.xml b/packages/SystemUI/res-product/values-nl/strings.xml
index bc3e72b7595f..76f66b790690 100644
--- a/packages/SystemUI/res-product/values-nl/strings.xml
+++ b/packages/SystemUI/res-product/values-nl/strings.xml
@@ -40,10 +40,7 @@
<string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4682221342671290678">"Je hebt <xliff:g id="NUMBER">%d</xliff:g> mislukte pogingen ondernomen om de telefoon te ontgrendelen. Het werkprofiel wordt verwijderd, waardoor alle profielgegevens worden verwijderd."</string>
<string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="1860049973474855672">"Je hebt je ontgrendelingspatroon <xliff:g id="NUMBER_0">%1$d</xliff:g> keer onjuist getekend. Na nog eens <xliff:g id="NUMBER_1">%2$d</xliff:g> mislukte pogingen wordt je gevraagd je tablet te ontgrendelen via een e-mailaccount.\n\n Probeer het over <xliff:g id="NUMBER_2">%3$d</xliff:g> seconden opnieuw."</string>
<string name="kg_failed_attempts_almost_at_login" product="default" msgid="44112553371516141">"Je hebt je ontgrendelingspatroon <xliff:g id="NUMBER_0">%1$d</xliff:g> keer onjuist getekend. Na nog eens <xliff:g id="NUMBER_1">%2$d</xliff:g> mislukte pogingen wordt je gevraagd je telefoon te ontgrendelen via een e-mailaccount.\n\n Probeer het over <xliff:g id="NUMBER_2">%3$d</xliff:g> seconden opnieuw."</string>
- <!-- no translation found for global_action_lock_message (7092460751050168771) -->
- <skip />
- <!-- no translation found for global_action_lock_message (1024230056230539493) -->
- <skip />
- <!-- no translation found for global_action_lock_message (3165224897120346096) -->
- <skip />
+ <string name="global_action_lock_message" product="default" msgid="7092460751050168771">"Ontgrendel je telefoon voor meer opties"</string>
+ <string name="global_action_lock_message" product="tablet" msgid="1024230056230539493">"Ontgrendel je tablet voor meer opties"</string>
+ <string name="global_action_lock_message" product="device" msgid="3165224897120346096">"Ontgrendel je apparaat voor meer opties"</string>
</resources>
diff --git a/packages/SystemUI/res-product/values-or/strings.xml b/packages/SystemUI/res-product/values-or/strings.xml
index 02948f9b72a6..f0525c98e311 100644
--- a/packages/SystemUI/res-product/values-or/strings.xml
+++ b/packages/SystemUI/res-product/values-or/strings.xml
@@ -40,10 +40,7 @@
<string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4682221342671290678">"ଆପଣ ଫୋନ୍‌କୁ ଅନ୍‌ଲକ୍ କରିବାକୁ<xliff:g id="NUMBER">%d</xliff:g>ଥର ଭୁଲ ପ୍ରୟାସ କରିଛନ୍ତି। କାର୍ଯ୍ୟ ପ୍ରୋଫାଇଲ୍ ବାହାର କରିଦିଆଯିବ, ଯାହା ଫଳରେ ସମସ୍ତ ପ୍ରୋଫାଇଲ୍ ଡାଟା ଡିଲିଟ୍ ହେବ।"</string>
<string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="1860049973474855672">"ଆପଣ ଆପଣଙ୍କ ଅନ୍‌ଲକ୍ ପାଟର୍ନକୁ <xliff:g id="NUMBER_0">%1$d</xliff:g>ଥର ଭୁଲ ଭାବେ ଡ୍ର କରିଛନ୍ତି। ଆଉ <xliff:g id="NUMBER_1">%2$d</xliff:g>ଟି ଭୁଲ ପ୍ରୟାସ ପରେ ଆପଣଙ୍କୁ ଏକ ଇମେଲ୍ ଆକାଉଣ୍ଟ ବ୍ୟବହାର କରି ଆପଣଙ୍କ ଟାବ୍‌ଲୋଟ୍‌କୁ ଅନ୍‌ଲକ୍ କରିବା ପାଇଁ କୁହାଯିବ।\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> ସେକେଣ୍ଡ ପରେ ପୁଣି ଚେଷ୍ଟା କରନ୍ତୁ।"</string>
<string name="kg_failed_attempts_almost_at_login" product="default" msgid="44112553371516141">"ଆପଣ ଆପଣଙ୍କ ଅନ୍‌ଲକ୍ ପାଟର୍ନକୁ <xliff:g id="NUMBER_0">%1$d</xliff:g>ଥର ଭୁଲ ଭାବେ ଡ୍ର କରିଛନ୍ତି। ଆଉ <xliff:g id="NUMBER_1">%2$d</xliff:g>ଟି ଭୁଲ ପ୍ରୟାସ ପରେ ଆପଣଙ୍କୁ ଏକ ଇମେଲ୍ ଆକାଉଣ୍ଟ ବ୍ୟବହାର କରି ଆପଣଙ୍କ ଫୋନ୍‌କୁ ଅନ୍‌ଲକ୍‌ କରିବା ପାଇଁ କୁହାଯିବ।\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> ସେକେଣ୍ଡ ପରେ ପୁଣି ଚେଷ୍ଟା କରନ୍ତୁ।"</string>
- <!-- no translation found for global_action_lock_message (7092460751050168771) -->
- <skip />
- <!-- no translation found for global_action_lock_message (1024230056230539493) -->
- <skip />
- <!-- no translation found for global_action_lock_message (3165224897120346096) -->
- <skip />
+ <string name="global_action_lock_message" product="default" msgid="7092460751050168771">"ଅଧିକ ବିକଳ୍ପ ପାଇଁ ଆପଣଙ୍କ ଫୋନ୍ ଅନଲକ୍ କରନ୍ତୁ"</string>
+ <string name="global_action_lock_message" product="tablet" msgid="1024230056230539493">"ଅଧିକ ବିକଳ୍ପ ପାଇଁ ଆପଣଙ୍କ ଟାବଲେଟ୍ ଅନଲକ୍ କରନ୍ତୁ"</string>
+ <string name="global_action_lock_message" product="device" msgid="3165224897120346096">"ଅଧିକ ବିକଳ୍ପ ପାଇଁ ଆପଣଙ୍କ ଡିଭାଇସ୍ ଅନଲକ୍ କରନ୍ତୁ"</string>
</resources>
diff --git a/packages/SystemUI/res-product/values-pa/strings.xml b/packages/SystemUI/res-product/values-pa/strings.xml
index 4f08cfdfc47f..fa6cc3ba1aa4 100644
--- a/packages/SystemUI/res-product/values-pa/strings.xml
+++ b/packages/SystemUI/res-product/values-pa/strings.xml
@@ -40,10 +40,7 @@
<string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4682221342671290678">"ਤੁਸੀਂ <xliff:g id="NUMBER">%d</xliff:g> ਵਾਰ ਗਲਤ ਢੰਗ ਨਾਲ ਫ਼ੋਨ ਨੂੰ ਅਣਲਾਕ ਕਰਨ ਦੀ ਕੋਸ਼ਿਸ਼ ਕੀਤੀ ਹੈ। ਕਾਰਜ ਪ੍ਰੋਫਾਈਲ ਹਟਾ ਦਿੱਤਾ ਜਾਵੇਗਾ, ਜਿਸ ਨਾਲ ਸਾਰਾ ਪ੍ਰੋਫਾਈਲ ਡਾਟਾ ਮਿਟ ਜਾਵੇਗਾ।"</string>
<string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="1860049973474855672">"ਤੁਸੀਂ <xliff:g id="NUMBER_0">%1$d</xliff:g> ਵਾਰ ਆਪਣਾ ਅਣਲਾਕ ਪੈਟਰਨ ਗਲਤ ਢੰਗ ਨਾਲ ਉਲੀਕਿਆ ਹੈ। <xliff:g id="NUMBER_1">%2$d</xliff:g> ਹੋਰ ਅਸਫਲ ਕੋਸ਼ਿਸ਼ਾਂ ਤੋਂ ਬਾਅਦ, ਤੁਹਾਨੂੰ ਇੱਕ ਈਮੇਲ ਖਾਤਾ ਵਰਤਦੇ ਹੋਏ ਆਪਣੇ ਟੈਬਲੈੱਟ ਨੂੰ ਅਣਲਾਕ ਕਰਨ ਲਈ ਕਿਹਾ ਜਾਵੇਗਾ।\n\n<xliff:g id="NUMBER_2">%3$d</xliff:g> ਸਕਿੰਟਾਂ ਵਿੱਚ ਦੁਬਾਰਾ ਕੋਸ਼ਿਸ਼ ਕਰੋ।"</string>
<string name="kg_failed_attempts_almost_at_login" product="default" msgid="44112553371516141">"ਤੁਸੀਂ <xliff:g id="NUMBER_0">%1$d</xliff:g> ਵਾਰ ਆਪਣਾ ਅਣਲਾਕ ਪੈਟਰਨ ਗਲਤ ਢੰਗ ਨਾਲ ਡ੍ਰਾ ਕੀਤਾ ਹੈ। <xliff:g id="NUMBER_1">%2$d</xliff:g> ਹੋਰ ਅਸਫਲ ਕੋਸ਼ਿਸ਼ਾਂ ਤੋਂ ਬਾਅਦ, ਤੁਹਾਨੂੰ ਇੱਕ ਈਮੇਲ ਖਾਤਾ ਵਰਤਦੇ ਹੋਏ ਆਪਣਾ ਫ਼ੋਨ ਅਣਲਾਕ ਕਰਨ ਲਈ ਕਿਹਾ ਜਾਏਗਾ।\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> ਸਕਿੰਟਾਂ ਵਿੱਚ ਦੁਬਾਰਾ ਕੋਸ਼ਿਸ਼ ਕਰੋ।"</string>
- <!-- no translation found for global_action_lock_message (7092460751050168771) -->
- <skip />
- <!-- no translation found for global_action_lock_message (1024230056230539493) -->
- <skip />
- <!-- no translation found for global_action_lock_message (3165224897120346096) -->
- <skip />
+ <string name="global_action_lock_message" product="default" msgid="7092460751050168771">"ਹੋਰ ਵਿਕਲਪਾਂ ਲਈ ਆਪਣਾ ਫ਼ੋਨ ਅਣਲਾਕ ਕਰੋ"</string>
+ <string name="global_action_lock_message" product="tablet" msgid="1024230056230539493">"ਹੋਰ ਵਿਕਲਪਾਂ ਲਈ ਆਪਣਾ ਟੈਬਲੈੱਟ ਅਣਲਾਕ ਕਰੋ"</string>
+ <string name="global_action_lock_message" product="device" msgid="3165224897120346096">"ਹੋਰ ਵਿਕਲਪਾਂ ਲਈ ਆਪਣਾ ਡੀਵਾਈਸ ਅਣਲਾਕ ਕਰੋ"</string>
</resources>
diff --git a/packages/SystemUI/res-product/values-pl/strings.xml b/packages/SystemUI/res-product/values-pl/strings.xml
index 132a0b9020a4..9a9980a02782 100644
--- a/packages/SystemUI/res-product/values-pl/strings.xml
+++ b/packages/SystemUI/res-product/values-pl/strings.xml
@@ -40,10 +40,7 @@
<string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4682221342671290678">"Po raz <xliff:g id="NUMBER">%d</xliff:g> próbowano nieprawidłowo odblokować telefon. Profil do pracy zostanie usunięty, co spowoduje skasowanie wszystkich jego danych."</string>
<string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="1860049973474855672">"Po raz <xliff:g id="NUMBER_0">%1$d</xliff:g> nieprawidłowo narysowano wzór odblokowania. Po kolejnych <xliff:g id="NUMBER_1">%2$d</xliff:g> nieudanych próbach konieczne będzie odblokowanie tabletu przy użyciu konta e-mail.\n\n Spróbuj ponownie za <xliff:g id="NUMBER_2">%3$d</xliff:g> s."</string>
<string name="kg_failed_attempts_almost_at_login" product="default" msgid="44112553371516141">"Po raz <xliff:g id="NUMBER_0">%1$d</xliff:g> nieprawidłowo narysowano wzór odblokowania. Po kolejnych <xliff:g id="NUMBER_1">%2$d</xliff:g> nieudanych próbach konieczne będzie odblokowanie telefonu przy użyciu konta e-mail.\n\n Spróbuj ponownie za <xliff:g id="NUMBER_2">%3$d</xliff:g> s."</string>
- <!-- no translation found for global_action_lock_message (7092460751050168771) -->
- <skip />
- <!-- no translation found for global_action_lock_message (1024230056230539493) -->
- <skip />
- <!-- no translation found for global_action_lock_message (3165224897120346096) -->
- <skip />
+ <string name="global_action_lock_message" product="default" msgid="7092460751050168771">"Odblokuj telefon, by wyświetlić więcej opcji"</string>
+ <string name="global_action_lock_message" product="tablet" msgid="1024230056230539493">"Odblokuj tablet, by wyświetlić więcej opcji"</string>
+ <string name="global_action_lock_message" product="device" msgid="3165224897120346096">"Odblokuj urządzenie, by wyświetlić więcej opcji"</string>
</resources>
diff --git a/packages/SystemUI/res-product/values-pt-rBR/strings.xml b/packages/SystemUI/res-product/values-pt-rBR/strings.xml
index 6497db23f9f0..499850a6995f 100644
--- a/packages/SystemUI/res-product/values-pt-rBR/strings.xml
+++ b/packages/SystemUI/res-product/values-pt-rBR/strings.xml
@@ -40,10 +40,7 @@
<string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4682221342671290678">"Você tentou desbloquear o smartphone incorretamente <xliff:g id="NUMBER">%d</xliff:g> vezes. O perfil de trabalho será removido, o que excluirá todos os dados do perfil."</string>
<string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="1860049973474855672">"Você desenhou seu padrão de desbloqueio incorretamente <xliff:g id="NUMBER_0">%1$d</xliff:g> vezes. Se fizer mais <xliff:g id="NUMBER_1">%2$d</xliff:g> tentativas incorretas, será solicitado que você use uma conta de e-mail para desbloquear o tablet.\n\n Tente novamente em <xliff:g id="NUMBER_2">%3$d</xliff:g> segundos."</string>
<string name="kg_failed_attempts_almost_at_login" product="default" msgid="44112553371516141">"Você desenhou seu padrão de desbloqueio incorretamente <xliff:g id="NUMBER_0">%1$d</xliff:g> vezes. Se fizer mais <xliff:g id="NUMBER_1">%2$d</xliff:g> tentativas incorretas, será solicitado que você use uma conta de e-mail para desbloquear o smartphone.\n\n Tente novamente em <xliff:g id="NUMBER_2">%3$d</xliff:g> segundos."</string>
- <!-- no translation found for global_action_lock_message (7092460751050168771) -->
- <skip />
- <!-- no translation found for global_action_lock_message (1024230056230539493) -->
- <skip />
- <!-- no translation found for global_action_lock_message (3165224897120346096) -->
- <skip />
+ <string name="global_action_lock_message" product="default" msgid="7092460751050168771">"Desbloqueie seu smartphone para ver mais opções"</string>
+ <string name="global_action_lock_message" product="tablet" msgid="1024230056230539493">"Desbloqueie seu tablet para ver mais opções"</string>
+ <string name="global_action_lock_message" product="device" msgid="3165224897120346096">"Desbloqueie seu dispositivo para ver mais opções"</string>
</resources>
diff --git a/packages/SystemUI/res-product/values-pt-rPT/strings.xml b/packages/SystemUI/res-product/values-pt-rPT/strings.xml
index 31dcdebcf73a..22166bd19a21 100644
--- a/packages/SystemUI/res-product/values-pt-rPT/strings.xml
+++ b/packages/SystemUI/res-product/values-pt-rPT/strings.xml
@@ -40,10 +40,7 @@
<string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4682221342671290678">"Tentou desbloquear incorretamente o telemóvel <xliff:g id="NUMBER">%d</xliff:g> vezes. O perfil de trabalho será removido, o que eliminará todos os dados do mesmo."</string>
<string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="1860049973474855672">"Desenhou o padrão de desbloqueio incorretamente <xliff:g id="NUMBER_0">%1$d</xliff:g> vezes. Após mais <xliff:g id="NUMBER_1">%2$d</xliff:g> tentativas sem êxito, ser-lhe-á pedido para desbloquear o tablet através de uma conta de email.\n\n Tente novamente dentro de <xliff:g id="NUMBER_2">%3$d</xliff:g> segundos."</string>
<string name="kg_failed_attempts_almost_at_login" product="default" msgid="44112553371516141">"Desenhou o padrão de desbloqueio incorretamente <xliff:g id="NUMBER_0">%1$d</xliff:g> vezes. Após mais <xliff:g id="NUMBER_1">%2$d</xliff:g> tentativas sem êxito, ser-lhe-á pedido para desbloquear o telemóvel através de uma conta de email.\n\n Tente novamente dentro de <xliff:g id="NUMBER_2">%3$d</xliff:g> segundos."</string>
- <!-- no translation found for global_action_lock_message (7092460751050168771) -->
- <skip />
- <!-- no translation found for global_action_lock_message (1024230056230539493) -->
- <skip />
- <!-- no translation found for global_action_lock_message (3165224897120346096) -->
- <skip />
+ <string name="global_action_lock_message" product="default" msgid="7092460751050168771">"Desbloqueie o telemóvel para obter mais opções."</string>
+ <string name="global_action_lock_message" product="tablet" msgid="1024230056230539493">"Desbloqueie o tablet para obter mais opções."</string>
+ <string name="global_action_lock_message" product="device" msgid="3165224897120346096">"Desbloqueie o dispositivo para obter mais opções."</string>
</resources>
diff --git a/packages/SystemUI/res-product/values-pt/strings.xml b/packages/SystemUI/res-product/values-pt/strings.xml
index 6497db23f9f0..499850a6995f 100644
--- a/packages/SystemUI/res-product/values-pt/strings.xml
+++ b/packages/SystemUI/res-product/values-pt/strings.xml
@@ -40,10 +40,7 @@
<string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4682221342671290678">"Você tentou desbloquear o smartphone incorretamente <xliff:g id="NUMBER">%d</xliff:g> vezes. O perfil de trabalho será removido, o que excluirá todos os dados do perfil."</string>
<string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="1860049973474855672">"Você desenhou seu padrão de desbloqueio incorretamente <xliff:g id="NUMBER_0">%1$d</xliff:g> vezes. Se fizer mais <xliff:g id="NUMBER_1">%2$d</xliff:g> tentativas incorretas, será solicitado que você use uma conta de e-mail para desbloquear o tablet.\n\n Tente novamente em <xliff:g id="NUMBER_2">%3$d</xliff:g> segundos."</string>
<string name="kg_failed_attempts_almost_at_login" product="default" msgid="44112553371516141">"Você desenhou seu padrão de desbloqueio incorretamente <xliff:g id="NUMBER_0">%1$d</xliff:g> vezes. Se fizer mais <xliff:g id="NUMBER_1">%2$d</xliff:g> tentativas incorretas, será solicitado que você use uma conta de e-mail para desbloquear o smartphone.\n\n Tente novamente em <xliff:g id="NUMBER_2">%3$d</xliff:g> segundos."</string>
- <!-- no translation found for global_action_lock_message (7092460751050168771) -->
- <skip />
- <!-- no translation found for global_action_lock_message (1024230056230539493) -->
- <skip />
- <!-- no translation found for global_action_lock_message (3165224897120346096) -->
- <skip />
+ <string name="global_action_lock_message" product="default" msgid="7092460751050168771">"Desbloqueie seu smartphone para ver mais opções"</string>
+ <string name="global_action_lock_message" product="tablet" msgid="1024230056230539493">"Desbloqueie seu tablet para ver mais opções"</string>
+ <string name="global_action_lock_message" product="device" msgid="3165224897120346096">"Desbloqueie seu dispositivo para ver mais opções"</string>
</resources>
diff --git a/packages/SystemUI/res-product/values-ro/strings.xml b/packages/SystemUI/res-product/values-ro/strings.xml
index 0c436b09924a..4740501f47bd 100644
--- a/packages/SystemUI/res-product/values-ro/strings.xml
+++ b/packages/SystemUI/res-product/values-ro/strings.xml
@@ -40,10 +40,7 @@
<string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4682221342671290678">"Ați efectuat <xliff:g id="NUMBER">%d</xliff:g> încercări incorecte de deblocare a telefonului. Profilul de serviciu va fi eliminat, iar toate datele profilului vor fi șterse."</string>
<string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="1860049973474855672">"Ați desenat incorect modelul pentru deblocare de <xliff:g id="NUMBER_0">%1$d</xliff:g> ori. După încă <xliff:g id="NUMBER_1">%2$d</xliff:g> încercări nereușite, vi se va solicita să deblocați tableta cu ajutorul unui cont de e-mail.\n\n Încercați din nou peste <xliff:g id="NUMBER_2">%3$d</xliff:g> secunde."</string>
<string name="kg_failed_attempts_almost_at_login" product="default" msgid="44112553371516141">"Ați desenat incorect modelul pentru deblocare de <xliff:g id="NUMBER_0">%1$d</xliff:g> ori. După încă <xliff:g id="NUMBER_1">%2$d</xliff:g> încercări nereușite, vi se va solicita să deblocați telefonul cu ajutorul unui cont de e-mail.\n\n Încercați din nou peste <xliff:g id="NUMBER_2">%3$d</xliff:g> secunde."</string>
- <!-- no translation found for global_action_lock_message (7092460751050168771) -->
- <skip />
- <!-- no translation found for global_action_lock_message (1024230056230539493) -->
- <skip />
- <!-- no translation found for global_action_lock_message (3165224897120346096) -->
- <skip />
+ <string name="global_action_lock_message" product="default" msgid="7092460751050168771">"Deblocați telefonul pentru mai multe opțiuni"</string>
+ <string name="global_action_lock_message" product="tablet" msgid="1024230056230539493">"Deblocați tableta pentru mai multe opțiuni"</string>
+ <string name="global_action_lock_message" product="device" msgid="3165224897120346096">"Deblocați dispozitivul pentru mai multe opțiuni"</string>
</resources>
diff --git a/packages/SystemUI/res-product/values-ru/strings.xml b/packages/SystemUI/res-product/values-ru/strings.xml
index 856ac3a520d7..e622dbce1745 100644
--- a/packages/SystemUI/res-product/values-ru/strings.xml
+++ b/packages/SystemUI/res-product/values-ru/strings.xml
@@ -40,10 +40,7 @@
<string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4682221342671290678">"Вы несколько раз (<xliff:g id="NUMBER">%d</xliff:g>) не смогли разблокировать телефон. Рабочий профиль и все его данные будут удалены."</string>
<string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="1860049973474855672">"Вы несколько раз (<xliff:g id="NUMBER_0">%1$d</xliff:g>) ввели неверный графический ключ. Осталось попыток: <xliff:g id="NUMBER_1">%2$d</xliff:g>. В случае неудачи вам будет предложено разблокировать планшет с помощью аккаунта электронной почты.\n\nПовторите попытку через <xliff:g id="NUMBER_2">%3$d</xliff:g> сек."</string>
<string name="kg_failed_attempts_almost_at_login" product="default" msgid="44112553371516141">"Вы несколько раз (<xliff:g id="NUMBER_0">%1$d</xliff:g>) ввели неверный графический ключ. Осталось попыток: <xliff:g id="NUMBER_1">%2$d</xliff:g>. В случае неудачи вам будет предложено разблокировать телефон с помощью аккаунта электронной почты.\n\nПовторите попытку через <xliff:g id="NUMBER_2">%3$d</xliff:g> сек."</string>
- <!-- no translation found for global_action_lock_message (7092460751050168771) -->
- <skip />
- <!-- no translation found for global_action_lock_message (1024230056230539493) -->
- <skip />
- <!-- no translation found for global_action_lock_message (3165224897120346096) -->
- <skip />
+ <string name="global_action_lock_message" product="default" msgid="7092460751050168771">"Чтобы посмотреть дополнительные параметры, разблокируйте телефон."</string>
+ <string name="global_action_lock_message" product="tablet" msgid="1024230056230539493">"Чтобы посмотреть дополнительные параметры, разблокируйте планшет."</string>
+ <string name="global_action_lock_message" product="device" msgid="3165224897120346096">"Чтобы посмотреть дополнительные параметры, разблокируйте устройство."</string>
</resources>
diff --git a/packages/SystemUI/res-product/values-si/strings.xml b/packages/SystemUI/res-product/values-si/strings.xml
index 4db177599fdd..efb2cdef258e 100644
--- a/packages/SystemUI/res-product/values-si/strings.xml
+++ b/packages/SystemUI/res-product/values-si/strings.xml
@@ -40,10 +40,7 @@
<string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4682221342671290678">"ඔබ දුරකථනය අගුළු හැරීමට <xliff:g id="NUMBER">%d</xliff:g> වරක් වැරදියට උත්සාහ කර ඇත. කාර්යාල පැතිකඩ ඉවත් කරනු ඇති අතර, එය සියලු පැතිකඩ දත්ත මකනු ඇත."</string>
<string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="1860049973474855672">"ඔබ අගුළු ඇරිමේ රටාව <xliff:g id="NUMBER_0">%1$d</xliff:g> වතාවක් වැරදියට ඇඳ ඇත. තවත් අසාර්ථක උත්සාහ <xliff:g id="NUMBER_1">%2$d</xliff:g> කින් පසුව, ඊ-තැපැල් ගිණුම භාවිතා කරමින් ඔබගේ ටැබ්ලටයේ අගුළු ඇරීමට ඔබට පවසනු ඇත.\n\n නැවත තත්පර <xliff:g id="NUMBER_2">%3$d</xliff:g> කින් උත්සාහ කරන්න."</string>
<string name="kg_failed_attempts_almost_at_login" product="default" msgid="44112553371516141">"ඔබ වැරදියට <xliff:g id="NUMBER_0">%1$d</xliff:g> වතාවක් ඔබගේ අගුළු හැරීමේ රටාව ඇඳ ඇත. අසාර්ථක උත්සහ කිරීම් <xliff:g id="NUMBER_1">%2$d</xliff:g> න් පසුව, ඔබගේ ඊ-තැපැල් ලිපිනය භාවිතයෙන් ඔබගේ දුරකථනය අගුළු හැරීමට ඔබගෙන් අසයි.\n\n තත්පර <xliff:g id="NUMBER_2">%3$d</xliff:g> න් පසුව නැවත උත්සහ කරන්න."</string>
- <!-- no translation found for global_action_lock_message (7092460751050168771) -->
- <skip />
- <!-- no translation found for global_action_lock_message (1024230056230539493) -->
- <skip />
- <!-- no translation found for global_action_lock_message (3165224897120346096) -->
- <skip />
+ <string name="global_action_lock_message" product="default" msgid="7092460751050168771">"තව විකල්ප සඳහා ඔබේ දුරකථනය අගුලු හරින්න"</string>
+ <string name="global_action_lock_message" product="tablet" msgid="1024230056230539493">"තව විකල්ප සඳහා ඔබේ ටැබ්ලට් පරිගණකය අගුලු හරින්න"</string>
+ <string name="global_action_lock_message" product="device" msgid="3165224897120346096">"තව විකල්ප සඳහා ඔබේ උපාංගය අගුලු හරින්න"</string>
</resources>
diff --git a/packages/SystemUI/res-product/values-sk/strings.xml b/packages/SystemUI/res-product/values-sk/strings.xml
index 748ab6afacae..a7b6f0a56274 100644
--- a/packages/SystemUI/res-product/values-sk/strings.xml
+++ b/packages/SystemUI/res-product/values-sk/strings.xml
@@ -40,10 +40,7 @@
<string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4682221342671290678">"Telefón ste sa pokúsili <xliff:g id="NUMBER">%d</xliff:g>‑krát nesprávne odomknúť. Pracovný profil bude odstránený spolu so všetkými údajmi."</string>
<string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="1860049973474855672">"<xliff:g id="NUMBER_0">%1$d</xliff:g>‑krát ste nesprávne nakreslili svoj bezpečnostný vzor. Po <xliff:g id="NUMBER_1">%2$d</xliff:g> ďalších neúspešných pokusoch sa zobrazí výzva na odomknutie tabletu pomocou e‑mailového účtu.\n\n Skúste to znova o <xliff:g id="NUMBER_2">%3$d</xliff:g> s."</string>
<string name="kg_failed_attempts_almost_at_login" product="default" msgid="44112553371516141">"Už ste <xliff:g id="NUMBER_0">%1$d</xliff:g>‑krát nesprávne nakreslili svoj bezpečnostný vzor. Po <xliff:g id="NUMBER_1">%2$d</xliff:g> ďalších neúspešných pokusoch sa zobrazí výzva na odomknutie telefónu pomocou e‑mailového účtu.\n\n Skúste to znova o <xliff:g id="NUMBER_2">%3$d</xliff:g> s."</string>
- <!-- no translation found for global_action_lock_message (7092460751050168771) -->
- <skip />
- <!-- no translation found for global_action_lock_message (1024230056230539493) -->
- <skip />
- <!-- no translation found for global_action_lock_message (3165224897120346096) -->
- <skip />
+ <string name="global_action_lock_message" product="default" msgid="7092460751050168771">"Ak chcete zobraziť ďalšie možnosti, odomknite telefón"</string>
+ <string name="global_action_lock_message" product="tablet" msgid="1024230056230539493">"Ak chcete zobraziť ďalšie možnosti, odomknite tablet"</string>
+ <string name="global_action_lock_message" product="device" msgid="3165224897120346096">"Ak chcete zobraziť ďalšie možnosti, odomknite zariadenie"</string>
</resources>
diff --git a/packages/SystemUI/res-product/values-sl/strings.xml b/packages/SystemUI/res-product/values-sl/strings.xml
index 3e73415ad67f..db55db823982 100644
--- a/packages/SystemUI/res-product/values-sl/strings.xml
+++ b/packages/SystemUI/res-product/values-sl/strings.xml
@@ -40,10 +40,7 @@
<string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4682221342671290678">"Telefon ste neuspešno poskusili odkleniti <xliff:g id="NUMBER">%d</xliff:g>-krat. Delovni profil bo odstranjen in vsi podatki profila bodo izbrisani."</string>
<string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="1860049973474855672">"Vzorec za odklepanje ste <xliff:g id="NUMBER_0">%1$d</xliff:g>-krat napačno vnesli. Če ga neuspešno poskusite vnesti še <xliff:g id="NUMBER_1">%2$d</xliff:g>-krat, boste pozvani, da tablični računalnik odklenete z e-poštnim računom.\n\nPoskusite znova čez <xliff:g id="NUMBER_2">%3$d</xliff:g> s."</string>
<string name="kg_failed_attempts_almost_at_login" product="default" msgid="44112553371516141">"Vzorec za odklepanje ste <xliff:g id="NUMBER_0">%1$d</xliff:g>-krat napačno vnesli. Če ga neuspešno poskusite vnesti še <xliff:g id="NUMBER_1">%2$d</xliff:g>-krat, boste pozvani, da telefon odklenete z e-poštnim računom.\n\nPoskusite znova čez <xliff:g id="NUMBER_2">%3$d</xliff:g> s."</string>
- <!-- no translation found for global_action_lock_message (7092460751050168771) -->
- <skip />
- <!-- no translation found for global_action_lock_message (1024230056230539493) -->
- <skip />
- <!-- no translation found for global_action_lock_message (3165224897120346096) -->
- <skip />
+ <string name="global_action_lock_message" product="default" msgid="7092460751050168771">"Za več možnosti odklenite telefon"</string>
+ <string name="global_action_lock_message" product="tablet" msgid="1024230056230539493">"Za več možnosti odklenite tablični računalnik"</string>
+ <string name="global_action_lock_message" product="device" msgid="3165224897120346096">"Za več možnosti odklenite napravo"</string>
</resources>
diff --git a/packages/SystemUI/res-product/values-sq/strings.xml b/packages/SystemUI/res-product/values-sq/strings.xml
index 936775ff6ef6..cc444c2f91c6 100644
--- a/packages/SystemUI/res-product/values-sq/strings.xml
+++ b/packages/SystemUI/res-product/values-sq/strings.xml
@@ -40,10 +40,7 @@
<string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4682221342671290678">"Ke tentuar <xliff:g id="NUMBER">%d</xliff:g> herë pa sukses për ta shkyçur telefonin. Profili i punës do të hiqet, gjë që do të fshijë të gjitha të dhënat e profilit."</string>
<string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="1860049973474855672">"Ke vizatuar <xliff:g id="NUMBER_0">%1$d</xliff:g> herë pa sukses motivin tënd të shkyçjes. Pas <xliff:g id="NUMBER_1">%2$d</xliff:g> tentativave të tjera të pasuksesshme, do të të duhet ta shkyçësh tabletin duke përdorur një llogari email-i.\n\n Provo sërish për <xliff:g id="NUMBER_2">%3$d</xliff:g> sekonda."</string>
<string name="kg_failed_attempts_almost_at_login" product="default" msgid="44112553371516141">"Ke vizatuar <xliff:g id="NUMBER_0">%1$d</xliff:g> herë pa sukses motivin tënd. Pas <xliff:g id="NUMBER_1">%2$d</xliff:g> tentativave të tjera të pasuksesshme, do të të duhet ta shkyçësh telefonin duke përdorur një llogari email-i.\n\n Provo sërish për <xliff:g id="NUMBER_2">%3$d</xliff:g> sekonda."</string>
- <!-- no translation found for global_action_lock_message (7092460751050168771) -->
- <skip />
- <!-- no translation found for global_action_lock_message (1024230056230539493) -->
- <skip />
- <!-- no translation found for global_action_lock_message (3165224897120346096) -->
- <skip />
+ <string name="global_action_lock_message" product="default" msgid="7092460751050168771">"Shkyçe telefonin për më shumë opsione"</string>
+ <string name="global_action_lock_message" product="tablet" msgid="1024230056230539493">"Shkyçe tabletin për më shumë opsione"</string>
+ <string name="global_action_lock_message" product="device" msgid="3165224897120346096">"Shkyçe pajisjen për më shumë opsione"</string>
</resources>
diff --git a/packages/SystemUI/res-product/values-sr/strings.xml b/packages/SystemUI/res-product/values-sr/strings.xml
index f7dd4f3fd245..f22d6407a075 100644
--- a/packages/SystemUI/res-product/values-sr/strings.xml
+++ b/packages/SystemUI/res-product/values-sr/strings.xml
@@ -40,10 +40,7 @@
<string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4682221342671290678">"Погрешно сте покушали да откључате телефон <xliff:g id="NUMBER">%d</xliff:g> пута. Уклонићемо пословни профил, чиме се бришу сви подаци са профила."</string>
<string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="1860049973474855672">"Нетачно сте нацртали шаблон за откључавање <xliff:g id="NUMBER_0">%1$d</xliff:g> пута. Ако погрешно покушате још <xliff:g id="NUMBER_1">%2$d</xliff:g> пута, затражићемо да откључате таблет помоћу имејл налога.\n\n Пробајте поново за <xliff:g id="NUMBER_2">%3$d</xliff:g> сек."</string>
<string name="kg_failed_attempts_almost_at_login" product="default" msgid="44112553371516141">"Нетачно сте нацртали шаблон за откључавање <xliff:g id="NUMBER_0">%1$d</xliff:g> пута. Ако погрешно покушате још <xliff:g id="NUMBER_1">%2$d</xliff:g> пута, затражићемо да откључате телефон помоћу имејл налога.\n\n Пробајте поново за <xliff:g id="NUMBER_2">%3$d</xliff:g> сек."</string>
- <!-- no translation found for global_action_lock_message (7092460751050168771) -->
- <skip />
- <!-- no translation found for global_action_lock_message (1024230056230539493) -->
- <skip />
- <!-- no translation found for global_action_lock_message (3165224897120346096) -->
- <skip />
+ <string name="global_action_lock_message" product="default" msgid="7092460751050168771">"Откључајте телефон за још опција"</string>
+ <string name="global_action_lock_message" product="tablet" msgid="1024230056230539493">"Откључајте таблет за још опција"</string>
+ <string name="global_action_lock_message" product="device" msgid="3165224897120346096">"Откључајте уређај за још опција"</string>
</resources>
diff --git a/packages/SystemUI/res-product/values-sv/strings.xml b/packages/SystemUI/res-product/values-sv/strings.xml
index 9f60a1685695..f6059e0294f1 100644
--- a/packages/SystemUI/res-product/values-sv/strings.xml
+++ b/packages/SystemUI/res-product/values-sv/strings.xml
@@ -40,10 +40,7 @@
<string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4682221342671290678">"Du har försökt låsa upp telefonen på ett felaktigt sätt <xliff:g id="NUMBER">%d</xliff:g> gånger. Jobbprofilen tas bort och all profildata raderas."</string>
<string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="1860049973474855672">"Du har ritat ditt grafiska lösenord fel <xliff:g id="NUMBER_0">%1$d</xliff:g> gånger. Efter ytterligare <xliff:g id="NUMBER_1">%2$d</xliff:g> försök måste du låsa upp surfplattan med hjälp av ett e-postkonto.\n\n Försök igen om <xliff:g id="NUMBER_2">%3$d</xliff:g> sekunder."</string>
<string name="kg_failed_attempts_almost_at_login" product="default" msgid="44112553371516141">"Du har ritat ditt grafiska lösenord fel <xliff:g id="NUMBER_0">%1$d</xliff:g> gånger. Efter ytterligare <xliff:g id="NUMBER_1">%2$d</xliff:g> försök måste du låsa upp telefonen med hjälp av ett e-postkonto.\n\n Försök igen om <xliff:g id="NUMBER_2">%3$d</xliff:g> sekunder."</string>
- <!-- no translation found for global_action_lock_message (7092460751050168771) -->
- <skip />
- <!-- no translation found for global_action_lock_message (1024230056230539493) -->
- <skip />
- <!-- no translation found for global_action_lock_message (3165224897120346096) -->
- <skip />
+ <string name="global_action_lock_message" product="default" msgid="7092460751050168771">"Lås upp telefonen för fler alternativ"</string>
+ <string name="global_action_lock_message" product="tablet" msgid="1024230056230539493">"Lås upp surfplattan för fler alternativ"</string>
+ <string name="global_action_lock_message" product="device" msgid="3165224897120346096">"Lås upp enheten för fler alternativ"</string>
</resources>
diff --git a/packages/SystemUI/res-product/values-sw/strings.xml b/packages/SystemUI/res-product/values-sw/strings.xml
index db69fb5e7715..171fd9763edb 100644
--- a/packages/SystemUI/res-product/values-sw/strings.xml
+++ b/packages/SystemUI/res-product/values-sw/strings.xml
@@ -40,10 +40,7 @@
<string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4682221342671290678">"Umejaribu kufungua simu mara <xliff:g id="NUMBER">%d</xliff:g> bila mafanikio. Wasifu wa kazini utaondolewa, hatua itakayofuta data yote ya wasifu."</string>
<string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="1860049973474855672">"Umeweka mchoro usio sahihi wa kufungua skrini mara <xliff:g id="NUMBER_0">%1$d</xliff:g>. Baada ya majaribio <xliff:g id="NUMBER_1">%2$d</xliff:g> zaidi bila mafanikio, utaombwa ufungue kompyuta yako kibao kwa kutumia akaunti ya barua pepe.\n\n Jaribu tena baada ya sekunde <xliff:g id="NUMBER_2">%3$d</xliff:g>."</string>
<string name="kg_failed_attempts_almost_at_login" product="default" msgid="44112553371516141">"Umeweka mchoro usio sahihi wa kufungua skrini mara <xliff:g id="NUMBER_0">%1$d</xliff:g>. Ukikosea mara nyingine <xliff:g id="NUMBER_1">%2$d</xliff:g>, utaombwa ufungue simu yako kwa kutumia akaunti ya barua pepe.\n\n Jaribu tena baada ya sekunde <xliff:g id="NUMBER_2">%3$d</xliff:g>."</string>
- <!-- no translation found for global_action_lock_message (7092460751050168771) -->
- <skip />
- <!-- no translation found for global_action_lock_message (1024230056230539493) -->
- <skip />
- <!-- no translation found for global_action_lock_message (3165224897120346096) -->
- <skip />
+ <string name="global_action_lock_message" product="default" msgid="7092460751050168771">"Fungua simu yako ili upate chaguo zaidi"</string>
+ <string name="global_action_lock_message" product="tablet" msgid="1024230056230539493">"Fungua kompyuta yako kibao ili upate chaguo zaidi"</string>
+ <string name="global_action_lock_message" product="device" msgid="3165224897120346096">"Fungua kifaa chako ili upate chaguo zaidi"</string>
</resources>
diff --git a/packages/SystemUI/res-product/values-ta/strings.xml b/packages/SystemUI/res-product/values-ta/strings.xml
index 4bb48d96960e..9819e7ced64f 100644
--- a/packages/SystemUI/res-product/values-ta/strings.xml
+++ b/packages/SystemUI/res-product/values-ta/strings.xml
@@ -40,10 +40,7 @@
<string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4682221342671290678">"மொபைலைத் திறக்க, <xliff:g id="NUMBER">%d</xliff:g> முறை தவறாக முயன்றுவிட்டதனால் பணிக் கணக்கு அகற்றப்படும். இதனால் அதிலுள்ள அனைத்துச் சுயவிவரத் தரவும் நீக்கப்படும்."</string>
<string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="1860049973474855672">"திறப்பதற்கான பேட்டர்னை, <xliff:g id="NUMBER_0">%1$d</xliff:g> முறை தவறாக வரைந்துவிட்டீர்கள். இன்னும் <xliff:g id="NUMBER_1">%2$d</xliff:g> முறை தவறாக வரைந்தால், மின்னஞ்சல் கணக்கைப் பயன்படுத்தி டேப்லெட்டைத் திறக்கும்படி கேட்கப்படுவீர்கள்.\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> வினாடிகளில் மீண்டும் முயலவும்."</string>
<string name="kg_failed_attempts_almost_at_login" product="default" msgid="44112553371516141">"திறப்பதற்கான பேட்டர்னை, <xliff:g id="NUMBER_0">%1$d</xliff:g> முறை தவறாக வரைந்துவிட்டீர்கள். இன்னும் <xliff:g id="NUMBER_1">%2$d</xliff:g> முறை தவறாக வரைந்தால், மின்னஞ்சல் கணக்கைப் பயன்படுத்தி மொபைலைத் திறக்கும்படி கேட்கப்படுவீர்கள்.\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> வினாடிகளில் மீண்டும் முயலவும்."</string>
- <!-- no translation found for global_action_lock_message (7092460751050168771) -->
- <skip />
- <!-- no translation found for global_action_lock_message (1024230056230539493) -->
- <skip />
- <!-- no translation found for global_action_lock_message (3165224897120346096) -->
- <skip />
+ <string name="global_action_lock_message" product="default" msgid="7092460751050168771">"மேலும் விருப்பங்களுக்கு மொபைலை அன்லாக் செய்யவும்"</string>
+ <string name="global_action_lock_message" product="tablet" msgid="1024230056230539493">"மேலும் விருப்பங்களுக்கு டேப்லெட்டை அன்லாக் செய்யவும்"</string>
+ <string name="global_action_lock_message" product="device" msgid="3165224897120346096">"மேலும் விருப்பங்களுக்குச் சாதனத்தை அன்லாக் செய்யவும்"</string>
</resources>
diff --git a/packages/SystemUI/res-product/values-te/strings.xml b/packages/SystemUI/res-product/values-te/strings.xml
index 3ba104cdf5da..1773f9087e0e 100644
--- a/packages/SystemUI/res-product/values-te/strings.xml
+++ b/packages/SystemUI/res-product/values-te/strings.xml
@@ -40,10 +40,7 @@
<string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4682221342671290678">"మీరు ఫోన్‌ను అన్‌లాక్ చేయడానికి <xliff:g id="NUMBER">%d</xliff:g> సార్లు తప్పు ప్రయత్నాలు చేశారు. కార్యాలయ ప్రొఫైల్ తీసివేయబడుతుంది, దీని వలన ప్రొఫైల్ డేటా మొత్తం తొలగించబడుతుంది."</string>
<string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="1860049973474855672">"మీరు మీ అన్‌లాక్ నమూనాను <xliff:g id="NUMBER_0">%1$d</xliff:g> సార్లు తప్పుగా గీసారు. మరో <xliff:g id="NUMBER_1">%2$d</xliff:g> ప్రయత్నాలలో విఫలమైతే, మీరు ఇమెయిల్ ఖాతాను ఉపయోగించి మీ టాబ్లెట్‌ను అన్‌లాక్ చేయాల్సి వస్తుంది.\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> సెకన్లలో మళ్లీ ప్రయత్నించండి."</string>
<string name="kg_failed_attempts_almost_at_login" product="default" msgid="44112553371516141">"మీరు మీ అన్‌లాక్ నమూనాను <xliff:g id="NUMBER_0">%1$d</xliff:g> సార్లు తప్పుగా గీసారు. మరో <xliff:g id="NUMBER_1">%2$d</xliff:g> ప్రయత్నాలలో విఫలమైతే, మీరు ఇమెయిల్ ఖాతాను ఉపయోగించి మీ ఫోన్‌ను అన్‌లాక్ చేయాల్సి వస్తుంది.\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> సెకన్లలో మళ్లీ ప్రయత్నించండి."</string>
- <!-- no translation found for global_action_lock_message (7092460751050168771) -->
- <skip />
- <!-- no translation found for global_action_lock_message (1024230056230539493) -->
- <skip />
- <!-- no translation found for global_action_lock_message (3165224897120346096) -->
- <skip />
+ <string name="global_action_lock_message" product="default" msgid="7092460751050168771">"మరిన్ని ఆప్షన్‌ల కోసం మీ ఫోన్‌ను అన్‌లాక్ చేయండి"</string>
+ <string name="global_action_lock_message" product="tablet" msgid="1024230056230539493">"మరిన్ని ఆప్షన్‌ల కోసం మీ టాబ్లెట్‌ను అన్‌లాక్ చేయండి"</string>
+ <string name="global_action_lock_message" product="device" msgid="3165224897120346096">"మరిన్ని ఆప్షన్‌ల కోసం మీ పరికరాన్ని అన్‌లాక్ చేయండి"</string>
</resources>
diff --git a/packages/SystemUI/res-product/values-th/strings.xml b/packages/SystemUI/res-product/values-th/strings.xml
index 4525ef5d0bf6..bf2261d79abd 100644
--- a/packages/SystemUI/res-product/values-th/strings.xml
+++ b/packages/SystemUI/res-product/values-th/strings.xml
@@ -40,10 +40,7 @@
<string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4682221342671290678">"คุณปลดล็อกโทรศัพท์ไม่ถูกต้อง <xliff:g id="NUMBER">%d</xliff:g> ครั้งแล้ว ระบบจะนำโปรไฟล์งานออก ซึ่งจะเป็นการลบข้อมูลทั้งหมดในโปรไฟล์"</string>
<string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="1860049973474855672">"คุณวาดรูปแบบการปลดล็อกไม่ถูกต้อง <xliff:g id="NUMBER_0">%1$d</xliff:g> ครั้งแล้ว หากทำไม่สำเร็จอีก <xliff:g id="NUMBER_1">%2$d</xliff:g> ครั้ง ระบบจะขอให้คุณปลดล็อกแท็บเล็ตโดยใช้บัญชีอีเมล\n\n โปรดลองอีกครั้งใน <xliff:g id="NUMBER_2">%3$d</xliff:g> วินาที"</string>
<string name="kg_failed_attempts_almost_at_login" product="default" msgid="44112553371516141">"คุณวาดรูปแบบการปลดล็อกไม่ถูกต้อง <xliff:g id="NUMBER_0">%1$d</xliff:g> ครั้งแล้ว หากทำไม่สำเร็จอีก <xliff:g id="NUMBER_1">%2$d</xliff:g> ครั้ง ระบบจะขอให้คุณปลดล็อกโทรศัพท์โดยใช้บัญชีอีเมล\n\n โปรดลองอีกครั้งในอีก <xliff:g id="NUMBER_2">%3$d</xliff:g> วินาที"</string>
- <!-- no translation found for global_action_lock_message (7092460751050168771) -->
- <skip />
- <!-- no translation found for global_action_lock_message (1024230056230539493) -->
- <skip />
- <!-- no translation found for global_action_lock_message (3165224897120346096) -->
- <skip />
+ <string name="global_action_lock_message" product="default" msgid="7092460751050168771">"ปลดล็อกโทรศัพท์เพื่อดูตัวเลือกเพิ่มเติม"</string>
+ <string name="global_action_lock_message" product="tablet" msgid="1024230056230539493">"ปลดล็อกแท็บเล็ตเพื่อดูตัวเลือกเพิ่มเติม"</string>
+ <string name="global_action_lock_message" product="device" msgid="3165224897120346096">"ปลดล็อกอุปกรณ์เพื่อดูตัวเลือกเพิ่มเติม"</string>
</resources>
diff --git a/packages/SystemUI/res-product/values-tl/strings.xml b/packages/SystemUI/res-product/values-tl/strings.xml
index 8d6931dab05d..a70a3a5c50ab 100644
--- a/packages/SystemUI/res-product/values-tl/strings.xml
+++ b/packages/SystemUI/res-product/values-tl/strings.xml
@@ -40,10 +40,7 @@
<string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4682221342671290678">"<xliff:g id="NUMBER">%d</xliff:g> (na) beses mo nang sinubukang i-unlock ang telepono gamit ang maling password. Aalisin ang profile sa trabaho, na magiging dahilan para ma-delete ang lahat ng data sa profile."</string>
<string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="1860049973474855672">"<xliff:g id="NUMBER_0">%1$d</xliff:g> (na) beses kang nagkamali sa pagguhit ng iyong pattern sa pag-unlock. Pagkatapos ng <xliff:g id="NUMBER_1">%2$d</xliff:g> pang hindi matagumpay na pagsubok, hihilingin sa iyong i-unlock ang tablet mo gamit ang isang email account.\n\n Subukan ulit sa loob ng <xliff:g id="NUMBER_2">%3$d</xliff:g> (na) segundo."</string>
<string name="kg_failed_attempts_almost_at_login" product="default" msgid="44112553371516141">"<xliff:g id="NUMBER_0">%1$d</xliff:g> (na) beses kang nagkamali sa pagguhit ng iyong pattern sa pag-unlock. Pagkatapos ng <xliff:g id="NUMBER_1">%2$d</xliff:g> pang hindi matagumpay na pagsubok, hihilingin sa iyong i-unlock ang telepono mo gamit ang isang email account.\n\n Subukan ulit sa loob ng <xliff:g id="NUMBER_2">%3$d</xliff:g> (na) segundo."</string>
- <!-- no translation found for global_action_lock_message (7092460751050168771) -->
- <skip />
- <!-- no translation found for global_action_lock_message (1024230056230539493) -->
- <skip />
- <!-- no translation found for global_action_lock_message (3165224897120346096) -->
- <skip />
+ <string name="global_action_lock_message" product="default" msgid="7092460751050168771">"I-unlock ang iyong telepono para sa higit pang opsyon"</string>
+ <string name="global_action_lock_message" product="tablet" msgid="1024230056230539493">"I-unlock ang iyong tablet para sa higit pang opsyon"</string>
+ <string name="global_action_lock_message" product="device" msgid="3165224897120346096">"I-unlock ang iyong device para sa higit pang opsyon"</string>
</resources>
diff --git a/packages/SystemUI/res-product/values-tr/strings.xml b/packages/SystemUI/res-product/values-tr/strings.xml
index 44d7cac2f237..5eb7e91e6943 100644
--- a/packages/SystemUI/res-product/values-tr/strings.xml
+++ b/packages/SystemUI/res-product/values-tr/strings.xml
@@ -40,10 +40,7 @@
<string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4682221342671290678">"Telefonun kilidini <xliff:g id="NUMBER">%d</xliff:g> kez hatalı bir şekilde açmayı denediniz. İş profili kaldırılacak ve tüm profil verileri silinecektir."</string>
<string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="1860049973474855672">"Kilit açma deseninizi <xliff:g id="NUMBER_0">%1$d</xliff:g> kez hatalı çizdiniz. <xliff:g id="NUMBER_1">%2$d</xliff:g> başarısız deneme daha yaparsanız tabletinizin kilidini bir e-posta hesabı kullanarak açmanız istenir.\n<xliff:g id="NUMBER_2">%3$d</xliff:g>\n saniye içinde tekrar deneyin."</string>
<string name="kg_failed_attempts_almost_at_login" product="default" msgid="44112553371516141">"Kilit açma deseninizi <xliff:g id="NUMBER_0">%1$d</xliff:g> kez yanlış çizdiniz. <xliff:g id="NUMBER_1">%2$d</xliff:g> başarısız deneme daha yaparsanız telefonunuzu bir e-posta hesabı kullanarak açmanız istenir.\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> saniye içinde tekrar deneyin."</string>
- <!-- no translation found for global_action_lock_message (7092460751050168771) -->
- <skip />
- <!-- no translation found for global_action_lock_message (1024230056230539493) -->
- <skip />
- <!-- no translation found for global_action_lock_message (3165224897120346096) -->
- <skip />
+ <string name="global_action_lock_message" product="default" msgid="7092460751050168771">"Diğer seçenekler için telefonunuzun kilidini açın"</string>
+ <string name="global_action_lock_message" product="tablet" msgid="1024230056230539493">"Diğer seçenekler için tabletinizin kilidini açın"</string>
+ <string name="global_action_lock_message" product="device" msgid="3165224897120346096">"Diğer seçenekler için cihazınızın kilidini açın"</string>
</resources>
diff --git a/packages/SystemUI/res-product/values-uk/strings.xml b/packages/SystemUI/res-product/values-uk/strings.xml
index db3ba081ba63..098f8e792bf4 100644
--- a/packages/SystemUI/res-product/values-uk/strings.xml
+++ b/packages/SystemUI/res-product/values-uk/strings.xml
@@ -40,10 +40,7 @@
<string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4682221342671290678">"Кількість невдалих спроб розблокувати телефон: <xliff:g id="NUMBER">%d</xliff:g>. Буде видалено робочий профіль і всі його дані."</string>
<string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="1860049973474855672">"Ключ розблокування неправильно намальовано стільки разів: <xliff:g id="NUMBER_0">%1$d</xliff:g>. Залишилося спроб: <xliff:g id="NUMBER_1">%2$d</xliff:g>. У разі невдачі з\'явиться запит розблокувати планшет за допомогою облікового запису електронної пошти.\n\n Повторіть спробу за <xliff:g id="NUMBER_2">%3$d</xliff:g> с."</string>
<string name="kg_failed_attempts_almost_at_login" product="default" msgid="44112553371516141">"Ключ розблокування неправильно намальовано стільки разів: <xliff:g id="NUMBER_0">%1$d</xliff:g>. Залишилося спроб: <xliff:g id="NUMBER_1">%2$d</xliff:g>. У разі невдачі з\'явиться запит розблокувати телефон за допомогою облікового запису електронної пошти.\n\n Повторіть спробу за <xliff:g id="NUMBER_2">%3$d</xliff:g> с."</string>
- <!-- no translation found for global_action_lock_message (7092460751050168771) -->
- <skip />
- <!-- no translation found for global_action_lock_message (1024230056230539493) -->
- <skip />
- <!-- no translation found for global_action_lock_message (3165224897120346096) -->
- <skip />
+ <string name="global_action_lock_message" product="default" msgid="7092460751050168771">"Розблокуйте телефон, щоб переглянути інші параметри"</string>
+ <string name="global_action_lock_message" product="tablet" msgid="1024230056230539493">"Розблокуйте планшет, щоб переглянути інші параметри"</string>
+ <string name="global_action_lock_message" product="device" msgid="3165224897120346096">"Розблокуйте пристрій, щоб переглянути інші параметри"</string>
</resources>
diff --git a/packages/SystemUI/res-product/values-ur/strings.xml b/packages/SystemUI/res-product/values-ur/strings.xml
index 294ad4fa75a9..298a72902d25 100644
--- a/packages/SystemUI/res-product/values-ur/strings.xml
+++ b/packages/SystemUI/res-product/values-ur/strings.xml
@@ -40,10 +40,7 @@
<string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4682221342671290678">"آپ نے فون کو غیر مقفل کرنے کیلئے <xliff:g id="NUMBER">%d</xliff:g> بار غلط طریقے سے کوشش کی ہے۔ دفتری پروفائل ہٹا دی جائے گی، جس سے پروفائل کا سبھی ڈیٹا حذف ہو جائے گا۔"</string>
<string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="1860049973474855672">"آپ نے اپنا غیر مقفل کرنے کا پیٹرن <xliff:g id="NUMBER_0">%1$d</xliff:g> بار غلط طریقے سے ڈرا کیا ہے۔ <xliff:g id="NUMBER_1">%2$d</xliff:g> مزید ناکام کوششوں کے بعد، آپ سے ایک ای میل اکاؤنٹ استعمال کر کے اپنا ٹیبلیٹ غیر مقفل کرنے کو کہا جائے گا۔\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> سیکنڈ میں دوبارہ کوشش کریں۔"</string>
<string name="kg_failed_attempts_almost_at_login" product="default" msgid="44112553371516141">"آپ نے اپنا غیر مقفل کرنے کا پیٹرن <xliff:g id="NUMBER_0">%1$d</xliff:g> بار غلط طریقے سے ڈرا کیا ہے۔ <xliff:g id="NUMBER_1">%2$d</xliff:g> مزید ناکام کوششوں کے بعد، آپ سے ایک ای میل اکاؤنٹ استعمال کر کے اپنا فون غیر مقفل کرنے کو کہا جائے گا۔\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> سیکنڈ میں دوبارہ کوشش کریں۔"</string>
- <!-- no translation found for global_action_lock_message (7092460751050168771) -->
- <skip />
- <!-- no translation found for global_action_lock_message (1024230056230539493) -->
- <skip />
- <!-- no translation found for global_action_lock_message (3165224897120346096) -->
- <skip />
+ <string name="global_action_lock_message" product="default" msgid="7092460751050168771">"مزید اختیارات کے لیے اپنا فون غیر مقفل کریں"</string>
+ <string name="global_action_lock_message" product="tablet" msgid="1024230056230539493">"مزید اختیارات کے لیے اپنا ٹیبلیٹ غیر مقفل کریں"</string>
+ <string name="global_action_lock_message" product="device" msgid="3165224897120346096">"مزید اختیارات کے لیے اپنا آلہ غیر مقفل کریں"</string>
</resources>
diff --git a/packages/SystemUI/res-product/values-uz/strings.xml b/packages/SystemUI/res-product/values-uz/strings.xml
index bc23963abc24..d9c0acdc22f6 100644
--- a/packages/SystemUI/res-product/values-uz/strings.xml
+++ b/packages/SystemUI/res-product/values-uz/strings.xml
@@ -40,10 +40,7 @@
<string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4682221342671290678">"Siz telefonni qulfdan chiqarish uchun <xliff:g id="NUMBER">%d</xliff:g> marta xato urinish qildingiz. Endi ish profili oʻchirib tashlanadi va undagi barcha maʼlumotlar ham oʻchib ketadi."</string>
<string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="1860049973474855672">"Grafik kalit <xliff:g id="NUMBER_0">%1$d</xliff:g> marta xato chizildi. <xliff:g id="NUMBER_1">%2$d</xliff:g> marta muvaffaqiyatsiz urinishdan keyin sizdan emailingizdan foydalanib, planshet qulfini ochishingiz soʻraladi.\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> soniyadan keyin yana urinib koʻring."</string>
<string name="kg_failed_attempts_almost_at_login" product="default" msgid="44112553371516141">"Grafik kalit <xliff:g id="NUMBER_0">%1$d</xliff:g> marta xato chizildi. <xliff:g id="NUMBER_1">%2$d</xliff:g> marta muvaffaqiyatsiz urinishdan keyin sizdan emailngizdan foydalanib, telefon qulfini ochishingiz soʻraladi.\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> soniyadan keyin qayta urinib koʻring."</string>
- <!-- no translation found for global_action_lock_message (7092460751050168771) -->
- <skip />
- <!-- no translation found for global_action_lock_message (1024230056230539493) -->
- <skip />
- <!-- no translation found for global_action_lock_message (3165224897120346096) -->
- <skip />
+ <string name="global_action_lock_message" product="default" msgid="7092460751050168771">"Boshqa parametrlar uchun telefoningiz qulfini oching"</string>
+ <string name="global_action_lock_message" product="tablet" msgid="1024230056230539493">"Boshqa parametrlar uchun planshetingiz qulfini oching"</string>
+ <string name="global_action_lock_message" product="device" msgid="3165224897120346096">"Boshqa parametrlar uchun qurilmangiz qulfini oching"</string>
</resources>
diff --git a/packages/SystemUI/res-product/values-vi/strings.xml b/packages/SystemUI/res-product/values-vi/strings.xml
index a15ee87ca98f..d6fdf9f6bdd2 100644
--- a/packages/SystemUI/res-product/values-vi/strings.xml
+++ b/packages/SystemUI/res-product/values-vi/strings.xml
@@ -40,10 +40,7 @@
<string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4682221342671290678">"Bạn đã mở khóa điện thoại sai <xliff:g id="NUMBER">%d</xliff:g> lần. Hồ sơ công việc sẽ bị xóa, tức là tất cả dữ liệu hồ sơ sẽ bị xóa."</string>
<string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="1860049973474855672">"Bạn đã vẽ không chính xác hình mở khóa <xliff:g id="NUMBER_0">%1$d</xliff:g> lần. Sau <xliff:g id="NUMBER_1">%2$d</xliff:g> lần thử không thành công nữa, bạn sẽ được yêu cầu mở khóa máy tính bảng bằng tài khoản email.\n\n Hãy thử lại sau <xliff:g id="NUMBER_2">%3$d</xliff:g> giây."</string>
<string name="kg_failed_attempts_almost_at_login" product="default" msgid="44112553371516141">"Bạn đã vẽ không chính xác hình mở khóa <xliff:g id="NUMBER_0">%1$d</xliff:g> lần. Sau <xliff:g id="NUMBER_1">%2$d</xliff:g> lần thử không thành công nữa, bạn sẽ được yêu cầu mở khóa điện thoại bằng tài khoản email.\n\n Hãy thử lại sau <xliff:g id="NUMBER_2">%3$d</xliff:g> giây."</string>
- <!-- no translation found for global_action_lock_message (7092460751050168771) -->
- <skip />
- <!-- no translation found for global_action_lock_message (1024230056230539493) -->
- <skip />
- <!-- no translation found for global_action_lock_message (3165224897120346096) -->
- <skip />
+ <string name="global_action_lock_message" product="default" msgid="7092460751050168771">"Mở khóa điện thoại của bạn để xem thêm tùy chọn"</string>
+ <string name="global_action_lock_message" product="tablet" msgid="1024230056230539493">"Mở khóa máy tính bảng của bạn để xem thêm tùy chọn"</string>
+ <string name="global_action_lock_message" product="device" msgid="3165224897120346096">"Mở khóa thiết bị của bạn để xem thêm tùy chọn"</string>
</resources>
diff --git a/packages/SystemUI/res-product/values-zh-rCN/strings.xml b/packages/SystemUI/res-product/values-zh-rCN/strings.xml
index b15b6dd272c0..19196eb6d4aa 100644
--- a/packages/SystemUI/res-product/values-zh-rCN/strings.xml
+++ b/packages/SystemUI/res-product/values-zh-rCN/strings.xml
@@ -40,10 +40,7 @@
<string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4682221342671290678">"您尝试解锁手机后失败的次数已达 <xliff:g id="NUMBER">%d</xliff:g> 次。系统将移除此工作资料,而这将删除所有的工作资料数据。"</string>
<string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="1860049973474855672">"您已 <xliff:g id="NUMBER_0">%1$d</xliff:g> 次画错解锁图案。如果再尝试 <xliff:g id="NUMBER_1">%2$d</xliff:g> 次后仍不成功,系统就会要求您使用自己的电子邮件帐号解锁平板电脑。\n\n请在 <xliff:g id="NUMBER_2">%3$d</xliff:g> 秒后重试。"</string>
<string name="kg_failed_attempts_almost_at_login" product="default" msgid="44112553371516141">"您已 <xliff:g id="NUMBER_0">%1$d</xliff:g> 次画错解锁图案。如果再尝试 <xliff:g id="NUMBER_1">%2$d</xliff:g> 次后仍不成功,系统就会要求您使用自己的电子邮件帐号解锁手机。\n\n请在 <xliff:g id="NUMBER_2">%3$d</xliff:g> 秒后重试。"</string>
- <!-- no translation found for global_action_lock_message (7092460751050168771) -->
- <skip />
- <!-- no translation found for global_action_lock_message (1024230056230539493) -->
- <skip />
- <!-- no translation found for global_action_lock_message (3165224897120346096) -->
- <skip />
+ <string name="global_action_lock_message" product="default" msgid="7092460751050168771">"解锁手机即可查看更多选项"</string>
+ <string name="global_action_lock_message" product="tablet" msgid="1024230056230539493">"解锁平板电脑即可查看更多选项"</string>
+ <string name="global_action_lock_message" product="device" msgid="3165224897120346096">"解锁设备即可查看更多选项"</string>
</resources>
diff --git a/packages/SystemUI/res-product/values-zh-rHK/strings.xml b/packages/SystemUI/res-product/values-zh-rHK/strings.xml
index e625a1a80500..27eda7705f20 100644
--- a/packages/SystemUI/res-product/values-zh-rHK/strings.xml
+++ b/packages/SystemUI/res-product/values-zh-rHK/strings.xml
@@ -40,10 +40,7 @@
<string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4682221342671290678">"您嘗試解鎖手機已失敗 <xliff:g id="NUMBER">%d</xliff:g> 次。系統將移除此工作設定檔,而所有設定檔資料亦會一併刪除。"</string>
<string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="1860049973474855672">"您已畫錯解鎖圖案 <xliff:g id="NUMBER_0">%1$d</xliff:g> 次。如果之後再嘗試 <xliff:g id="NUMBER_1">%2$d</xliff:g> 次仍未成功,系統會要求您透過電郵帳戶解鎖平板電腦。\n\n請在 <xliff:g id="NUMBER_2">%3$d</xliff:g> 秒後再試一次。"</string>
<string name="kg_failed_attempts_almost_at_login" product="default" msgid="44112553371516141">"您已畫錯解鎖圖案 <xliff:g id="NUMBER_0">%1$d</xliff:g> 次。如果之後再嘗試 <xliff:g id="NUMBER_1">%2$d</xliff:g> 次仍未成功,系統會要求您透過電郵帳戶解鎖手機。\n\n請在 <xliff:g id="NUMBER_2">%3$d</xliff:g> 秒後再試一次。"</string>
- <!-- no translation found for global_action_lock_message (7092460751050168771) -->
- <skip />
- <!-- no translation found for global_action_lock_message (1024230056230539493) -->
- <skip />
- <!-- no translation found for global_action_lock_message (3165224897120346096) -->
- <skip />
+ <string name="global_action_lock_message" product="default" msgid="7092460751050168771">"解鎖手機以存取更多選項"</string>
+ <string name="global_action_lock_message" product="tablet" msgid="1024230056230539493">"解鎖平板電腦以存取更多選項"</string>
+ <string name="global_action_lock_message" product="device" msgid="3165224897120346096">"解鎖裝置以存取更多選項"</string>
</resources>
diff --git a/packages/SystemUI/res-product/values-zh-rTW/strings.xml b/packages/SystemUI/res-product/values-zh-rTW/strings.xml
index 5810ac96f3eb..e484b663bb54 100644
--- a/packages/SystemUI/res-product/values-zh-rTW/strings.xml
+++ b/packages/SystemUI/res-product/values-zh-rTW/strings.xml
@@ -40,10 +40,7 @@
<string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4682221342671290678">"你嘗試解鎖手機已失敗 <xliff:g id="NUMBER">%d</xliff:g> 次。你的工作資料夾將遭到移除,所有設定檔資料也會一併遭到刪除。"</string>
<string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="1860049973474855672">"你的解鎖圖案已畫錯 <xliff:g id="NUMBER_0">%1$d</xliff:g> 次,目前還剩 <xliff:g id="NUMBER_1">%2$d</xliff:g> 次機會。如果失敗次數超過限制,系統會要求你透過電子郵件帳戶將平板電腦解鎖。\n\n請在 <xliff:g id="NUMBER_2">%3$d</xliff:g> 秒後再試一次。"</string>
<string name="kg_failed_attempts_almost_at_login" product="default" msgid="44112553371516141">"你的解鎖圖案已畫錯 <xliff:g id="NUMBER_0">%1$d</xliff:g> 次,目前還剩 <xliff:g id="NUMBER_1">%2$d</xliff:g> 次機會。如果失敗次數超過限制,系統會要求你透過電子郵件帳戶將手機解鎖。\n\n請在 <xliff:g id="NUMBER_2">%3$d</xliff:g> 秒後再試一次。"</string>
- <!-- no translation found for global_action_lock_message (7092460751050168771) -->
- <skip />
- <!-- no translation found for global_action_lock_message (1024230056230539493) -->
- <skip />
- <!-- no translation found for global_action_lock_message (3165224897120346096) -->
- <skip />
+ <string name="global_action_lock_message" product="default" msgid="7092460751050168771">"解鎖手機可查看更多選項"</string>
+ <string name="global_action_lock_message" product="tablet" msgid="1024230056230539493">"解鎖平板電腦可查看更多選項"</string>
+ <string name="global_action_lock_message" product="device" msgid="3165224897120346096">"解鎖裝置可查看更多選項"</string>
</resources>
diff --git a/packages/SystemUI/res-product/values-zu/strings.xml b/packages/SystemUI/res-product/values-zu/strings.xml
index 595447c5e556..e6c140a76bdf 100644
--- a/packages/SystemUI/res-product/values-zu/strings.xml
+++ b/packages/SystemUI/res-product/values-zu/strings.xml
@@ -40,10 +40,7 @@
<string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4682221342671290678">"Uzame ngokungalungile ukuvula ifoni izikhathi ezingu-<xliff:g id="NUMBER">%d</xliff:g>. Iphrofayela yomsebenzi izosuswa, okuzosusa yonke idatha yephrofayela."</string>
<string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="1860049973474855672">"Udwebe ngokungalungile iphethini yakho yokuvula ngezikhathi ezingu-<xliff:g id="NUMBER_0">%1$d</xliff:g>. Ngemuva kwemizamo engaphumelelanga kaningi engu-<xliff:g id="NUMBER_1">%2$d</xliff:g>, uzocelwa ukuthi uvule ithebulethi yakho usebenzisa i-akhawunti ye-imeyili.\n\nZama futhi kumasekhondi angu-<xliff:g id="NUMBER_2">%3$d</xliff:g>."</string>
<string name="kg_failed_attempts_almost_at_login" product="default" msgid="44112553371516141">"Ukulayisha ungenisa iphathini yakho yokuvula ngendlela engalungile izikhathi ezi-<xliff:g id="NUMBER_0">%1$d</xliff:g> Emva kweminye imizamo engu-<xliff:g id="NUMBER_1">%2$d</xliff:g>, uzocelwa ukuvula ifoni yakho usebenzisa ukungena ngemvume ku-Google\n\n Zame futhi emumva kwengu- <xliff:g id="NUMBER_2">%3$d</xliff:g> imizuzwana."</string>
- <!-- no translation found for global_action_lock_message (7092460751050168771) -->
- <skip />
- <!-- no translation found for global_action_lock_message (1024230056230539493) -->
- <skip />
- <!-- no translation found for global_action_lock_message (3165224897120346096) -->
- <skip />
+ <string name="global_action_lock_message" product="default" msgid="7092460751050168771">"Vula ifoni yakho ukuthola izinketho ezengeziwe"</string>
+ <string name="global_action_lock_message" product="tablet" msgid="1024230056230539493">"Vula ithebulethi yakho ukuthola izinketho ezengeziwe"</string>
+ <string name="global_action_lock_message" product="device" msgid="3165224897120346096">"Vula idivayisi yakho ukuthola izinketho ezengeziwe"</string>
</resources>
diff --git a/packages/SystemUI/res/drawable/dismiss_circle_background.xml b/packages/SystemUI/res/drawable/dismiss_circle_background.xml
index e311c520d3d6..7809c8398c2d 100644
--- a/packages/SystemUI/res/drawable/dismiss_circle_background.xml
+++ b/packages/SystemUI/res/drawable/dismiss_circle_background.xml
@@ -21,8 +21,8 @@
<stroke
android:width="1dp"
- android:color="#66FFFFFF" />
+ android:color="#AAFFFFFF" />
- <solid android:color="#B3000000" />
+ <solid android:color="#77000000" />
</shape> \ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/floating_dismiss_gradient.xml b/packages/SystemUI/res/drawable/floating_dismiss_gradient.xml
new file mode 100644
index 000000000000..8f7fb1011cf4
--- /dev/null
+++ b/packages/SystemUI/res/drawable/floating_dismiss_gradient.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+<shape
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:shape="rectangle">
+ <gradient
+ android:angle="270"
+ android:startColor="#00000000"
+ android:endColor="#77000000"
+ android:type="linear" />
+</shape> \ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/floating_dismiss_gradient_transition.xml b/packages/SystemUI/res/drawable/floating_dismiss_gradient_transition.xml
new file mode 100644
index 000000000000..6a0695e817c7
--- /dev/null
+++ b/packages/SystemUI/res/drawable/floating_dismiss_gradient_transition.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+<transition xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:drawable="@color/transparent" />
+ <item android:drawable="@drawable/floating_dismiss_gradient" />
+</transition> \ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/ic_create_bubble.xml b/packages/SystemUI/res/drawable/ic_create_bubble.xml
index d58e9a347a2f..4abbc8179b4d 100644
--- a/packages/SystemUI/res/drawable/ic_create_bubble.xml
+++ b/packages/SystemUI/res/drawable/ic_create_bubble.xml
@@ -15,11 +15,11 @@
limitations under the License.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="24dp"
- android:height="24dp"
+ android:width="20dp"
+ android:height="20dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="#FF000000"
- android:pathData="M22,12C22,12 22,12 22,12C22,12 22,12 22,12c0,0.56 -0.06,1.1 -0.15,1.64l-1.97,-0.33c0.15,-0.91 0.15,-1.84 -0.02,-2.75c-0.01,-0.03 -0.01,-0.07 -0.02,-0.1c-0.03,-0.18 -0.08,-0.36 -0.13,-0.54c-0.02,-0.08 -0.04,-0.16 -0.06,-0.24c-0.04,-0.14 -0.09,-0.27 -0.14,-0.41c-0.04,-0.12 -0.08,-0.24 -0.13,-0.35c-0.04,-0.09 -0.08,-0.18 -0.13,-0.27c-0.07,-0.15 -0.14,-0.3 -0.22,-0.45c-0.03,-0.05 -0.06,-0.09 -0.08,-0.14c-0.72,-1.26 -1.77,-2.31 -3.03,-3.03c-0.05,-0.03 -0.09,-0.06 -0.14,-0.08c-0.15,-0.08 -0.3,-0.15 -0.45,-0.22c-0.09,-0.04 -0.18,-0.09 -0.27,-0.13c-0.11,-0.05 -0.23,-0.09 -0.35,-0.13c-0.14,-0.05 -0.27,-0.1 -0.41,-0.14c-0.08,-0.02 -0.16,-0.04 -0.23,-0.06c-0.18,-0.05 -0.36,-0.1 -0.54,-0.13c-0.03,-0.01 -0.07,-0.01 -0.1,-0.01c-0.95,-0.17 -1.93,-0.17 -2.88,0c-0.03,0.01 -0.07,0.01 -0.1,0.01c-0.18,0.04 -0.36,0.08 -0.54,0.13C9.85,4.3 9.77,4.32 9.69,4.34C9.55,4.38 9.42,4.44 9.28,4.49C9.17,4.53 9.05,4.57 8.93,4.61C8.84,4.65 8.75,4.7 8.66,4.74c-0.15,0.07 -0.3,0.14 -0.45,0.22C8.16,4.98 8.12,5.01 8.07,5.04C5.64,6.42 4,9.02 4,12c0,2.74 1.39,5.16 3.49,6.6c0.01,0.01 0.03,0.02 0.04,0.03c0.16,0.11 0.33,0.2 0.49,0.3c0.06,0.04 0.12,0.08 0.19,0.11c0.13,0.07 0.27,0.13 0.4,0.19c0.11,0.05 0.21,0.1 0.32,0.15c0.1,0.04 0.2,0.07 0.29,0.11c0.15,0.06 0.31,0.11 0.46,0.16c0.05,0.02 0.11,0.03 0.17,0.04c1.11,0.31 2.27,0.35 3.4,0.18l0.35,1.98c-0.54,0.09 -1.08,0.14 -1.62,0.14V22c-0.65,0 -1.28,-0.07 -1.9,-0.19c-0.01,0 -0.01,0 -0.02,0c-0.25,-0.05 -0.49,-0.11 -0.73,-0.18c-0.08,-0.02 -0.16,-0.04 -0.23,-0.06c-0.19,-0.06 -0.37,-0.13 -0.55,-0.19c-0.13,-0.05 -0.26,-0.09 -0.39,-0.14c-0.13,-0.05 -0.25,-0.12 -0.38,-0.18c-0.18,-0.08 -0.35,-0.16 -0.53,-0.25c-0.07,-0.04 -0.14,-0.08 -0.21,-0.13c-0.22,-0.12 -0.43,-0.25 -0.64,-0.39c-0.01,-0.01 -0.02,-0.02 -0.04,-0.03c-0.51,-0.35 -1,-0.74 -1.45,-1.2l0,0C3.12,17.26 2,14.76 2,12c0,-2.76 1.12,-5.26 2.93,-7.07l0,0c0.45,-0.45 0.93,-0.84 1.44,-1.19C6.39,3.73 6.4,3.72 6.42,3.71c0.2,-0.14 0.41,-0.26 0.62,-0.38c0.08,-0.05 0.15,-0.09 0.23,-0.14c0.17,-0.09 0.33,-0.16 0.5,-0.24c0.13,-0.06 0.27,-0.13 0.4,-0.19C8.3,2.71 8.42,2.67 8.55,2.63c0.19,-0.07 0.38,-0.14 0.58,-0.2c0.07,-0.02 0.14,-0.03 0.21,-0.05C10.18,2.14 11.07,2 12,2c0.65,0 1.29,0.07 1.91,0.19c0,0 0,0 0,0c0.25,0.05 0.5,0.11 0.75,0.18c0.07,0.02 0.14,0.03 0.22,0.06c0.19,0.06 0.38,0.13 0.57,0.2c0.12,0.05 0.25,0.09 0.37,0.14c0.14,0.06 0.27,0.12 0.4,0.18c0.17,0.08 0.34,0.16 0.51,0.25c0.08,0.04 0.15,0.09 0.23,0.14c0.21,0.12 0.42,0.24 0.62,0.38c0.01,0.01 0.03,0.02 0.04,0.03c0.51,0.35 0.99,0.74 1.45,1.19c0.24,0.24 0.47,0.49 0.68,0.75c0.04,0.04 0.06,0.09 0.1,0.13c0.17,0.22 0.34,0.45 0.5,0.68c0.01,0.01 0.02,0.03 0.03,0.04c0.69,1.05 1.17,2.21 1.42,3.44c0,0 0,0.01 0,0.01c0.06,0.29 0.1,0.58 0.13,0.87c0.01,0.04 0.01,0.09 0.02,0.13C21.98,11.32 22,11.66 22,12zM18.5,15c-1.93,0 -3.5,1.57 -3.5,3.5s1.57,3.5 3.5,3.5s3.5,-1.57 3.5,-3.5S20.43,15 18.5,15z"/>
-</vector> \ No newline at end of file
+ android:pathData="M23,5v8h-2V5H3v14h10v2v0H3c-1.1,0 -2,-0.9 -2,-2V5c0,-1.1 0.9,-2 2,-2h18C22.1,3 23,3.9 23,5zM10,8v2.59L5.71,6.29L4.29,7.71L8.59,12H6v2h6V8H10zM19,15c-1.66,0 -3,1.34 -3,3s1.34,3 3,3s3,-1.34 3,-3S20.66,15 19,15z"/>
+</vector>
diff --git a/packages/SystemUI/res/drawable/ic_error_outline.xml b/packages/SystemUI/res/drawable/ic_error_outline.xml
new file mode 100644
index 000000000000..140180ae8dbf
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_error_outline.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ 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
+ -->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24">
+ <path
+ android:fillColor="#FF000000"
+ android:pathData="M11,15h2v2h-2v-2zM11,7h2v6h-2L11,7zM11.99,2C6.47,2 2,6.48 2,12s4.47,10 9.99,10C17.52,22 22,17.52 22,12S17.52,2 11.99,2zM12,20c-4.42,0 -8,-3.58 -8,-8s3.58,-8 8,-8 8,3.58 8,8 -3.58,8 -8,8z"/>
+</vector>
diff --git a/packages/SystemUI/res/drawable/dismiss_target_x.xml b/packages/SystemUI/res/drawable/ic_music_note.xml
index 3672efffe139..30959a870a02 100644
--- a/packages/SystemUI/res/drawable/dismiss_target_x.xml
+++ b/packages/SystemUI/res/drawable/ic_music_note.xml
@@ -1,4 +1,3 @@
-<?xml version="1.0" encoding="utf-8"?>
<!--
~ Copyright (C) 2020 The Android Open Source Project
~
@@ -14,15 +13,12 @@
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->
-
-<!-- 'X' icon. -->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="24.0dp"
- android:height="24.0dp"
- android:viewportWidth="24.0"
- android:viewportHeight="24.0">
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24">
<path
- android:pathData="M19.000000,6.400000l-1.400000,-1.400000 -5.600000,5.600000 -5.600000,-5.600000 -1.400000,1.400000 5.600000,5.600000 -5.600000,5.600000 1.400000,1.400000 5.600000,-5.600000 5.600000,5.600000 1.400000,-1.400000 -5.600000,-5.600000z"
- android:fillColor="#FFFFFFFF"
- android:strokeColor="#FF000000"/>
-</vector> \ No newline at end of file
+ android:fillColor="#FF000000"
+ android:pathData="M12,3v10.55c-0.59,-0.34 -1.27,-0.55 -2,-0.55 -2.21,0 -4,1.79 -4,4s1.79,4 4,4 4,-1.79 4,-4V7h4V3h-6z"/>
+</vector>
diff --git a/packages/SystemUI/res/drawable/ic_settings_power.xml b/packages/SystemUI/res/drawable/ic_settings_power.xml
new file mode 100644
index 000000000000..137c289ac572
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_settings_power.xml
@@ -0,0 +1,25 @@
+<!--
+ ~ 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.
+ -->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24">
+ <path
+ android:pathData="M8,24c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1 -1,0.45 -1,1 0.45,1 1,1zM12,24c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1 -1,0.45 -1,1 0.45,1 1,1zM13,2h-2v10h2L13,2zM16.56,4.44l-1.45,1.45C16.84,6.94 18,8.83 18,11c0,3.31 -2.69,6 -6,6s-6,-2.69 -6,-6c0,-2.17 1.16,-4.06 2.88,-5.12L7.44,4.44C5.36,5.88 4,8.28 4,11c0,4.42 3.58,8 8,8s8,-3.58 8,-8c0,-2.72 -1.36,-5.12 -3.44,-6.56zM16,24c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1 -1,0.45 -1,1 0.45,1 1,1z"
+ android:fillColor="#000000"/>
+</vector> \ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/ic_stop_bubble.xml b/packages/SystemUI/res/drawable/ic_stop_bubble.xml
index 11bc741a4f17..6cf67a77ff55 100644
--- a/packages/SystemUI/res/drawable/ic_stop_bubble.xml
+++ b/packages/SystemUI/res/drawable/ic_stop_bubble.xml
@@ -15,11 +15,11 @@
limitations under the License.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="24dp"
- android:height="24dp"
+ android:width="20dp"
+ android:height="20dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="#FF000000"
- android:pathData="M21.98,18.32l-3.3,-3.3C20.47,15.11 21.89,16.53 21.98,18.32zM8.66,4.74C8.75,4.7 8.84,4.65 8.93,4.61c0.11,-0.05 0.23,-0.09 0.35,-0.13c0.14,-0.05 0.27,-0.1 0.41,-0.14C9.77,4.32 9.85,4.3 9.92,4.28c0.18,-0.05 0.36,-0.1 0.54,-0.13c0.03,-0.01 0.07,-0.01 0.1,-0.01c0.95,-0.17 1.93,-0.17 2.88,0c0.03,0.01 0.07,0.01 0.1,0.01c0.18,0.04 0.36,0.08 0.54,0.13c0.08,0.02 0.16,0.04 0.23,0.06c0.14,0.04 0.27,0.09 0.41,0.14c0.12,0.04 0.23,0.08 0.35,0.13c0.09,0.04 0.18,0.09 0.27,0.13c0.15,0.07 0.3,0.14 0.45,0.22c0.05,0.03 0.09,0.06 0.14,0.08c1.26,0.72 2.31,1.77 3.03,3.03c0.03,0.05 0.06,0.09 0.08,0.14c0.08,0.15 0.15,0.3 0.22,0.45c0.04,0.09 0.09,0.18 0.13,0.27c0.05,0.11 0.09,0.23 0.13,0.35c0.05,0.13 0.1,0.27 0.14,0.41c0.02,0.08 0.04,0.16 0.06,0.24c0.05,0.18 0.1,0.36 0.13,0.54c0.01,0.03 0.01,0.07 0.02,0.1c0.16,0.91 0.17,1.84 0.02,2.75l1.97,0.33C21.94,13.1 22,12.56 22,12c0,0 0,0 0,0s0,0 0,0c0,-0.34 -0.02,-0.68 -0.05,-1.01c0,-0.04 -0.01,-0.09 -0.02,-0.13c-0.03,-0.29 -0.07,-0.58 -0.13,-0.87c0,0 0,-0.01 0,-0.01c-0.25,-1.23 -0.73,-2.39 -1.42,-3.44c-0.01,-0.01 -0.02,-0.03 -0.03,-0.04c-0.15,-0.23 -0.32,-0.46 -0.5,-0.68c-0.03,-0.04 -0.06,-0.09 -0.1,-0.13c-0.21,-0.26 -0.44,-0.51 -0.68,-0.75c-0.45,-0.45 -0.94,-0.84 -1.45,-1.19c-0.01,-0.01 -0.03,-0.02 -0.04,-0.03c-0.2,-0.14 -0.41,-0.26 -0.62,-0.38c-0.08,-0.04 -0.15,-0.09 -0.23,-0.14c-0.17,-0.09 -0.34,-0.17 -0.51,-0.25c-0.13,-0.06 -0.26,-0.13 -0.4,-0.18c-0.12,-0.05 -0.25,-0.09 -0.37,-0.14c-0.19,-0.07 -0.38,-0.14 -0.57,-0.2c-0.07,-0.02 -0.14,-0.04 -0.22,-0.06c-0.25,-0.07 -0.5,-0.13 -0.75,-0.18c0,0 0,0 0,0C13.29,2.07 12.65,2 12,2c-0.93,0 -1.82,0.14 -2.67,0.37C9.26,2.39 9.19,2.41 9.12,2.43c-0.2,0.06 -0.39,0.13 -0.58,0.2C8.42,2.67 8.3,2.71 8.18,2.76c-0.14,0.06 -0.27,0.12 -0.4,0.19C7.61,3.03 7.44,3.1 7.27,3.19C7.19,3.24 7.12,3.29 7.04,3.33C7.03,3.34 7.02,3.34 7.01,3.35l1.48,1.48C8.55,4.8 8.6,4.77 8.66,4.74zM2.71,1.29L1.29,2.71l2.97,2.97C2.85,7.4 2,9.6 2,12c0,2.76 1.12,5.26 2.93,7.07l0,0c0.45,0.45 0.94,0.85 1.45,1.2c0.01,0.01 0.02,0.02 0.04,0.03c0.21,0.14 0.42,0.27 0.64,0.39c0.07,0.04 0.14,0.09 0.21,0.13c0.17,0.09 0.35,0.17 0.53,0.25c0.13,0.06 0.25,0.12 0.38,0.18c0.13,0.05 0.26,0.1 0.39,0.14c0.18,0.07 0.36,0.14 0.55,0.19c0.08,0.02 0.16,0.04 0.23,0.06c0.24,0.07 0.48,0.13 0.73,0.18c0.01,0 0.01,0 0.02,0C10.72,21.93 11.35,22 12,22v-0.01c0.54,0 1.08,-0.05 1.62,-0.14l-0.35,-1.98c-1.13,0.18 -2.29,0.13 -3.4,-0.18c-0.06,-0.02 -0.11,-0.03 -0.17,-0.04c-0.16,-0.05 -0.31,-0.11 -0.46,-0.16c-0.1,-0.04 -0.2,-0.07 -0.29,-0.11c-0.11,-0.05 -0.22,-0.1 -0.32,-0.15c-0.13,-0.06 -0.27,-0.12 -0.4,-0.19c-0.06,-0.03 -0.13,-0.08 -0.19,-0.11c-0.17,-0.1 -0.33,-0.19 -0.49,-0.3c-0.01,-0.01 -0.03,-0.02 -0.04,-0.03C5.39,17.16 4,14.74 4,12c0,-1.85 0.64,-3.54 1.7,-4.89l9.73,9.73C15.16,17.33 15,17.9 15,18.5c0,1.93 1.57,3.5 3.5,3.5c0.6,0 1.17,-0.16 1.66,-0.43l1.13,1.13l1.41,-1.41L2.71,1.29z"/>
+ android:pathData="M11.29,14.71L7,10.41V13H5V7h6v2H8.41l4.29,4.29L11.29,14.71zM21,3H3C1.9,3 1,3.9 1,5v14c0,1.1 0.9,2 2,2h10v0v-2H3V5h18v8h2V5C23,3.9 22.1,3 21,3zM19,15c-1.66,0 -3,1.34 -3,3s1.34,3 3,3s3,-1.34 3,-3S20.66,15 19,15z"/>
</vector>
diff --git a/packages/SystemUI/res/layout-sw600dp/keyguard_user_switcher_item.xml b/packages/SystemUI/res/layout-sw600dp/keyguard_user_switcher_item.xml
index 4413b1ef3cd3..9ce030e844d4 100644
--- a/packages/SystemUI/res/layout-sw600dp/keyguard_user_switcher_item.xml
+++ b/packages/SystemUI/res/layout-sw600dp/keyguard_user_switcher_item.xml
@@ -27,13 +27,13 @@
android:gravity="end|center_vertical"
android:clickable="true"
android:background="@drawable/kg_user_switcher_rounded_bg"
+ sysui:activatedTextAppearance="@style/TextAppearance.StatusBar.Expanded.UserSwitcher"
sysui:regularTextAppearance="@style/TextAppearance.StatusBar.Expanded.UserSwitcher">
<TextView android:id="@+id/user_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="25dp"
android:layout_marginEnd="12dp"
- android:textAppearance="@style/TextAppearance.StatusBar.Expanded.UserSwitcher"
/>
<com.android.systemui.statusbar.phone.UserAvatarView android:id="@+id/user_picture"
android:layout_width="@dimen/kg_framed_avatar_size"
diff --git a/packages/SystemUI/res/layout/bubbles_manage_button_education.xml b/packages/SystemUI/res/layout/bubbles_manage_button_education.xml
index 0cabc3245152..7313d54c599a 100644
--- a/packages/SystemUI/res/layout/bubbles_manage_button_education.xml
+++ b/packages/SystemUI/res/layout/bubbles_manage_button_education.xml
@@ -17,30 +17,72 @@
<com.android.systemui.bubbles.BubbleManageEducationView
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
- android:layout_height="match_parent">
-
+ android:layout_height="match_parent"
+ >
<LinearLayout
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
android:id="@+id/manage_education_view"
+ android:clickable="true"
+ android:paddingTop="28dp"
+ android:paddingBottom="16dp"
+ android:paddingStart="@dimen/bubble_expanded_view_padding"
+ android:paddingEnd="48dp"
+ android:layout_marginEnd="24dp"
android:orientation="vertical"
- android:layout_height="wrap_content"
- android:layout_width="@dimen/bubbles_manage_education_width">
+ android:background="@drawable/bubble_stack_user_education_bg"
+ android:alpha="0.9"
+ >
+
+ <TextView
+ android:id="@+id/user_education_title"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:paddingStart="16dp"
+ android:paddingBottom="16dp"
+ android:fontFamily="@*android:string/config_bodyFontFamilyMedium"
+ android:maxLines="1"
+ android:text="@string/bubbles_user_education_manage_title"
+ android:textAppearance="@*android:style/TextAppearance.DeviceDefault.Headline"/>
<TextView
android:id="@+id/user_education_description"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:padding="8dp"
+ android:paddingStart="16dp"
+ android:paddingBottom="24dp"
android:text="@string/bubbles_user_education_manage"
android:fontFamily="@*android:string/config_bodyFontFamily"
- android:textAppearance="@*android:style/TextAppearance.DeviceDefault.Body2"
- android:background="@drawable/bubble_manage_user_education_bg"
- />
+ android:textAppearance="@*android:style/TextAppearance.DeviceDefault.Body2"/>
+
+ <LinearLayout
+ android:layout_height="wrap_content"
+ android:layout_width="wrap_content"
+ android:orientation="horizontal" >
- <View
- android:id="@+id/user_education_pointer"
- android:layout_width="@dimen/bubble_pointer_width"
- android:layout_height="@dimen/bubble_pointer_height"
- />
+ <com.android.systemui.statusbar.AlphaOptimizedButton
+ style="@android:style/Widget.Material.Button.Borderless"
+ android:id="@+id/manage"
+ android:layout_gravity="start"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:focusable="true"
+ android:clickable="false"
+ android:text="@string/manage_bubbles_text"
+ android:textColor="?attr/wallpaperTextColor"
+ android:alpha="0.89"
+ />
+ <com.android.systemui.statusbar.AlphaOptimizedButton
+ style="@android:style/Widget.Material.Button.Borderless"
+ android:id="@+id/got_it"
+ android:layout_gravity="start"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:focusable="true"
+ android:text="@string/bubbles_user_education_got_it"
+ android:textColor="?attr/wallpaperTextColor"
+ />
+ </LinearLayout>
</LinearLayout>
</com.android.systemui.bubbles.BubbleManageEducationView> \ No newline at end of file
diff --git a/packages/SystemUI/res/layout/controls_base_item.xml b/packages/SystemUI/res/layout/controls_base_item.xml
index 477a70f4c7ad..5f83f45958e9 100644
--- a/packages/SystemUI/res/layout/controls_base_item.xml
+++ b/packages/SystemUI/res/layout/controls_base_item.xml
@@ -52,6 +52,7 @@
android:singleLine="true"
android:ellipsize="marquee"
android:marqueeRepeatLimit = "marquee_forever"
+ android:textDirection="locale"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintBottom_toBottomOf="@+id/icon"
app:layout_constraintStart_toEndOf="@+id/icon" />
@@ -67,6 +68,7 @@
android:focusable="false"
android:maxLines="1"
android:ellipsize="end"
+ android:textDirection="locale"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintBottom_toTopOf="@id/barrier"/>
@@ -90,6 +92,7 @@
android:focusable="false"
android:maxLines="1"
android:ellipsize="end"
+ android:textDirection="locale"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toStartOf="@id/favorite"
app:layout_constraintTop_toTopOf="@id/favorite"
diff --git a/packages/SystemUI/res/layout/controls_detail_dialog.xml b/packages/SystemUI/res/layout/controls_detail_dialog.xml
index d61122fd47dd..ee5315ad782f 100644
--- a/packages/SystemUI/res/layout/controls_detail_dialog.xml
+++ b/packages/SystemUI/res/layout/controls_detail_dialog.xml
@@ -42,6 +42,7 @@
android:layout_height="1dp" />
<ImageView
android:id="@+id/control_detail_open_in_app"
+ android:contentDescription="@string/controls_open_app"
android:src="@drawable/ic_open_in_new"
android:background="?android:attr/selectableItemBackgroundBorderless"
android:tint="@color/control_primary_text"
diff --git a/packages/SystemUI/res/layout/controls_more_item.xml b/packages/SystemUI/res/layout/controls_more_item.xml
index df03787d567c..da9c43ccc1e9 100644
--- a/packages/SystemUI/res/layout/controls_more_item.xml
+++ b/packages/SystemUI/res/layout/controls_more_item.xml
@@ -20,5 +20,6 @@
android:layout_height="wrap_content"
android:layout_gravity="start"
android:paddingStart="@dimen/control_menu_horizontal_padding"
- android:paddingEnd="@dimen/control_menu_horizontal_padding"/>
+ android:paddingEnd="@dimen/control_menu_horizontal_padding"
+ android:textDirection="locale"/>
diff --git a/packages/SystemUI/res/layout/global_screenshot.xml b/packages/SystemUI/res/layout/global_screenshot.xml
index fce4610b934b..6a235218b32f 100644
--- a/packages/SystemUI/res/layout/global_screenshot.xml
+++ b/packages/SystemUI/res/layout/global_screenshot.xml
@@ -30,11 +30,10 @@
android:id="@+id/global_screenshot_animated_view"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:layout_gravity="center"
+ android:layout_gravity="top|start"
android:visibility="gone"
android:elevation="@dimen/screenshot_preview_elevation"
- android:background="@drawable/screenshot_rounded_corners"
- android:adjustViewBounds="true"/>
+ android:background="@drawable/screenshot_rounded_corners" />
<ImageView
android:id="@+id/global_screenshot_flash"
android:layout_width="match_parent"
diff --git a/packages/SystemUI/res/layout/global_screenshot_static.xml b/packages/SystemUI/res/layout/global_screenshot_static.xml
index a46823d9bc38..da5277ce3876 100644
--- a/packages/SystemUI/res/layout/global_screenshot_static.xml
+++ b/packages/SystemUI/res/layout/global_screenshot_static.xml
@@ -53,15 +53,6 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
</HorizontalScrollView>
- <ImageView
- android:id="@+id/global_screenshot_animated_view"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:layout_gravity="center"
- android:visibility="gone"
- android:elevation="@dimen/screenshot_preview_elevation"
- android:background="@drawable/screenshot_rounded_corners"
- android:adjustViewBounds="true"/>
<include layout="@layout/global_screenshot_preview"/>
<FrameLayout
android:id="@+id/global_screenshot_dismiss_button"
diff --git a/packages/SystemUI/res/layout/keyguard_user_switcher_item.xml b/packages/SystemUI/res/layout/keyguard_user_switcher_item.xml
index 626951c8c0b7..1cd1a04ab462 100644
--- a/packages/SystemUI/res/layout/keyguard_user_switcher_item.xml
+++ b/packages/SystemUI/res/layout/keyguard_user_switcher_item.xml
@@ -39,8 +39,6 @@
android:layout_width="@dimen/kg_framed_avatar_size"
android:layout_height="@dimen/kg_framed_avatar_size"
android:contentDescription="@null"
- android:backgroundTint="@color/qs_user_detail_avatar_tint"
- android:backgroundTintMode="src_atop"
sysui:frameWidth="@dimen/keyguard_user_switcher_border_thickness"
sysui:framePadding="2.5dp"
sysui:badgeDiameter="18dp"
diff --git a/packages/SystemUI/res/layout/notification_conversation_info.xml b/packages/SystemUI/res/layout/notification_conversation_info.xml
index 3bd7e04f2094..2c4b937ce95b 100644
--- a/packages/SystemUI/res/layout/notification_conversation_info.xml
+++ b/packages/SystemUI/res/layout/notification_conversation_info.xml
@@ -34,7 +34,7 @@
android:layout_height="wrap_content"
android:gravity="center_vertical"
android:clipChildren="false"
- android:paddingTop="8dp"
+ android:paddingTop="11dp"
android:clipToPadding="true">
<ImageView
android:id="@+id/conversation_icon"
@@ -84,34 +84,21 @@
android:layout_weight="1"
style="@style/TextAppearance.NotificationImportanceChannel"/>
</LinearLayout>
- <LinearLayout
+ <TextView
+ android:id="@+id/group_name"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:gravity="start"
- android:orientation="horizontal">
- <TextView
- android:id="@+id/pkg_name"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- style="@style/TextAppearance.NotificationImportanceChannelGroup"
- android:ellipsize="end"
- android:maxLines="1"/>
- <TextView
- android:id="@+id/group_divider"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_centerVertical="true"
- style="@style/TextAppearance.NotificationImportanceHeader"
- android:layout_marginStart="2dp"
- android:layout_marginEnd="2dp"
- android:text="@*android:string/notification_header_divider_symbol" />
- <TextView
- android:id="@+id/group_name"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_weight="1"
- style="@style/TextAppearance.NotificationImportanceChannelGroup"/>
- </LinearLayout>
+ android:ellipsize="end"
+ android:textDirection="locale"
+ style="@style/TextAppearance.NotificationImportanceChannelGroup"/>
+ <TextView
+ android:id="@+id/pkg_name"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ style="@style/TextAppearance.NotificationImportanceApp"
+ android:ellipsize="end"
+ android:textDirection="locale"
+ android:maxLines="1"/>
<TextView
android:id="@+id/delegate_name"
android:layout_width="match_parent"
@@ -121,6 +108,7 @@
android:layout_marginStart="2dp"
android:layout_marginEnd="2dp"
android:ellipsize="end"
+ android:textDirection="locale"
android:text="@string/notification_delegate_header"
android:maxLines="1" />
diff --git a/packages/SystemUI/res/layout/notification_info.xml b/packages/SystemUI/res/layout/notification_info.xml
index af5a8f4d3c23..1c7c22653f9f 100644
--- a/packages/SystemUI/res/layout/notification_info.xml
+++ b/packages/SystemUI/res/layout/notification_info.xml
@@ -58,35 +58,21 @@
android:layout_height="wrap_content"
android:textDirection="locale"
style="@style/TextAppearance.NotificationImportanceChannel"/>
- <LinearLayout
+ <TextView
+ android:id="@+id/group_name"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:gravity="start"
- android:orientation="horizontal">
- <TextView
- android:id="@+id/pkg_name"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- style="@style/TextAppearance.NotificationImportanceChannelGroup"
- android:ellipsize="end"
- android:maxLines="1"/>
- <TextView
- android:id="@+id/group_divider"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_centerVertical="true"
- style="@style/TextAppearance.NotificationImportanceHeader"
- android:layout_marginStart="2dp"
- android:layout_marginEnd="2dp"
- android:text="@*android:string/notification_header_divider_symbol" />
- <TextView
- android:id="@+id/group_name"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_weight="1"
- android:textDirection="locale"
- style="@style/TextAppearance.NotificationImportanceChannelGroup"/>
- </LinearLayout>
+ android:textDirection="locale"
+ android:ellipsize="end"
+ style="@style/TextAppearance.NotificationImportanceChannelGroup"/>
+ <TextView
+ android:id="@+id/pkg_name"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ style="@style/TextAppearance.NotificationImportanceApp"
+ android:ellipsize="end"
+ android:textDirection="locale"
+ android:maxLines="1"/>
<TextView
android:id="@+id/delegate_name"
android:layout_width="match_parent"
@@ -96,6 +82,7 @@
android:layout_marginStart="2dp"
android:layout_marginEnd="2dp"
android:ellipsize="end"
+ android:textDirection="locale"
android:text="@string/notification_delegate_header"
android:maxLines="1" />
diff --git a/packages/SystemUI/res/layout/partial_conversation_info.xml b/packages/SystemUI/res/layout/partial_conversation_info.xml
index a261114fa0f2..07951705664a 100644
--- a/packages/SystemUI/res/layout/partial_conversation_info.xml
+++ b/packages/SystemUI/res/layout/partial_conversation_info.xml
@@ -35,7 +35,7 @@
android:clipChildren="false"
android:clipToPadding="false">
<ImageView
- android:id="@+id/conversation_icon"
+ android:id="@+id/icon"
android:layout_width="@dimen/notification_guts_conversation_icon_size"
android:layout_height="@dimen/notification_guts_conversation_icon_size"
android:layout_centerVertical="true"
@@ -46,66 +46,19 @@
android:layout_weight="1"
android:layout_width="0dp"
android:orientation="vertical"
-
android:layout_height="wrap_content"
android:minHeight="@dimen/notification_guts_conversation_icon_size"
android:layout_centerVertical="true"
android:gravity="center_vertical"
android:layout_alignEnd="@id/conversation_icon"
android:layout_toEndOf="@id/conversation_icon">
- <LinearLayout
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:gravity="start"
- android:orientation="horizontal">
- <TextView
- android:id="@+id/name"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- style="@style/TextAppearance.NotificationImportanceChannel"/>
- <TextView
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_centerVertical="true"
- style="@style/TextAppearance.NotificationImportanceHeader"
- android:layout_marginStart="2dp"
- android:layout_marginEnd="2dp"
- android:text="@*android:string/notification_header_divider_symbol" />
- <TextView
- android:id="@+id/parent_channel_name"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- style="@style/TextAppearance.NotificationImportanceChannel"/>
-
- </LinearLayout>
- <LinearLayout
+ <TextView
+ android:id="@+id/name"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:gravity="start"
- android:orientation="horizontal">
- <TextView
- android:id="@+id/pkg_name"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- style="@style/TextAppearance.NotificationImportanceChannelGroup"
- android:ellipsize="end"
- android:maxLines="1"/>
- <TextView
- android:id="@+id/group_divider"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_centerVertical="true"
- style="@style/TextAppearance.NotificationImportanceHeader"
- android:layout_marginStart="2dp"
- android:layout_marginEnd="2dp"
- android:text="@*android:string/notification_header_divider_symbol" />
- <TextView
- android:id="@+id/group_name"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_weight="1"
- style="@style/TextAppearance.NotificationImportanceChannelGroup"/>
- </LinearLayout>
+ android:ellipsize="end"
+ android:textDirection="locale"
+ style="@style/TextAppearance.NotificationImportanceChannel"/>
<TextView
android:id="@+id/delegate_name"
android:layout_width="match_parent"
@@ -115,6 +68,7 @@
android:layout_marginStart="2dp"
android:layout_marginEnd="2dp"
android:ellipsize="end"
+ android:textDirection="locale"
android:text="@string/notification_delegate_header"
android:maxLines="1" />
@@ -159,18 +113,21 @@
android:layout_height="wrap_content"
android:clipChildren="false"
android:clipToPadding="false"
+ android:layout_centerVertical="true"
android:orientation="horizontal">
<ImageView
- android:layout_height="wrap_content"
+ android:layout_height="match_parent"
android:layout_width="wrap_content"
android:contentDescription="@null"
android:src="@drawable/ic_info"
+ android:layout_centerVertical="true"
android:tint="?android:attr/textColorPrimary"
android:layout_marginEnd="8dp"/>
<TextView
android:id="@+id/non_configurable_text"
android:layout_width="match_parent"
android:layout_height="wrap_content"
+ android:layout_centerVertical="true"
style="@style/TextAppearance.NotificationImportanceChannelGroup" />
</LinearLayout>
</com.android.systemui.statusbar.notification.row.ButtonLinearLayout>
diff --git a/packages/SystemUI/res/layout/priority_onboarding_half_shell.xml b/packages/SystemUI/res/layout/priority_onboarding_half_shell.xml
index c27b3a9b3bf4..3f0e514a9af2 100644
--- a/packages/SystemUI/res/layout/priority_onboarding_half_shell.xml
+++ b/packages/SystemUI/res/layout/priority_onboarding_half_shell.xml
@@ -38,157 +38,117 @@
android:background="@drawable/rounded_bg_full"
>
- <!-- We have a known number of rows that can be shown; just design them all here -->
- <LinearLayout
- android:id="@+id/show_at_top_tip"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:paddingTop="8dp"
- android:paddingBottom="8dp"
- android:paddingStart="4dp"
- android:paddingEnd="4dp"
- android:orientation="horizontal"
- >
- <ImageView
- android:id="@+id/bell_icon"
- android:layout_width="24dp"
- android:layout_height="24dp"
- android:layout_gravity="center_vertical"
- android:src="@drawable/ic_notifications_alert"
- android:tint="?android:attr/colorControlNormal" />
+ <FrameLayout
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:clipChildren="false"
+ android:clipToPadding="false"
+ android:padding="12dp"
+ android:layout_gravity="center_horizontal"
+ >
- <TextView
- android:id="@+id/show_at_top_text"
+ <!-- Big icon: 52x52, 12dp padding left + top, 16dp padding right -->
+ <ImageView
+ android:id="@+id/conversation_icon"
+ android:layout_width="@*android:dimen/conversation_avatar_size"
+ android:layout_height="@*android:dimen/conversation_avatar_size"
+ android:scaleType="centerCrop"
+ android:importantForAccessibility="no"
+ />
+
+ <FrameLayout
+ android:id="@+id/conversation_icon_badge"
+ android:layout_width="@*android:dimen/conversation_icon_size_badged"
+ android:layout_height="@*android:dimen/conversation_icon_size_badged"
+ android:layout_marginLeft="@*android:dimen/conversation_badge_side_margin"
+ android:layout_marginTop="@*android:dimen/conversation_badge_side_margin"
+ android:clipChildren="false"
+ android:clipToPadding="false"
+ >
+ <ImageView
+ android:id="@+id/conversation_icon_badge_bg"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:layout_gravity="center"
+ android:src="@*android:drawable/conversation_badge_background"
+ android:forceHasOverlappingRendering="false"
+ />
+ <ImageView
+ android:id="@+id/icon"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:layout_margin="4dp"
+ android:layout_gravity="center"
+ android:forceHasOverlappingRendering="false"
+ />
+ <ImageView
+ android:id="@+id/conversation_icon_badge_ring"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:paddingStart="16dp"
- android:paddingEnd="16dp"
- android:gravity="center_vertical|start"
- android:textSize="15sp"
- android:ellipsize="end"
- android:maxLines="2"
- android:text="@string/priority_onboarding_show_at_top_text"
- style="@style/TextAppearance.NotificationInfo"
- />
-
- </LinearLayout>
-
- <LinearLayout
- android:id="@+id/show_avatar_tip"
+ android:layout_gravity="center"
+ android:src="@*android:drawable/conversation_badge_ring"
+ android:forceHasOverlappingRendering="false"
+ android:clipToPadding="false"
+ android:scaleType="center"
+ />
+ </FrameLayout>
+ </FrameLayout>
+
+ <TextView
+ android:id="@+id/title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:paddingTop="8dp"
- android:paddingBottom="8dp"
- android:paddingStart="4dp"
- android:paddingEnd="4dp"
- android:orientation="horizontal"
- >
- <ImageView
- android:id="@+id/avatar_icon"
- android:layout_width="24dp"
- android:layout_height="24dp"
- android:layout_gravity="center_vertical"
- android:src="@drawable/ic_person"
- android:tint="?android:attr/colorControlNormal" />
-
- <TextView
- android:id="@+id/avatar_text"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:paddingStart="16dp"
- android:paddingEnd="16dp"
- android:gravity="center_vertical|start"
- android:textSize="15sp"
- android:ellipsize="end"
- android:maxLines="2"
- android:text="@string/priority_onboarding_show_avatar_text"
- style="@style/TextAppearance.NotificationInfo"
- />
-
- </LinearLayout>
-
- <!-- These rows show optionally -->
+ android:gravity="center_horizontal"
+ android:layout_marginTop="16dp"
+ android:text="@string/priority_onboarding_title"
+ style="@style/TextAppearance.NotificationImportanceChannel"
+ />
+
+ <View
+ android:id="@+id/divider"
+ android:layout_width="match_parent"
+ android:layout_height="0.5dp"
+ android:layout_marginTop="20dp"
+ android:layout_marginBottom="20dp"
+ android:background="@color/material_grey_300" />
- <LinearLayout
- android:id="@+id/floating_bubble_tip"
+ <TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:paddingTop="8dp"
- android:paddingBottom="8dp"
- android:paddingStart="4dp"
- android:paddingEnd="4dp"
- android:orientation="horizontal"
- >
-
- <ImageView
- android:id="@+id/bubble_icon"
- android:layout_width="24dp"
- android:layout_height="24dp"
- android:layout_gravity="center_vertical"
- android:src="@drawable/ic_create_bubble"
- android:tint="?android:attr/colorControlNormal" />
-
- <TextView
- android:id="@+id/bubble_text"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:paddingStart="16dp"
- android:paddingEnd="16dp"
- android:gravity="center_vertical|start"
- android:textSize="15sp"
- android:ellipsize="end"
- android:maxLines="2"
- android:text="@string/priority_onboarding_appear_as_bubble_text"
- style="@style/TextAppearance.NotificationInfo"
- />
-
- </LinearLayout>
+ android:gravity="start"
+ android:text="@string/priority_onboarding_behavior"
+ style="@style/TextAppearance.NotificationImportanceChannelGroup"
+ />
- <LinearLayout
- android:id="@+id/ignore_dnd_tip"
+ <TextView
+ android:id="@+id/behaviors"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:paddingTop="8dp"
- android:paddingBottom="8dp"
- android:paddingStart="4dp"
- android:paddingEnd="4dp"
- android:orientation="horizontal"
- >
-
- <ImageView
- android:id="@+id/dnd_icon"
- android:layout_width="24dp"
- android:layout_height="24dp"
- android:layout_gravity="center_vertical"
- android:src="@drawable/moon"
- android:tint="?android:attr/colorControlNormal" />
-
- <TextView
- android:id="@+id/dnd_text"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:paddingStart="16dp"
- android:paddingEnd="16dp"
- android:gravity="center_vertical|start"
- android:textSize="15sp"
- android:ellipsize="end"
- android:maxLines="2"
- android:text="@string/priority_onboarding_ignores_dnd_text"
- style="@style/TextAppearance.NotificationInfo"
- />
-
- </LinearLayout>
+ android:gravity="start"
+ android:layout_marginTop="8dp"
+ style="@style/TextAppearance.NotificationImportanceChannelGroup"
+ />
<!-- Bottom button container -->
<RelativeLayout
android:id="@+id/button_container"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:paddingStart="4dp"
- android:paddingEnd="4dp"
+ android:layout_marginTop="32dp"
android:orientation="horizontal"
>
<TextView
+ android:id="@+id/settings_button"
+ android:text="@string/priority_onboarding_settings_button_title"
+ android:layout_width="wrap_content"
+ 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="125dp"
+ style="@style/TextAppearance.NotificationInfo.Button"/>
+ <TextView
android:id="@+id/done_button"
android:text="@string/priority_onboarding_done_button_title"
android:layout_width="wrap_content"
diff --git a/packages/SystemUI/res/layout/qs_user_detail_item.xml b/packages/SystemUI/res/layout/qs_user_detail_item.xml
index 0608685c3440..cc6c5d343502 100644
--- a/packages/SystemUI/res/layout/qs_user_detail_item.xml
+++ b/packages/SystemUI/res/layout/qs_user_detail_item.xml
@@ -30,6 +30,7 @@
android:clipToPadding="false"
android:focusable="true"
android:background="@drawable/ripple_drawable"
+ systemui:activatedTextAppearance="@style/TextAppearance.QS.UserSwitcher"
systemui:regularTextAppearance="@style/TextAppearance.QS.UserSwitcher">
<com.android.systemui.statusbar.phone.UserAvatarView
@@ -37,8 +38,6 @@
android:layout_width="@dimen/qs_framed_avatar_size"
android:layout_height="@dimen/qs_framed_avatar_size"
android:layout_marginBottom="7dp"
- android:backgroundTint="@color/qs_user_detail_avatar_tint"
- android:backgroundTintMode="src_atop"
systemui:frameWidth="6dp"
systemui:badgeDiameter="18dp"
systemui:badgeMargin="1dp"
diff --git a/packages/SystemUI/res/layout/quick_qs_status_icons.xml b/packages/SystemUI/res/layout/quick_qs_status_icons.xml
index 5b7e7e7d59a3..44f52efd175e 100644
--- a/packages/SystemUI/res/layout/quick_qs_status_icons.xml
+++ b/packages/SystemUI/res/layout/quick_qs_status_icons.xml
@@ -21,8 +21,6 @@
android:layout_height="wrap_content"
android:paddingTop="@dimen/qs_header_top_padding"
android:paddingBottom="@dimen/qs_header_bottom_padding"
- android:paddingStart="@dimen/status_bar_padding_start"
- android:paddingEnd="@dimen/status_bar_padding_end"
android:layout_below="@id/quick_status_bar_system_icons"
android:clipChildren="false"
android:clipToPadding="false"
diff --git a/packages/SystemUI/res/layout/quick_settings_brightness_dialog.xml b/packages/SystemUI/res/layout/quick_settings_brightness_dialog.xml
index 28672241b1b2..12127f529054 100644
--- a/packages/SystemUI/res/layout/quick_settings_brightness_dialog.xml
+++ b/packages/SystemUI/res/layout/quick_settings_brightness_dialog.xml
@@ -18,8 +18,6 @@
android:layout_height="wrap_content"
android:layout_width="match_parent"
android:layout_gravity="center_vertical"
- android:paddingLeft="16dp"
- android:paddingRight="16dp"
style="@style/BrightnessDialogContainer">
<com.android.systemui.settings.ToggleSliderView
diff --git a/packages/SystemUI/res/layout/quick_settings_footer.xml b/packages/SystemUI/res/layout/quick_settings_footer.xml
index 846c5386dd06..15f398aa52e6 100644
--- a/packages/SystemUI/res/layout/quick_settings_footer.xml
+++ b/packages/SystemUI/res/layout/quick_settings_footer.xml
@@ -23,7 +23,7 @@
android:paddingStart="@dimen/qs_footer_padding_start"
android:paddingEnd="@dimen/qs_footer_padding_end"
android:gravity="center_vertical"
- android:background="?android:attr/colorPrimary" >
+ android:background="@android:color/transparent">
<TextView
android:id="@+id/footer_text"
@@ -32,7 +32,7 @@
android:gravity="start"
android:layout_weight="1"
android:textAppearance="@style/TextAppearance.QS.TileLabel"
- android:textColor="?android:attr/textColorSecondary"/>
+ style="@style/qs_security_footer"/>
<ImageView
android:id="@+id/footer_icon"
@@ -40,6 +40,6 @@
android:layout_height="@dimen/qs_footer_icon_size"
android:contentDescription="@null"
android:src="@drawable/ic_info_outline"
- android:tint="?android:attr/textColorSecondary"/>
+ style="@style/qs_security_footer"/>
</LinearLayout>
diff --git a/packages/SystemUI/res/layout/quick_settings_header_info.xml b/packages/SystemUI/res/layout/quick_settings_header_info.xml
index 683e86728e91..e6ef9b4b902c 100644
--- a/packages/SystemUI/res/layout/quick_settings_header_info.xml
+++ b/packages/SystemUI/res/layout/quick_settings_header_info.xml
@@ -19,8 +19,6 @@
android:layout_width="match_parent"
android:layout_height="@dimen/qs_header_tooltip_height"
android:layout_below="@id/quick_status_bar_system_icons"
- android:paddingStart="@dimen/status_bar_padding_start"
- android:paddingEnd="@dimen/status_bar_padding_end"
android:visibility="invisible"
android:theme="@style/QSHeaderTheme">
diff --git a/packages/SystemUI/res/layout/quick_status_bar_expanded_header.xml b/packages/SystemUI/res/layout/quick_status_bar_expanded_header.xml
index 9a7c344baf20..abeb33111c40 100644
--- a/packages/SystemUI/res/layout/quick_status_bar_expanded_header.xml
+++ b/packages/SystemUI/res/layout/quick_status_bar_expanded_header.xml
@@ -33,6 +33,7 @@
android:paddingStart="0dp"
android:elevation="4dp" >
+ <!-- The clock -->
<include layout="@layout/quick_status_bar_header_system_icons" />
<!-- Status icons within the panel itself (and not in the top-most status bar) -->
diff --git a/packages/SystemUI/res/layout/quick_status_bar_header_system_icons.xml b/packages/SystemUI/res/layout/quick_status_bar_header_system_icons.xml
index b27d096c12b5..be86e5f5abc5 100644
--- a/packages/SystemUI/res/layout/quick_status_bar_header_system_icons.xml
+++ b/packages/SystemUI/res/layout/quick_status_bar_header_system_icons.xml
@@ -25,8 +25,6 @@
android:gravity="center"
android:orientation="horizontal"
android:clickable="true"
- android:paddingStart="@dimen/status_bar_padding_start"
- android:paddingEnd="@dimen/status_bar_padding_end"
android:paddingTop="@dimen/status_bar_padding_top" >
<com.android.systemui.statusbar.policy.Clock
diff --git a/packages/SystemUI/res/layout/screen_record_dialog_audio_source.xml b/packages/SystemUI/res/layout/screen_record_dialog_audio_source.xml
index af6f9bb827f6..0c4d5a26f95b 100644
--- a/packages/SystemUI/res/layout/screen_record_dialog_audio_source.xml
+++ b/packages/SystemUI/res/layout/screen_record_dialog_audio_source.xml
@@ -16,21 +16,20 @@
-->
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="match_parent"
+ android:layout_width="250dp"
android:layout_height="48dp"
android:orientation="vertical"
- android:padding="10dp"
- android:layout_weight="1">
+ android:padding="13dp">
<TextView
android:id="@+id/screen_recording_dialog_source_text"
- android:layout_width="match_parent"
+ android:layout_width="250dp"
android:layout_height="match_parent"
android:layout_gravity="center_vertical"
android:textAppearance="?android:attr/textAppearanceSmall"
android:textColor="?android:attr/textColorPrimary"/>
<TextView
android:id="@+id/screen_recording_dialog_source_description"
- android:layout_width="wrap_content"
+ android:layout_width="250dp"
android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceSmall"
android:textColor="?android:attr/textColorSecondary"/>
diff --git a/packages/SystemUI/res/values-af/strings.xml b/packages/SystemUI/res/values-af/strings.xml
index cc1f7a3afead..88102b2adc94 100644
--- a/packages/SystemUI/res/values-af/strings.xml
+++ b/packages/SystemUI/res/values-af/strings.xml
@@ -77,9 +77,6 @@
<string name="compat_mode_on" msgid="4963711187149440884">"Zoem om skerm te vul"</string>
<string name="compat_mode_off" msgid="7682459748279487945">"Strek om skerm te vul"</string>
<string name="global_action_screenshot" msgid="2760267567509131654">"Skermkiekie"</string>
- <string name="global_action_lock_message" product="default" msgid="4466026255205186456">"Ontsluit jou foon vir meer opsies"</string>
- <string name="global_action_lock_message" product="tablet" msgid="7621167597240332986">"Ontsluit jou tablet vir meer opsies"</string>
- <string name="global_action_lock_message" product="device" msgid="538790401275363781">"Ontsluit jou toestel vir meer opsies"</string>
<string name="remote_input_image_insertion_text" msgid="4850791636452521123">"het \'n prent gestuur"</string>
<string name="screenshot_saving_ticker" msgid="6519186952674544916">"Stoor tans skermkiekie..."</string>
<string name="screenshot_saving_title" msgid="2298349784913287333">"Stoor tans skermkiekie..."</string>
@@ -722,7 +719,7 @@
<string name="notification_channel_summary_priority" msgid="7952654515769021553">"Wys boaan die gespreksafdeling, verskyn as \'n swewende borrel, wys profielfoto op sluitskerm"</string>
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"Instellings"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"Prioriteit"</string>
- <string name="no_shortcut" msgid="7176375126961212514">"<xliff:g id="APP_NAME">%1$s</xliff:g> steun nie gesprekspesifieke-instellings nie"</string>
+ <string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> steun nie gesprekskenmerke nie"</string>
<string name="bubble_overflow_empty_title" msgid="3120029421991510842">"Geen onlangse borrels nie"</string>
<string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"Onlangse borrels en borrels wat toegemaak is, sal hier verskyn"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"Hierdie kennisgewings kan nie gewysig word nie."</string>
@@ -1005,7 +1002,8 @@
<string name="bubble_accessibility_action_move_top_right" msgid="6916868852433483569">"Beweeg na regs bo"</string>
<string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"Beweeg na links onder"</string>
<string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"Beweeg na regs onder"</string>
- <string name="bubble_dismiss_text" msgid="7071770411580452911">"Maak toe"</string>
+ <!-- no translation found for bubble_dismiss_text (1314082410868930066) -->
+ <skip />
<string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"Moenie dat gesprek \'n borrel word nie"</string>
<string name="bubbles_user_education_title" msgid="5547017089271445797">"Klets met borrels"</string>
<string name="bubbles_user_education_description" msgid="1160281719576715211">"Nuwe gesprekke verskyn as swerwende ikone, of borrels Tik op borrel om dit oop te maak. Sleep om dit te skuif."</string>
@@ -1016,11 +1014,14 @@
<string name="notification_content_system_nav_changed" msgid="5077913144844684544">"Stelselnavigasie is opgedateer. Gaan na Instellings toe om veranderinge te maak."</string>
<string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"Gaan na Instellings toe om stelselnavigasie op te dateer"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Bystandmodus"</string>
+ <string name="priority_onboarding_title" msgid="2893070698479227616">"Gesprek is op prioriteit gestel"</string>
+ <string name="priority_onboarding_behavior" msgid="5342816047020432929">"Prioriteitgesprekke sal:"</string>
<string name="priority_onboarding_show_at_top_text" msgid="1678400241025513541">"Wys boaan gespreksafdeling"</string>
<string name="priority_onboarding_show_avatar_text" msgid="5756291381124091508">"Wys profielprent op slotskerm"</string>
<string name="priority_onboarding_appear_as_bubble_text" msgid="4227039772250263122">"Verskyn as \'n swewende borrel bo-oor programme"</string>
<string name="priority_onboarding_ignores_dnd_text" msgid="2918952762719600529">"Onderbreek Moenie Steur Nie"</string>
<string name="priority_onboarding_done_button_title" msgid="4569550984286506007">"Het dit"</string>
+ <string name="priority_onboarding_settings_button_title" msgid="6663601574303585927">"Instellings"</string>
<string name="magnification_overlay_title" msgid="6584179429612427958">"Vergrotingoorleggervenster"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"Vergrotingvenster"</string>
<string name="magnification_controls_title" msgid="8421106606708891519">"Vergrotingvensterkontroles"</string>
@@ -1062,9 +1063,13 @@
<string name="controls_structure_tooltip" msgid="4355922222944447867">"Swiep om meer te sien"</string>
<string name="controls_seeding_in_progress" msgid="3033855341410264148">"Laai tans aanbevelings"</string>
<string name="controls_media_close_session" msgid="9023534788828414585">"Maak hierdie mediasessie toe"</string>
+ <string name="controls_media_resume" msgid="1933520684481586053">"Hervat"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"Onaktief, gaan program na"</string>
<string name="controls_error_retryable" msgid="864025882878378470">"Fout, probeer tans weer …"</string>
- <string name="controls_error_removed" msgid="6299213591234723805">"Toestel is verwyder"</string>
+ <string name="controls_error_removed" msgid="6675638069846014366">"Nie gekry nie"</string>
+ <string name="controls_error_removed_title" msgid="1207794911208047818">"Kontrole is nie beskikbaar nie"</string>
+ <string name="controls_error_removed_message" msgid="2885911717034750542">"Kon nie by <xliff:g id="DEVICE">%1$s</xliff:g> ingaan nie. Gaan die <xliff:g id="APPLICATION">%2$s</xliff:g>-program na om seker te maak dat die kontrole steeds beskikbaar is en dat die programinstellings nie verander het nie."</string>
+ <string name="controls_open_app" msgid="483650971094300141">"Maak program oop"</string>
<string name="controls_error_generic" msgid="352500456918362905">"Kan nie status laai nie"</string>
<string name="controls_error_failed" msgid="960228639198558525">"Fout, probeer weer"</string>
<string name="controls_in_progress" msgid="4421080500238215939">"Besig"</string>
diff --git a/packages/SystemUI/res/values-am/strings.xml b/packages/SystemUI/res/values-am/strings.xml
index dff3e810ecbc..66c0131d6671 100644
--- a/packages/SystemUI/res/values-am/strings.xml
+++ b/packages/SystemUI/res/values-am/strings.xml
@@ -77,9 +77,6 @@
<string name="compat_mode_on" msgid="4963711187149440884">"ማያ እንዲሞላ አጉላ"</string>
<string name="compat_mode_off" msgid="7682459748279487945">"ማያ ለመሙለት ሳብ"</string>
<string name="global_action_screenshot" msgid="2760267567509131654">"ቅጽበታዊ ገጽ እይታ"</string>
- <string name="global_action_lock_message" product="default" msgid="4466026255205186456">"ለተጨማሪ አማራጮች የእርስዎን ስልክ ይክፈቱ"</string>
- <string name="global_action_lock_message" product="tablet" msgid="7621167597240332986">"ለተጨማሪ አማራጮች የእርስዎን ጡባዊ ይክፈቱ"</string>
- <string name="global_action_lock_message" product="device" msgid="538790401275363781">"ለተጨማሪ አማራጮች የእርስዎን መሣሪያ ይክፈቱ"</string>
<string name="remote_input_image_insertion_text" msgid="4850791636452521123">"ምስል ተልኳል"</string>
<string name="screenshot_saving_ticker" msgid="6519186952674544916">"ቅጽበታዊ ገጽ እይታ በማስቀመጥ ላይ..."</string>
<string name="screenshot_saving_title" msgid="2298349784913287333">"ቅጽበታዊ ገጽ እይታ በማስቀመጥ ላይ..."</string>
@@ -722,7 +719,7 @@
<string name="notification_channel_summary_priority" msgid="7952654515769021553">"በውይይት ክፍል አናት ላይ ያሳያል፣ እንደ ተንሳፋፊ አረፋ ብቅ ይላል፣ በቆልፍ ማያ ገጽ ላይ የመገለጫ ሥዕልን ያሳያል"</string>
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"ቅንብሮች"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"ቅድሚያ"</string>
- <string name="no_shortcut" msgid="7176375126961212514">"<xliff:g id="APP_NAME">%1$s</xliff:g> ውይይት-ተኮር ቅንብሮችን አይደግፍም"</string>
+ <string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> የውይይት ባህሪያትን አይደግፍም"</string>
<string name="bubble_overflow_empty_title" msgid="3120029421991510842">"ምንም የቅርብ ጊዜ አረፋዎች የሉም"</string>
<string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"የቅርብ ጊዜ አረፋዎች እና የተሰናበቱ አረፋዎች እዚህ ብቅ ይላሉ"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"እነዚህ ማሳወቂያዎች ሊሻሻሉ አይችሉም።"</string>
@@ -1005,7 +1002,8 @@
<string name="bubble_accessibility_action_move_top_right" msgid="6916868852433483569">"ወደ ላይኛው ቀኝ አንቀሳቅስ"</string>
<string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"የግርጌውን ግራ አንቀሳቅስ"</string>
<string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"ታችኛውን ቀኝ ያንቀሳቅሱ"</string>
- <string name="bubble_dismiss_text" msgid="7071770411580452911">"አሰናብት"</string>
+ <!-- no translation found for bubble_dismiss_text (1314082410868930066) -->
+ <skip />
<string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"ውይይቶችን በአረፋ አታሳይ"</string>
<string name="bubbles_user_education_title" msgid="5547017089271445797">"አረፋዎችን በመጠቀም ይወያዩ"</string>
<string name="bubbles_user_education_description" msgid="1160281719576715211">"አዲስ ውይይቶች እንደ ተንሳፋፊ አዶዎች ወይም አረፋዎች ሆነው ይታያሉ። አረፋን ለመክፈት መታ ያድርጉ። ለመውሰድ ይጎትቱት።"</string>
@@ -1016,11 +1014,14 @@
<string name="notification_content_system_nav_changed" msgid="5077913144844684544">"የስርዓት ዳሰሳ ተዘምኗል። ለውጦችን ለማድረግ ወደ ቅንብሮች ይሂዱ።"</string>
<string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"የስርዓት ዳሰሳን ለማዘመን ወደ ቅንብሮች ይሂዱ"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"ተጠባባቂ"</string>
+ <string name="priority_onboarding_title" msgid="2893070698479227616">"ልወጣ ወደ ቅድሚያ ተቀናብሯል"</string>
+ <string name="priority_onboarding_behavior" msgid="5342816047020432929">"ቅድሚያ የሚሰጣቸው ልወጣዎች እነዚህን ያደርጋሉ፦"</string>
<string name="priority_onboarding_show_at_top_text" msgid="1678400241025513541">"በውይይት ክፍል አናት ላይ አአሳይ"</string>
<string name="priority_onboarding_show_avatar_text" msgid="5756291381124091508">"የመገለጫ ስዕልን በማያ ገጽ ቁልፍ ላይ አሳይ"</string>
<string name="priority_onboarding_appear_as_bubble_text" msgid="4227039772250263122">"በመተግበሪያዎች ላይ እንደ ተንሳፋፊ አረፋ ሆኖ ይታያሉ"</string>
<string name="priority_onboarding_ignores_dnd_text" msgid="2918952762719600529">"አትረብሽን አቋርጥ"</string>
<string name="priority_onboarding_done_button_title" msgid="4569550984286506007">"ገባኝ"</string>
+ <string name="priority_onboarding_settings_button_title" msgid="6663601574303585927">"ቅንብሮች"</string>
<string name="magnification_overlay_title" msgid="6584179429612427958">"የማጉያ ንብርብር መስኮት"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"የማጉያ መስኮት"</string>
<string name="magnification_controls_title" msgid="8421106606708891519">"የማጉያ መስኮት መቆጣጠሪያዎች"</string>
@@ -1062,9 +1063,13 @@
<string name="controls_structure_tooltip" msgid="4355922222944447867">"ተጨማሪ ለማየት ያንሸራትቱ"</string>
<string name="controls_seeding_in_progress" msgid="3033855341410264148">"ምክሮችን በመጫን ላይ"</string>
<string name="controls_media_close_session" msgid="9023534788828414585">"ይህን የሚዲያ ክፍለ-ጊዜ ዝጋ"</string>
+ <string name="controls_media_resume" msgid="1933520684481586053">"ከቆመበት ቀጥል"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"ንቁ ያልኾነ፣ መተግበሪያን ይፈትሹ"</string>
<string name="controls_error_retryable" msgid="864025882878378470">"ስህተት፣ እንደገና በመሞከር ላይ…"</string>
- <string name="controls_error_removed" msgid="6299213591234723805">"መሣሪያ ተወግዷል"</string>
+ <string name="controls_error_removed" msgid="6675638069846014366">"አልተገኘም"</string>
+ <string name="controls_error_removed_title" msgid="1207794911208047818">"መቆጣጠሪያ አይገኝም"</string>
+ <string name="controls_error_removed_message" msgid="2885911717034750542">"<xliff:g id="DEVICE">%1$s</xliff:g>ን መድረስ አልተቻለም። አሁንም ድረስ መቆጣጠሪያው ሊገኝ እንደሚችል እና የመተግበሪያ ቅንብሮቹ እንዳልተለወጡ ለማረጋገጥ <xliff:g id="APPLICATION">%2$s</xliff:g> መተግበሪያን ይፈትሹ።"</string>
+ <string name="controls_open_app" msgid="483650971094300141">"መተግበሪያ ክፈት"</string>
<string name="controls_error_generic" msgid="352500456918362905">"ሁኔታን መጫን አልተቻልም"</string>
<string name="controls_error_failed" msgid="960228639198558525">"ስህተት፣ እንደገና ይሞክሩ"</string>
<string name="controls_in_progress" msgid="4421080500238215939">"በሂደት ላይ"</string>
diff --git a/packages/SystemUI/res/values-ar/strings.xml b/packages/SystemUI/res/values-ar/strings.xml
index 084081c4748c..ebf4bc80b689 100644
--- a/packages/SystemUI/res/values-ar/strings.xml
+++ b/packages/SystemUI/res/values-ar/strings.xml
@@ -77,9 +77,6 @@
<string name="compat_mode_on" msgid="4963711187149440884">"تكبير/تصغير لملء الشاشة"</string>
<string name="compat_mode_off" msgid="7682459748279487945">"توسيع بملء الشاشة"</string>
<string name="global_action_screenshot" msgid="2760267567509131654">"لقطة شاشة"</string>
- <string name="global_action_lock_message" product="default" msgid="4466026255205186456">"يمكنك فتح قفل هاتفك للوصول إلى مزيد من الخيارات."</string>
- <string name="global_action_lock_message" product="tablet" msgid="7621167597240332986">"يمكنك فتح قفل جهازك اللوحي للوصول إلى مزيد من الخيارات."</string>
- <string name="global_action_lock_message" product="device" msgid="538790401275363781">"يمكنك فتح قفل جهازك للوصول إلى مزيد من الخيارات."</string>
<string name="remote_input_image_insertion_text" msgid="4850791636452521123">"أرسَل صورة"</string>
<string name="screenshot_saving_ticker" msgid="6519186952674544916">"جارٍ حفظ لقطة الشاشة..."</string>
<string name="screenshot_saving_title" msgid="2298349784913287333">"جارٍ حفظ لقطة الشاشة..."</string>
@@ -607,29 +604,21 @@
<string name="volume_odi_captions_hint_enable" msgid="2073091194012843195">"تفعيل"</string>
<string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"إيقاف"</string>
<string name="accessibility_output_chooser" msgid="7807898688967194183">"تبديل جهاز الاستماع"</string>
- <!-- no translation found for screen_pinning_title (9058007390337841305) -->
- <skip />
+ <string name="screen_pinning_title" msgid="9058007390337841305">"تم تثبيت الشاشة على التطبيق"</string>
<string name="screen_pinning_description" msgid="8699395373875667743">"يؤدي هذا إلى استمرار عرض الشاشة المُختارة إلى أن تتم إزالة تثبيتها. المس مع الاستمرار الزرين \"رجوع\" و\"نظرة عامة\" لإزالة التثبيت."</string>
<string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"يؤدي هذا إلى استمرار عرض الشاشة المُختارة إلى أن تتم إزالة تثبيتها. المس مع الاستمرار الزرين \"رجوع\" و\"الشاشة الرئيسية\" لإزالة التثبيت."</string>
<string name="screen_pinning_description_gestural" msgid="7246323931831232068">"يؤدي هذا إلى استمرار عرض الشاشة المُختارة إلى أن تتم إزالة تثبيتها. مرّر الشاشة بسرعة للأعلى مع الاستمرار لإزالة تثبيت الشاشة."</string>
<string name="screen_pinning_description_accessible" msgid="7386449191953535332">"يؤدي هذا إلى استمرار عرض الشاشة المُختارة إلى أن تتم إزالة تثبيتها. المس مع الاستمرار زر \"نظرة عامة\" لإزالة التثبيت."</string>
<string name="screen_pinning_description_recents_invisible_accessible" msgid="2857071808674481986">"يؤدي هذا إلى استمرار عرض الشاشة المُختارة إلى أن تتم إزالة تثبيتها. المس مع الاستمرار زر \"الشاشة الرئيسية\" لإزالة التثبيت."</string>
- <!-- no translation found for screen_pinning_exposes_personal_data (8189852022981524789) -->
- <skip />
- <!-- no translation found for screen_pinning_can_open_other_apps (7529756813231421455) -->
- <skip />
- <!-- no translation found for screen_pinning_toast (8177286912533744328) -->
- <skip />
- <!-- no translation found for screen_pinning_toast_recents_invisible (6850978077443052594) -->
- <skip />
- <!-- no translation found for screen_pinning_toast_gesture_nav (170699893395336705) -->
- <skip />
+ <string name="screen_pinning_exposes_personal_data" msgid="8189852022981524789">"يمكن الوصول إلى البيانات الشخصية (مثلاً جهات الاتصال ومحتوى الرسائل الإلكترونية)"</string>
+ <string name="screen_pinning_can_open_other_apps" msgid="7529756813231421455">"عند تثبيت الشاشة على تطبيق معيّن، سيظل بإمكان التطبيق فتح تطبيقات أخرى."</string>
+ <string name="screen_pinning_toast" msgid="8177286912533744328">"لإلغاء تثبيت الشاشة على هذا التطبيق، المس مع الاستمرار زرّي \"الرجوع\" و\"لمحة عامة\" (رمز المربّع)."</string>
+ <string name="screen_pinning_toast_recents_invisible" msgid="6850978077443052594">"لإلغاء تثبيت الشاشة على هذا التطبيق، المس مع الاستمرار زرّي \"الرجوع\" و\"الشاشة الرئيسية\"."</string>
+ <string name="screen_pinning_toast_gesture_nav" msgid="170699893395336705">"لإلغاء تثبيت الشاشة على هذا التطبيق، اسحب بسرعة للأعلى مع إبقاء الإصبع على الشاشة."</string>
<string name="screen_pinning_positive" msgid="3285785989665266984">"حسنًا"</string>
<string name="screen_pinning_negative" msgid="6882816864569211666">"لا، شكرًا"</string>
- <!-- no translation found for screen_pinning_start (7483998671383371313) -->
- <skip />
- <!-- no translation found for screen_pinning_exit (4553787518387346893) -->
- <skip />
+ <string name="screen_pinning_start" msgid="7483998671383371313">"تم تثبيت الشاشة على التطبيق."</string>
+ <string name="screen_pinning_exit" msgid="4553787518387346893">"تم إلغاء تثبيت الشاشة"</string>
<string name="quick_settings_reset_confirmation_title" msgid="463533331480997595">"هل تريد إخفاء <xliff:g id="TILE_LABEL">%1$s</xliff:g>؟"</string>
<string name="quick_settings_reset_confirmation_message" msgid="2320586180785674186">"سيظهر مرة أخرى عند تمكينه في الإعدادات المرة التالية."</string>
<string name="quick_settings_reset_confirmation_button" msgid="3341477479055016776">"إخفاء"</string>
@@ -736,13 +725,13 @@
<string name="notification_bubble_title" msgid="8330481035191903164">"فقاعة"</string>
<string name="notification_channel_summary_low" msgid="4860617986908931158">"بدون صوت أو اهتزاز"</string>
<string name="notification_conversation_summary_low" msgid="1734433426085468009">"بدون صوت أو اهتزاز وتظهر في موضع أسفل في قسم المحادثات"</string>
- <string name="notification_channel_summary_default" msgid="3282930979307248890">"يمكن الرن أو الاهتزاز بناءً على إعدادات الهاتف"</string>
- <string name="notification_channel_summary_default_with_bubbles" msgid="1782419896613644568">"يمكن الرن أو الاهتزاز بناءً على إعدادات الهاتف. تظهر المحادثات من <xliff:g id="APP_NAME">%1$s</xliff:g> كفقاعات تلقائيًا."</string>
+ <string name="notification_channel_summary_default" msgid="3282930979307248890">"يمكن إصدار رنين أو اهتزاز بناءً على إعدادات الهاتف"</string>
+ <string name="notification_channel_summary_default_with_bubbles" msgid="1782419896613644568">"يمكن إصدار رنين أو اهتزاز بناءً على إعدادات الهاتف. تظهر المحادثات من <xliff:g id="APP_NAME">%1$s</xliff:g> كفقاعات تلقائيًا."</string>
<string name="notification_channel_summary_bubble" msgid="7235935211580860537">"يلفِت هذا الإشعار انتباهك لهذا المحتوى باستخدام اختصار عائم."</string>
<string name="notification_channel_summary_priority" msgid="7952654515769021553">"تظهر في أعلى قسم المحادثات وتظهر كفقاعة عائمة وتعرض صورة الملف الشخصي على شاشة القفل"</string>
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"الإعدادات"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"الأولوية"</string>
- <string name="no_shortcut" msgid="7176375126961212514">"لا يدعم تطبيق <xliff:g id="APP_NAME">%1$s</xliff:g> الإعدادات الخاصة بالمحادثة."</string>
+ <string name="no_shortcut" msgid="8257177117568230126">"لا يدعم تطبيق <xliff:g id="APP_NAME">%1$s</xliff:g> ميزات المحادثات."</string>
<string name="bubble_overflow_empty_title" msgid="3120029421991510842">"ليس هناك فقاعات محادثات"</string>
<string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"ستظهر هنا أحدث فقاعات المحادثات وفقاعات المحادثات التي تم إغلاقها."</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"يتعذّر تعديل هذه الإشعارات."</string>
@@ -1033,7 +1022,8 @@
<string name="bubble_accessibility_action_move_top_right" msgid="6916868852433483569">"الانتقال إلى أعلى اليسار"</string>
<string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"نقل إلى أسفل يمين الشاشة"</string>
<string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"نقل إلى أسفل اليسار"</string>
- <string name="bubble_dismiss_text" msgid="7071770411580452911">"تجاهل"</string>
+ <!-- no translation found for bubble_dismiss_text (1314082410868930066) -->
+ <skip />
<string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"عدم عرض المحادثة كفقاعة محادثة"</string>
<string name="bubbles_user_education_title" msgid="5547017089271445797">"الدردشة باستخدام فقاعات المحادثات"</string>
<string name="bubbles_user_education_description" msgid="1160281719576715211">"تظهر المحادثات الجديدة كرموز عائمة أو كفقاعات. انقر لفتح فقاعة المحادثة، واسحبها لتحريكها."</string>
@@ -1044,11 +1034,14 @@
<string name="notification_content_system_nav_changed" msgid="5077913144844684544">"تم تحديث التنقل داخل النظام. لإجراء التغييرات، يُرجى الانتقال إلى \"الإعدادات\"."</string>
<string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"الانتقال إلى \"الإعدادات\" لتعديل التنقل داخل النظام"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"وضع الاستعداد"</string>
+ <string name="priority_onboarding_title" msgid="2893070698479227616">"تم ضبط المحادثة على أنها ذات أولوية"</string>
+ <string name="priority_onboarding_behavior" msgid="5342816047020432929">"المحادثات ذات الأولوية:"</string>
<string name="priority_onboarding_show_at_top_text" msgid="1678400241025513541">"تظهر في أعلى قسم المحادثات"</string>
<string name="priority_onboarding_show_avatar_text" msgid="5756291381124091508">"تظهر صورة الملف الشخصي على شاشة القفل"</string>
<string name="priority_onboarding_appear_as_bubble_text" msgid="4227039772250263122">"تظهر كفقاعة عائمة فوق التطبيقات"</string>
<string name="priority_onboarding_ignores_dnd_text" msgid="2918952762719600529">"لا تتقيّد بميزة \"عدم الإزعاج\""</string>
<string name="priority_onboarding_done_button_title" msgid="4569550984286506007">"حسنًا"</string>
+ <string name="priority_onboarding_settings_button_title" msgid="6663601574303585927">"الإعدادات"</string>
<string name="magnification_overlay_title" msgid="6584179429612427958">"نافذة تراكب التكبير"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"نافذة التكبير"</string>
<string name="magnification_controls_title" msgid="8421106606708891519">"عناصر التحكم في نافذة التكبير"</string>
@@ -1094,9 +1087,13 @@
<string name="controls_structure_tooltip" msgid="4355922222944447867">"مرّر سريعًا لرؤية المزيد."</string>
<string name="controls_seeding_in_progress" msgid="3033855341410264148">"جارٍ تحميل الاقتراحات"</string>
<string name="controls_media_close_session" msgid="9023534788828414585">"إغلاق جلسة تشغيل الوسائط هذه"</string>
+ <string name="controls_media_resume" msgid="1933520684481586053">"استئناف التشغيل"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"غير نشط، تحقّق من التطبيق."</string>
<string name="controls_error_retryable" msgid="864025882878378470">"حدث خطأ، جارٍ إعادة المحاولة…"</string>
- <string name="controls_error_removed" msgid="6299213591234723805">"تمت إزالة الجهاز."</string>
+ <string name="controls_error_removed" msgid="6675638069846014366">"لم يتم العثور عليه."</string>
+ <string name="controls_error_removed_title" msgid="1207794911208047818">"عنصر التحكّم غير متوفّر"</string>
+ <string name="controls_error_removed_message" msgid="2885911717034750542">"تعذّر الوصول إلى <xliff:g id="DEVICE">%1$s</xliff:g>. تحقّق من تطبيق <xliff:g id="APPLICATION">%2$s</xliff:g> للتأكّد من أن عنصر التحكّم لا يزال متوفّرًا وأنه لم يتم تغيير إعدادات التطبيق."</string>
+ <string name="controls_open_app" msgid="483650971094300141">"فتح التطبيق"</string>
<string name="controls_error_generic" msgid="352500456918362905">"يتعذّر تحميل الحالة."</string>
<string name="controls_error_failed" msgid="960228639198558525">"حدث خطأ، يُرجى إعادة المحاولة."</string>
<string name="controls_in_progress" msgid="4421080500238215939">"قيد التقدم"</string>
diff --git a/packages/SystemUI/res/values-as/strings.xml b/packages/SystemUI/res/values-as/strings.xml
index 697d3753f4dd..c3d1e78f74e5 100644
--- a/packages/SystemUI/res/values-as/strings.xml
+++ b/packages/SystemUI/res/values-as/strings.xml
@@ -77,9 +77,6 @@
<string name="compat_mode_on" msgid="4963711187149440884">"স্ক্ৰীণ পূর্ণ কৰিবলৈ জুম কৰক"</string>
<string name="compat_mode_off" msgid="7682459748279487945">"স্ক্ৰীণ পূর্ণ কৰিবলৈ প্ৰসাৰিত কৰক"</string>
<string name="global_action_screenshot" msgid="2760267567509131654">"স্ক্ৰীনশ্বট"</string>
- <string name="global_action_lock_message" product="default" msgid="4466026255205186456">"অধিক বিকল্পৰ বাবে আপোনাৰ ফ’নটো আনলক কৰক"</string>
- <string name="global_action_lock_message" product="tablet" msgid="7621167597240332986">"অধিক বিকল্পৰ বাবে আপোনাৰ টেবলেটটো আনলক কৰক"</string>
- <string name="global_action_lock_message" product="device" msgid="538790401275363781">"অধিক বিকল্পৰ বাবে আপোনাৰ ডিভাইচটো আনলক কৰক"</string>
<string name="remote_input_image_insertion_text" msgid="4850791636452521123">"এখন প্ৰতিচ্ছবি পঠিয়াইছে"</string>
<string name="screenshot_saving_ticker" msgid="6519186952674544916">"স্ক্ৰীণশ্বট ছেভ কৰি থকা হৈছে…"</string>
<string name="screenshot_saving_title" msgid="2298349784913287333">"স্ক্ৰীণশ্বট ছেভ কৰি থকা হৈছে…"</string>
@@ -595,29 +592,21 @@
<string name="volume_odi_captions_hint_enable" msgid="2073091194012843195">"সক্ষম কৰক"</string>
<string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"অক্ষম কৰক"</string>
<string name="accessibility_output_chooser" msgid="7807898688967194183">"আউটপুট ডিভাইচ সলনি কৰক"</string>
- <!-- no translation found for screen_pinning_title (9058007390337841305) -->
- <skip />
+ <string name="screen_pinning_title" msgid="9058007390337841305">"এপ্‌টো পিন কৰা আছে"</string>
<string name="screen_pinning_description" msgid="8699395373875667743">"এই কাৰ্যই আপুনি আনপিন নকৰালৈকে ইয়াক দেখা পোৱা অৱস্থাত ৰাখে। আনপিন কৰিবলৈ \'পিছলৈ যাওক\' আৰু \'অৱলোকন\'-ত স্পৰ্শ কৰি থাকক।"</string>
<string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"এই কাৰ্যই আপুনি আনপিন নকৰালৈকে ইয়াক দেখা পোৱা অৱস্থাত ৰাখে। আনপিন কৰিবলৈ পিছলৈ যাওক আৰু হ\'মত স্পৰ্শ কৰি সেঁচি ধৰক।"</string>
<string name="screen_pinning_description_gestural" msgid="7246323931831232068">"এই কাৰ্যই আপুনি আনপিন নকৰালৈকে ইয়াক দেখা পোৱা অৱস্থাত ৰাখে। আনপিন কৰিবলৈ ওপৰলৈ ছোৱাইপ কৰি ধৰি ৰাখক।"</string>
<string name="screen_pinning_description_accessible" msgid="7386449191953535332">"এই কাৰ্যই আপুনি আনপিন নকৰালৈকে ইয়াক দেখা পোৱা অৱস্থাত ৰাখে। আনপিন কৰিবলৈ \'অৱলোকন\'-ত স্পৰ্শ কৰি থাকক।"</string>
<string name="screen_pinning_description_recents_invisible_accessible" msgid="2857071808674481986">"এই কাৰ্যই আপুনি আনপিন নকৰালৈকে ইয়াক দেখা পোৱা অৱস্থাত ৰাখে। আনপিন কৰিবলৈ পিছলৈ যাওক আৰু হ\'মত স্পৰ্শ কৰি সেঁচি ধৰক।"</string>
- <!-- no translation found for screen_pinning_exposes_personal_data (8189852022981524789) -->
- <skip />
- <!-- no translation found for screen_pinning_can_open_other_apps (7529756813231421455) -->
- <skip />
- <!-- no translation found for screen_pinning_toast (8177286912533744328) -->
- <skip />
- <!-- no translation found for screen_pinning_toast_recents_invisible (6850978077443052594) -->
- <skip />
- <!-- no translation found for screen_pinning_toast_gesture_nav (170699893395336705) -->
- <skip />
+ <string name="screen_pinning_exposes_personal_data" msgid="8189852022981524789">"ব্যক্তিগত ডেটা এক্সেছ কৰিব পৰা যাব পাৰে (যেনে সম্পর্কসমূহ আৰু ইমেইলৰ সমল)।"</string>
+ <string name="screen_pinning_can_open_other_apps" msgid="7529756813231421455">"পিন কৰি ৰখা এপ্‌টোৱে হয়তো অন্য এপ্‌সমূহ খুলিব পাৰে।"</string>
+ <string name="screen_pinning_toast" msgid="8177286912533744328">"এই এপ্‌টো আনপিন কৰিবলৈ, উভতি যাওক আৰু ৰূপৰেখাৰ বুটামসমূহ স্পৰ্শ কৰি ধৰি ৰাখক"</string>
+ <string name="screen_pinning_toast_recents_invisible" msgid="6850978077443052594">"এই এপ্‌টো আনপিন কৰিবলৈ, উভতি যাওক আৰু গৃহপৃষ্ঠাৰ বুটামসমূহ স্পৰ্শ কৰি ধৰি ৰাখক"</string>
+ <string name="screen_pinning_toast_gesture_nav" msgid="170699893395336705">"এই এপ্‌টো আনপিন কৰিবলৈ, ওপৰলৈ ছোৱাইপ কৰক আৰু ধৰি ৰাখক"</string>
<string name="screen_pinning_positive" msgid="3285785989665266984">"বুজি পালোঁ"</string>
<string name="screen_pinning_negative" msgid="6882816864569211666">"নালাগে, ধন্যবাদ"</string>
- <!-- no translation found for screen_pinning_start (7483998671383371313) -->
- <skip />
- <!-- no translation found for screen_pinning_exit (4553787518387346893) -->
- <skip />
+ <string name="screen_pinning_start" msgid="7483998671383371313">"এপ্‌টো পিন কৰা হ’ল"</string>
+ <string name="screen_pinning_exit" msgid="4553787518387346893">"এপ্‌টো আনপিন কৰা হ’ল"</string>
<string name="quick_settings_reset_confirmation_title" msgid="463533331480997595">"<xliff:g id="TILE_LABEL">%1$s</xliff:g> লুকুৱাবনে?"</string>
<string name="quick_settings_reset_confirmation_message" msgid="2320586180785674186">"আপুনি ইয়াক পৰৱৰ্তী সময়ত ছেটিংসমূহত অন কৰিলে ই পুনৰ প্ৰকট হ\'ব।"</string>
<string name="quick_settings_reset_confirmation_button" msgid="3341477479055016776">"লুকুৱাওক"</string>
@@ -730,7 +719,7 @@
<string name="notification_channel_summary_priority" msgid="7952654515769021553">"বাৰ্তালাপ শাখাটোৰ শীৰ্ষত দেখুৱায়, ওপঙা বাবল হিচাপে দেখা পোৱা যায়, লক স্ক্ৰীনত প্ৰ’ফাইলৰ চিত্ৰ প্ৰদৰ্শন কৰে"</string>
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"ছেটিংসমূহ"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"অগ্ৰাধিকাৰ"</string>
- <string name="no_shortcut" msgid="7176375126961212514">"<xliff:g id="APP_NAME">%1$s</xliff:g>এ বাৰ্তালাপ নিৰ্দিষ্ট ছেটিংসমূহ সমৰ্থন নকৰে"</string>
+ <string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g>এ বাৰ্তালাপৰ সুবিধাসমূহ সমৰ্থন নকৰে"</string>
<string name="bubble_overflow_empty_title" msgid="3120029421991510842">"কোনো শেহতীয়া bubbles নাই"</string>
<string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"শেহতীয়া bubbles আৰু অগ্ৰাহ্য কৰা bubbles ইয়াত প্ৰদর্শিত হ\'ব"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"এই জাননীসমূহ সংশোধন কৰিব নোৱাৰি।"</string>
@@ -1013,7 +1002,8 @@
<string name="bubble_accessibility_action_move_top_right" msgid="6916868852433483569">"শীৰ্ষৰ সোঁফালে নিয়ক"</string>
<string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"বুটামটো বাওঁফালে নিয়ক"</string>
<string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"তলৰ সোঁফালে নিয়ক"</string>
- <string name="bubble_dismiss_text" msgid="7071770411580452911">"অগ্ৰাহ্য কৰক"</string>
+ <!-- no translation found for bubble_dismiss_text (1314082410868930066) -->
+ <skip />
<string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"বাৰ্তালাপ বাবল নকৰিব"</string>
<string name="bubbles_user_education_title" msgid="5547017089271445797">"Bubbles ব্যৱহাৰ কৰি চাট কৰক"</string>
<string name="bubbles_user_education_description" msgid="1160281719576715211">"নতুন বাৰ্তালাপ উপঙি থকা চিহ্নসমূহ অথবা bubbles হিচাপে প্ৰদর্শিত হয়। Bubbles খুলিবলৈ টিপক। এইটো স্থানান্তৰ কৰিবলৈ টানি নিয়ক।"</string>
@@ -1024,11 +1014,14 @@
<string name="notification_content_system_nav_changed" msgid="5077913144844684544">"ছিষ্টেম নেভিগেশ্বন আপডে’ট কৰা হ’ল। সলনি কৰিবলৈ ছেটিংসমূহ-লৈ যাওক।"</string>
<string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"ছিষ্টেম নেভিগেশ্বন আপডে’ট কৰিবলৈ ছেটিংসমূহ-লৈ যাওক"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"ষ্টেণ্ডবাই"</string>
+ <string name="priority_onboarding_title" msgid="2893070698479227616">"বাৰ্তালাপসমূহ অগ্ৰাধিকাৰপ্ৰাপ্ত হিচাপে ছেট কৰা হৈছে"</string>
+ <string name="priority_onboarding_behavior" msgid="5342816047020432929">"অগ্ৰাধিকাৰপ্ৰাপ্ত বাৰ্তালাপসমূহে এইসমূহ কৰিব:"</string>
<string name="priority_onboarding_show_at_top_text" msgid="1678400241025513541">"বাৰ্তালাপ শাখাটোৰ শীৰ্ষত দেখুৱাওক"</string>
<string name="priority_onboarding_show_avatar_text" msgid="5756291381124091508">"লক স্ক্ৰীনত প্ৰ\'ফাইল-চিত্ৰ দেখুৱাওক"</string>
<string name="priority_onboarding_appear_as_bubble_text" msgid="4227039772250263122">"এপ্‌সমূহৰ ওপৰত ওপঙা বাবল হিচাপে দেখা পোৱা যাব"</string>
<string name="priority_onboarding_ignores_dnd_text" msgid="2918952762719600529">"অসুবিধা নিদিব সুবিধাটোত ব্যাঘাত জন্মাওক"</string>
<string name="priority_onboarding_done_button_title" msgid="4569550984286506007">"বুজি পালোঁ"</string>
+ <string name="priority_onboarding_settings_button_title" msgid="6663601574303585927">"ছেটিংসমূহ"</string>
<string name="magnification_overlay_title" msgid="6584179429612427958">"বিবৰ্ধন অ’ভাৰলে’ৰ ৱিণ্ড’"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"বিবৰ্ধন ৱিণ্ড’"</string>
<string name="magnification_controls_title" msgid="8421106606708891519">"বিবৰ্ধন ৱিণ্ড’ৰ নিয়ন্ত্ৰণসমূহ"</string>
@@ -1070,9 +1063,13 @@
<string name="controls_structure_tooltip" msgid="4355922222944447867">"অধিক চাবলৈ ছোৱাইপ কৰক"</string>
<string name="controls_seeding_in_progress" msgid="3033855341410264148">"চুপাৰিছসমূহ ল’ড কৰি থকা হৈছে"</string>
<string name="controls_media_close_session" msgid="9023534788828414585">"এই মিডিয়া ছেশ্বনটো বন্ধ কৰক"</string>
+ <string name="controls_media_resume" msgid="1933520684481586053">"পুনৰ আৰম্ভ কৰক"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"সক্ৰিয় নহয়, এপ্‌টো পৰীক্ষা কৰক"</string>
<string name="controls_error_retryable" msgid="864025882878378470">"আসোঁৱাহ, পুনৰ চেষ্টা কৰি আছে…"</string>
- <string name="controls_error_removed" msgid="6299213591234723805">"ডিভাইচটো আঁতৰোৱা হৈছে"</string>
+ <string name="controls_error_removed" msgid="6675638069846014366">"বিচাৰি পোৱা নগ’ল"</string>
+ <string name="controls_error_removed_title" msgid="1207794911208047818">"নিয়ন্ত্ৰণটো উপলব্ধ নহয়"</string>
+ <string name="controls_error_removed_message" msgid="2885911717034750542">"<xliff:g id="DEVICE">%1$s</xliff:g> এক্সেছ কৰিব পৰা নগ’ল। নিয়ন্ত্ৰণটো এতিয়াও উপলব্ধ আৰু এপ্‌টোৰ ছেটিংসমূহ সলনি কৰা হোৱা নাই বুলি নিশ্চিত কৰিবলৈ <xliff:g id="APPLICATION">%2$s</xliff:g> এপ্‌টো পৰীক্ষা কৰক।"</string>
+ <string name="controls_open_app" msgid="483650971094300141">"এপ্‌টো খোলক"</string>
<string name="controls_error_generic" msgid="352500456918362905">"স্থিতি ল’ড কৰিব নোৱাৰি"</string>
<string name="controls_error_failed" msgid="960228639198558525">"আসোঁৱাহ হৈছে, আকৌ চেষ্টা কৰক"</string>
<string name="controls_in_progress" msgid="4421080500238215939">"চলি আছে"</string>
diff --git a/packages/SystemUI/res/values-az/strings.xml b/packages/SystemUI/res/values-az/strings.xml
index 52c85d1d70e7..3919fe314361 100644
--- a/packages/SystemUI/res/values-az/strings.xml
+++ b/packages/SystemUI/res/values-az/strings.xml
@@ -77,9 +77,6 @@
<string name="compat_mode_on" msgid="4963711187149440884">"Ekranı doldurmaq üçün yaxınlaşdır"</string>
<string name="compat_mode_off" msgid="7682459748279487945">"Ekranı doldurmaq üçün uzat"</string>
<string name="global_action_screenshot" msgid="2760267567509131654">"Skrinşot"</string>
- <string name="global_action_lock_message" product="default" msgid="4466026255205186456">"Daha çox seçim üçün telefonu kiliddən çıxarın"</string>
- <string name="global_action_lock_message" product="tablet" msgid="7621167597240332986">"Daha çox seçim üçün planşeti kiliddən çıxarın"</string>
- <string name="global_action_lock_message" product="device" msgid="538790401275363781">"Daha çox seçim üçün cihazı kiliddən çıxarın"</string>
<string name="remote_input_image_insertion_text" msgid="4850791636452521123">"şəkil göndərdi"</string>
<string name="screenshot_saving_ticker" msgid="6519186952674544916">"Skrinşot yadda saxlanılır..."</string>
<string name="screenshot_saving_title" msgid="2298349784913287333">"Skrinşot yadda saxlanır..."</string>
@@ -595,29 +592,21 @@
<string name="volume_odi_captions_hint_enable" msgid="2073091194012843195">"aktiv edin"</string>
<string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"deaktiv edin"</string>
<string name="accessibility_output_chooser" msgid="7807898688967194183">"Çıxış cihazına keçin"</string>
- <!-- no translation found for screen_pinning_title (9058007390337841305) -->
- <skip />
+ <string name="screen_pinning_title" msgid="9058007390337841305">"Tətbiq bərkidilib"</string>
<string name="screen_pinning_description" msgid="8699395373875667743">"Sancaq götürülənə qədər bu görünəcək. Sancağı götürmək üçün Geri və İcmal düymələrinə basıb saxlayın."</string>
<string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"Sancaq götürülənə qədər bu görünəcək. Sancağı götürmək üçün Geri və Əsas səhifə düymələrinə basıb saxlayın."</string>
<string name="screen_pinning_description_gestural" msgid="7246323931831232068">"Bu, onu çıxarana qədər görünəcək. Çıxarmaq üçün yuxarı sürüşdürün &amp; basıb saxlayın."</string>
<string name="screen_pinning_description_accessible" msgid="7386449191953535332">"Sancaq götürülənə qədər bu görünəcək. Sancağı götürmək üçün Geri düyməsinə basıb saxlayın."</string>
<string name="screen_pinning_description_recents_invisible_accessible" msgid="2857071808674481986">"Sancaq götürülənə qədər bu görünəcək. Sancağı götürmək üçün Əsas səhifə düyməsinə basıb saxlayın."</string>
- <!-- no translation found for screen_pinning_exposes_personal_data (8189852022981524789) -->
- <skip />
- <!-- no translation found for screen_pinning_can_open_other_apps (7529756813231421455) -->
- <skip />
- <!-- no translation found for screen_pinning_toast (8177286912533744328) -->
- <skip />
- <!-- no translation found for screen_pinning_toast_recents_invisible (6850978077443052594) -->
- <skip />
- <!-- no translation found for screen_pinning_toast_gesture_nav (170699893395336705) -->
- <skip />
+ <string name="screen_pinning_exposes_personal_data" msgid="8189852022981524789">"Şəxsi məlumatlar (məsələn, kontaktlar və e-poçt məzmunu) əlçatan ola bilər."</string>
+ <string name="screen_pinning_can_open_other_apps" msgid="7529756813231421455">"Bərkidilmiş tətbiq digər tətbiqləri aça bilər."</string>
+ <string name="screen_pinning_toast" msgid="8177286912533744328">"Bu tətbiqi çıxarmaq üçün Geri və İcmal düymələrinə basıb saxlayın"</string>
+ <string name="screen_pinning_toast_recents_invisible" msgid="6850978077443052594">"Bu tətbiqi çıxarmaq üçün Geri və Əsas ekran düymələrinə basıb saxlayın"</string>
+ <string name="screen_pinning_toast_gesture_nav" msgid="170699893395336705">"Bu tətbiqi çıxarmaq üçün yuxarı sürüşdürüb saxlayın"</string>
<string name="screen_pinning_positive" msgid="3285785989665266984">"Anladım!"</string>
<string name="screen_pinning_negative" msgid="6882816864569211666">"Yox, çox sağ olun"</string>
- <!-- no translation found for screen_pinning_start (7483998671383371313) -->
- <skip />
- <!-- no translation found for screen_pinning_exit (4553787518387346893) -->
- <skip />
+ <string name="screen_pinning_start" msgid="7483998671383371313">"Tətbiq bərkidildi"</string>
+ <string name="screen_pinning_exit" msgid="4553787518387346893">"Tətbiq çıxarıldı"</string>
<string name="quick_settings_reset_confirmation_title" msgid="463533331480997595">"<xliff:g id="TILE_LABEL">%1$s</xliff:g> gizlədilsin?"</string>
<string name="quick_settings_reset_confirmation_message" msgid="2320586180785674186">"Ayarlarda onu aktivləşdirəcəyiniz vaxta qədər o, yenidən görünəcək."</string>
<string name="quick_settings_reset_confirmation_button" msgid="3341477479055016776">"Gizlədin"</string>
@@ -730,7 +719,7 @@
<string name="notification_channel_summary_priority" msgid="7952654515769021553">"Söhbət bölməsinin yuxarısında göstərilir, üzən qabarcıq kimi görünür, kilid ekranında profil şəkli göstərir"</string>
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"Ayarlar"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"Prioritet"</string>
- <string name="no_shortcut" msgid="7176375126961212514">"<xliff:g id="APP_NAME">%1$s</xliff:g> söhbətə aid ayarları dəstəkləmir"</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>
<string name="bubble_overflow_empty_title" msgid="3120029421991510842">"Yumrucuqlar yoxdur"</string>
<string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"Son yumrucuqlar və buraxılmış yumrucuqlar burada görünəcək"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"Bu bildirişlər dəyişdirilə bilməz."</string>
@@ -1013,7 +1002,8 @@
<string name="bubble_accessibility_action_move_top_right" msgid="6916868852433483569">"Yuxarıya sağa köçürün"</string>
<string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"Aşağıya sola köçürün"</string>
<string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"Aşağıya sağa köçürün"</string>
- <string name="bubble_dismiss_text" msgid="7071770411580452911">"Kənarlaşdırın"</string>
+ <!-- no translation found for bubble_dismiss_text (1314082410868930066) -->
+ <skip />
<string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"Söhbətdən gələn bildirişi göstərməyin"</string>
<string name="bubbles_user_education_title" msgid="5547017089271445797">"Yumrucuqlardan istifadə edərək söhbət edin"</string>
<string name="bubbles_user_education_description" msgid="1160281719576715211">"Yeni söhbətlər üzən nişanlar və ya yumrucuqlar kimi görünür. Yumrucuğu açmaq üçün toxunun. Hərəkət etdirmək üçün sürüşdürün."</string>
@@ -1024,11 +1014,14 @@
<string name="notification_content_system_nav_changed" msgid="5077913144844684544">"Sistem naviqasiyası yeniləndi. Dəyişiklik etmək üçün Ayarlara daxil olun."</string>
<string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"Sistem naviqasiyasını yeniləmək üçün Ayarlara keçin"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Gözləmə rejimi"</string>
+ <string name="priority_onboarding_title" msgid="2893070698479227616">"Söhbət prioritet olaraq ayarlanıb"</string>
+ <string name="priority_onboarding_behavior" msgid="5342816047020432929">"Prioritet söhbətlər bunları edəcək:"</string>
<string name="priority_onboarding_show_at_top_text" msgid="1678400241025513541">"Söhbət bölməsinin yuxarısında göstərilir"</string>
<string name="priority_onboarding_show_avatar_text" msgid="5756291381124091508">"Kilid ekranında profil şəkli göstərilir"</string>
<string name="priority_onboarding_appear_as_bubble_text" msgid="4227039772250263122">"Tətbiqlərin üzərində üzən qabarcıq kimi görünəcək"</string>
<string name="priority_onboarding_ignores_dnd_text" msgid="2918952762719600529">"Narahat Etməyin rejimində göstərilsin"</string>
<string name="priority_onboarding_done_button_title" msgid="4569550984286506007">"Anladım"</string>
+ <string name="priority_onboarding_settings_button_title" msgid="6663601574303585927">"Ayarlar"</string>
<string name="magnification_overlay_title" msgid="6584179429612427958">"Böyütmə Üst-üstə Düşən Pəncərəsi"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"Böyütmə Pəncərəsi"</string>
<string name="magnification_controls_title" msgid="8421106606708891519">"Böyütmə Pəncərəsi Kontrolları"</string>
@@ -1070,9 +1063,13 @@
<string name="controls_structure_tooltip" msgid="4355922222944447867">"Digərlərini görmək üçün sürüşdürün"</string>
<string name="controls_seeding_in_progress" msgid="3033855341410264148">"Tövsiyələr yüklənir"</string>
<string name="controls_media_close_session" msgid="9023534788828414585">"Bu media sessiyasını bağlayın"</string>
+ <string name="controls_media_resume" msgid="1933520684481586053">"Davam edin"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"Aktiv deyil, tətbiqi yoxlayın"</string>
<string name="controls_error_retryable" msgid="864025882878378470">"Xəta, yenidən cəhd edilir…"</string>
- <string name="controls_error_removed" msgid="6299213591234723805">"Cihaz silindi"</string>
+ <string name="controls_error_removed" msgid="6675638069846014366">"Tapılmadı"</string>
+ <string name="controls_error_removed_title" msgid="1207794911208047818">"Nəzarət əlçatan deyil"</string>
+ <string name="controls_error_removed_message" msgid="2885911717034750542">"<xliff:g id="DEVICE">%1$s</xliff:g> cihazına giriş mümkün olmadı. <xliff:g id="APPLICATION">%2$s</xliff:g> tətbiqini yoxlayaraq nəzarətin hələ də əlçatan olduğuna və tətbiq ayarlarının dəyişmədiyinə əmin olun."</string>
+ <string name="controls_open_app" msgid="483650971094300141">"Tətbiqi açın"</string>
<string name="controls_error_generic" msgid="352500456918362905">"Statusu yükləmək alınmadı"</string>
<string name="controls_error_failed" msgid="960228639198558525">"Xəta, yenidən cəhd edin"</string>
<string name="controls_in_progress" msgid="4421080500238215939">"Davam edir"</string>
diff --git a/packages/SystemUI/res/values-b+sr+Latn/strings.xml b/packages/SystemUI/res/values-b+sr+Latn/strings.xml
index 2057dd2d576c..f2a6d65bd051 100644
--- a/packages/SystemUI/res/values-b+sr+Latn/strings.xml
+++ b/packages/SystemUI/res/values-b+sr+Latn/strings.xml
@@ -77,9 +77,6 @@
<string name="compat_mode_on" msgid="4963711187149440884">"Zumiraj na celom ekranu"</string>
<string name="compat_mode_off" msgid="7682459748279487945">"Razvuci na ceo ekran"</string>
<string name="global_action_screenshot" msgid="2760267567509131654">"Snimak ekrana"</string>
- <string name="global_action_lock_message" product="default" msgid="4466026255205186456">"Otključajte telefon za još opcija"</string>
- <string name="global_action_lock_message" product="tablet" msgid="7621167597240332986">"Otključajte tablet za još opcija"</string>
- <string name="global_action_lock_message" product="device" msgid="538790401275363781">"Otključajte uređaj za još opcija"</string>
<string name="remote_input_image_insertion_text" msgid="4850791636452521123">"je poslao/la sliku"</string>
<string name="screenshot_saving_ticker" msgid="6519186952674544916">"Čuvanje snimka ekrana..."</string>
<string name="screenshot_saving_title" msgid="2298349784913287333">"Čuvanje snimka ekrana..."</string>
@@ -725,7 +722,7 @@
<string name="notification_channel_summary_priority" msgid="7952654515769021553">"Prikazuje se u vrhu odeljka za konverzacije kao plutajući oblačić, prikazuje sliku profila na zaključanom ekranu"</string>
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"Podešavanja"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"Prioritet"</string>
- <string name="no_shortcut" msgid="7176375126961212514">"<xliff:g id="APP_NAME">%1$s</xliff:g> ne podržava podešavanja za konverzacije"</string>
+ <string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> ne podržava funkcije konverzacije"</string>
<string name="bubble_overflow_empty_title" msgid="3120029421991510842">"Nema nedavnih oblačića"</string>
<string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"Ovde se prikazuju nedavni i odbačeni oblačići"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"Ova obaveštenja ne mogu da se menjaju."</string>
@@ -1010,9 +1007,10 @@
<string name="bubble_accessibility_action_move_top_right" msgid="6916868852433483569">"Premesti gore desno"</string>
<string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"Premesti dole levo"</string>
<string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"Premesti dole desno"</string>
- <string name="bubble_dismiss_text" msgid="7071770411580452911">"Odbaci"</string>
+ <!-- no translation found for bubble_dismiss_text (1314082410868930066) -->
+ <skip />
<string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"Ne koristi oblačiće za konverzaciju"</string>
- <string name="bubbles_user_education_title" msgid="5547017089271445797">"Ćaskajte pomoću oblačića"</string>
+ <string name="bubbles_user_education_title" msgid="5547017089271445797">"Ćaskajte u oblačićima"</string>
<string name="bubbles_user_education_description" msgid="1160281719576715211">"Nove konverzacije se prikazuju kao plutajuće ikone ili oblačići. Dodirnite da biste otvorili oblačić. Prevucite da biste ga premestili."</string>
<string name="bubbles_user_education_manage_title" msgid="2848511858160342320">"Kontrolišite oblačiće u bilo kom trenutku"</string>
<string name="bubbles_user_education_manage" msgid="1391639189507036423">"Dodirnite Upravljajte da biste isključili oblačiće iz ove aplikacije"</string>
@@ -1021,11 +1019,14 @@
<string name="notification_content_system_nav_changed" msgid="5077913144844684544">"Navigacija sistema je ažurirana. Da biste uneli izmene, idite u Podešavanja."</string>
<string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"Idite u Podešavanja da biste ažurirali navigaciju sistema"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Stanje pripravnosti"</string>
+ <string name="priority_onboarding_title" msgid="2893070698479227616">"Konverzacija je podešena na prioritetnu"</string>
+ <string name="priority_onboarding_behavior" msgid="5342816047020432929">"Prioritetne konverzacije će:"</string>
<string name="priority_onboarding_show_at_top_text" msgid="1678400241025513541">"Prikazuje se u vrhu odeljka za konverzacije"</string>
<string name="priority_onboarding_show_avatar_text" msgid="5756291381124091508">"Prikazuje sliku profila na zaključanom ekranu"</string>
<string name="priority_onboarding_appear_as_bubble_text" msgid="4227039772250263122">"Prikazuju se plutajući oblačići preko aplikacija"</string>
<string name="priority_onboarding_ignores_dnd_text" msgid="2918952762719600529">"Ometa podešavanje Ne uznemiravaj"</string>
<string name="priority_onboarding_done_button_title" msgid="4569550984286506007">"Važi"</string>
+ <string name="priority_onboarding_settings_button_title" msgid="6663601574303585927">"Podešavanja"</string>
<string name="magnification_overlay_title" msgid="6584179429612427958">"Preklopni prozor za uvećanje"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"Prozor za uvećanje"</string>
<string name="magnification_controls_title" msgid="8421106606708891519">"Kontrole prozora za uvećanje"</string>
@@ -1062,19 +1063,23 @@
<string name="controls_pin_wrong" msgid="6162694056042164211">"Pogrešan PIN"</string>
<string name="controls_pin_verifying" msgid="3755045989392131746">"Verifikuje se…"</string>
<string name="controls_pin_instructions" msgid="6363309783822475238">"Unesite PIN"</string>
- <string name="controls_pin_instructions_retry" msgid="1566667581012131046">"Probajte pomoću drugog PIN-a"</string>
+ <string name="controls_pin_instructions_retry" msgid="1566667581012131046">"Probajte drugi PIN"</string>
<string name="controls_confirmation_confirming" msgid="2596071302617310665">"Potvrđuje se…"</string>
<string name="controls_confirmation_message" msgid="7744104992609594859">"Potvrdite promenu za: <xliff:g id="DEVICE">%s</xliff:g>"</string>
<string name="controls_structure_tooltip" msgid="4355922222944447867">"Prevucite da biste videli još"</string>
<string name="controls_seeding_in_progress" msgid="3033855341410264148">"Učitavaju se preporuke"</string>
<string name="controls_media_close_session" msgid="9023534788828414585">"Zatvorite ovu sesiju medija"</string>
+ <string name="controls_media_resume" msgid="1933520684481586053">"Nastavi"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"Neaktivno. Vidite aplikaciju"</string>
<string name="controls_error_retryable" msgid="864025882878378470">"Greška, pokušava se ponovo…"</string>
- <string name="controls_error_removed" msgid="6299213591234723805">"Uređaj je uklonjen"</string>
+ <string name="controls_error_removed" msgid="6675638069846014366">"Nije pronađeno"</string>
+ <string name="controls_error_removed_title" msgid="1207794911208047818">"Kontrola nije dostupna"</string>
+ <string name="controls_error_removed_message" msgid="2885911717034750542">"Pristupanje uređaju <xliff:g id="DEVICE">%1$s</xliff:g> nije uspelo. Pogledajte aplikaciju <xliff:g id="APPLICATION">%2$s</xliff:g> da biste se uverili da je kontrola još uvek dostupna i da se podešavanja aplikacije nisu promenila."</string>
+ <string name="controls_open_app" msgid="483650971094300141">"Otvori aplikaciju"</string>
<string name="controls_error_generic" msgid="352500456918362905">"Učitavanje statusa nije uspelo"</string>
<string name="controls_error_failed" msgid="960228639198558525">"Greška. Probajte ponovo"</string>
<string name="controls_in_progress" msgid="4421080500238215939">"U toku"</string>
<string name="controls_added_tooltip" msgid="4842812921719153085">"Zadržite dugme za uključivanje da biste videli nove kontrole"</string>
<string name="controls_menu_add" msgid="4447246119229920050">"Dodaj kontrole"</string>
- <string name="controls_menu_edit" msgid="890623986951347062">"Izmenite kontrole"</string>
+ <string name="controls_menu_edit" msgid="890623986951347062">"Izmeni kontrole"</string>
</resources>
diff --git a/packages/SystemUI/res/values-be/strings.xml b/packages/SystemUI/res/values-be/strings.xml
index 82c2535a7316..d34f089ec9aa 100644
--- a/packages/SystemUI/res/values-be/strings.xml
+++ b/packages/SystemUI/res/values-be/strings.xml
@@ -77,9 +77,6 @@
<string name="compat_mode_on" msgid="4963711187149440884">"Павял. на ўвесь экран"</string>
<string name="compat_mode_off" msgid="7682459748279487945">"Расцягн. на ўвесь экран"</string>
<string name="global_action_screenshot" msgid="2760267567509131654">"Здымак экрана"</string>
- <string name="global_action_lock_message" product="default" msgid="4466026255205186456">"Каб адкрыць іншыя параметры, разблакіруйце тэлефон"</string>
- <string name="global_action_lock_message" product="tablet" msgid="7621167597240332986">"Каб адкрыць іншыя параметры, разблакіруйце планшэт"</string>
- <string name="global_action_lock_message" product="device" msgid="538790401275363781">"Каб адкрыць іншыя параметры, разблакіруйце прыладу"</string>
<string name="remote_input_image_insertion_text" msgid="4850791636452521123">"адпраўлены відарыс"</string>
<string name="screenshot_saving_ticker" msgid="6519186952674544916">"Захаванне скрыншота..."</string>
<string name="screenshot_saving_title" msgid="2298349784913287333">"Захаванне скрыншота..."</string>
@@ -728,7 +725,7 @@
<string name="notification_channel_summary_priority" msgid="7952654515769021553">"Паказваецца ўверсе раздзела размоў у выглядзе ўсплывальнага апавяшчэння, а на экране блакіроўкі – у выглядзе відарыса профілю"</string>
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"Налады"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"Прыярытэт"</string>
- <string name="no_shortcut" msgid="7176375126961212514">"<xliff:g id="APP_NAME">%1$s</xliff:g> не падтрымлівае пэўныя налады размоў"</string>
+ <string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> не падтрымлівае функцыі размовы"</string>
<string name="bubble_overflow_empty_title" msgid="3120029421991510842">"Няма нядаўніх усплывальных апавяшчэнняў"</string>
<string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"Нядаўнія і адхіленыя ўсплывальныя апавяшчэнні будуць паказаны тут"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"Гэтыя апавяшчэнні нельга змяніць."</string>
@@ -1015,9 +1012,10 @@
<string name="bubble_accessibility_action_move_top_right" msgid="6916868852433483569">"Перамясціце правей і вышэй"</string>
<string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"Перамясціць лявей і ніжэй"</string>
<string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"Перамясціць правей і ніжэй"</string>
- <string name="bubble_dismiss_text" msgid="7071770411580452911">"Адхіліць"</string>
+ <!-- no translation found for bubble_dismiss_text (1314082410868930066) -->
+ <skip />
<string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"Не паказваць размову ў выглядзе ўсплывальных апавяшчэнняў"</string>
- <string name="bubbles_user_education_title" msgid="5547017089271445797">"Размаўляйце ў чаце, які паказвае ўсплывальныя апавяшчэнні"</string>
+ <string name="bubbles_user_education_title" msgid="5547017089271445797">"Усплывальныя апавяшчэнні"</string>
<string name="bubbles_user_education_description" msgid="1160281719576715211">"Новыя размовы будуць паказвацца як рухомыя значкі ці ўсплывальныя апавяшчэнні. Націсніце, каб адкрыць усплывальнае апавяшчэнне. Перацягніце яго, каб перамясціць."</string>
<string name="bubbles_user_education_manage_title" msgid="2848511858160342320">"Кіруйце ўсплывальнымі апавяшчэннямі ў любы час"</string>
<string name="bubbles_user_education_manage" msgid="1391639189507036423">"Каб выключыць усплывальныя апавяшчэнні з гэтай праграмы, націсніце \"Кіраваць\""</string>
@@ -1026,11 +1024,14 @@
<string name="notification_content_system_nav_changed" msgid="5077913144844684544">"Навігацыя ў сістэме абноўлена. Каб унесці змяненні, перайдзіце ў Налады."</string>
<string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"Перайдзіце ў Налады, каб абнавіць параметры навігацыі ў сістэме"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Рэжым чакання"</string>
+ <string name="priority_onboarding_title" msgid="2893070698479227616">"Размова пазначана як прыярытэтная"</string>
+ <string name="priority_onboarding_behavior" msgid="5342816047020432929">"Прыярытэтныя размовы будуць:"</string>
<string name="priority_onboarding_show_at_top_text" msgid="1678400241025513541">"Паказваюцца ўверсе раздзела размоў"</string>
<string name="priority_onboarding_show_avatar_text" msgid="5756291381124091508">"Паказваюць відарыс профілю на экране блакіроўкі"</string>
<string name="priority_onboarding_appear_as_bubble_text" msgid="4227039772250263122">"Паказваюцца як рухомыя апавяшчэнні паверх праграм"</string>
<string name="priority_onboarding_ignores_dnd_text" msgid="2918952762719600529">"Паказваюцца ў рэжыме \"Не турбаваць\""</string>
<string name="priority_onboarding_done_button_title" msgid="4569550984286506007">"Зразумела"</string>
+ <string name="priority_onboarding_settings_button_title" msgid="6663601574303585927">"Налады"</string>
<string name="magnification_overlay_title" msgid="6584179429612427958">"Акно-накладка з павелічэннем"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"Акно павелічэння"</string>
<string name="magnification_controls_title" msgid="8421106606708891519">"Налады акна павелічэння"</string>
@@ -1074,9 +1075,13 @@
<string name="controls_structure_tooltip" msgid="4355922222944447867">"Правядзіце пальцам, каб убачыць больш інфармацыі"</string>
<string name="controls_seeding_in_progress" msgid="3033855341410264148">"Загружаюцца рэкамендацыі"</string>
<string name="controls_media_close_session" msgid="9023534788828414585">"Закрыць гэты сеанс мультымедыя"</string>
+ <string name="controls_media_resume" msgid="1933520684481586053">"Узнавіць"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"Неактыўна, праверце праграму"</string>
<string name="controls_error_retryable" msgid="864025882878378470">"Памылка, паўторная спроба…"</string>
- <string name="controls_error_removed" msgid="6299213591234723805">"Прылада выдалена"</string>
+ <string name="controls_error_removed" msgid="6675638069846014366">"Не знойдзена"</string>
+ <string name="controls_error_removed_title" msgid="1207794911208047818">"Кіраванне недаступнае"</string>
+ <string name="controls_error_removed_message" msgid="2885911717034750542">"Не ўдалося атрымаць доступ да прылады \"<xliff:g id="DEVICE">%1$s</xliff:g>\". Праверце, ці не змяніліся налады праграмы \"<xliff:g id="APPLICATION">%2$s</xliff:g>\" і ці даступная ў ёй функцыя кіравання."</string>
+ <string name="controls_open_app" msgid="483650971094300141">"Адкрыць праграму"</string>
<string name="controls_error_generic" msgid="352500456918362905">"Не ўдалося загрузіць стан"</string>
<string name="controls_error_failed" msgid="960228639198558525">"Памылка, паўтарыце спробу"</string>
<string name="controls_in_progress" msgid="4421080500238215939">"Выконваецца"</string>
diff --git a/packages/SystemUI/res/values-bg/strings.xml b/packages/SystemUI/res/values-bg/strings.xml
index 6dd050fb0735..2388cf6167c0 100644
--- a/packages/SystemUI/res/values-bg/strings.xml
+++ b/packages/SystemUI/res/values-bg/strings.xml
@@ -77,9 +77,6 @@
<string name="compat_mode_on" msgid="4963711187149440884">"Мащаб – запълва екрана"</string>
<string name="compat_mode_off" msgid="7682459748279487945">"Разпъване – запълва екрана"</string>
<string name="global_action_screenshot" msgid="2760267567509131654">"Екранна снимка"</string>
- <string name="global_action_lock_message" product="default" msgid="4466026255205186456">"Отключете телефона си за още опции"</string>
- <string name="global_action_lock_message" product="tablet" msgid="7621167597240332986">"Отключете таблета си за още опции"</string>
- <string name="global_action_lock_message" product="device" msgid="538790401275363781">"Отключете устройството си за още опции"</string>
<string name="remote_input_image_insertion_text" msgid="4850791636452521123">"изпратено изображение"</string>
<string name="screenshot_saving_ticker" msgid="6519186952674544916">"Екранната снимка се запазва..."</string>
<string name="screenshot_saving_title" msgid="2298349784913287333">"Екранната снимка се запазва..."</string>
@@ -595,29 +592,21 @@
<string name="volume_odi_captions_hint_enable" msgid="2073091194012843195">"активиране"</string>
<string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"деактивиране"</string>
<string name="accessibility_output_chooser" msgid="7807898688967194183">"Превключване на устройството за възпроизвеждане на звук"</string>
- <!-- no translation found for screen_pinning_title (9058007390337841305) -->
- <skip />
+ <string name="screen_pinning_title" msgid="9058007390337841305">"Приложението е фиксирано"</string>
<string name="screen_pinning_description" msgid="8699395373875667743">"Екранът ще се показва, докато не го освободите с докосване и задържане на бутона за връщане назад и този за общ преглед."</string>
<string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"Екранът ще се показва, докато не го освободите с докосване и задържане на бутона за връщане назад и „Начало“."</string>
<string name="screen_pinning_description_gestural" msgid="7246323931831232068">"Екранът ще остане на преден план, докато не го освободите. Прекарайте пръст нагоре и задръжте за освобождаване."</string>
<string name="screen_pinning_description_accessible" msgid="7386449191953535332">"Екранът ще се показва, докато не го освободите с докосване и задържане на бутона за общ преглед."</string>
<string name="screen_pinning_description_recents_invisible_accessible" msgid="2857071808674481986">"Екранът ще се показва, докато не го освободите с докосване и задържане на бутона „Начало“."</string>
- <!-- no translation found for screen_pinning_exposes_personal_data (8189852022981524789) -->
- <skip />
- <!-- no translation found for screen_pinning_can_open_other_apps (7529756813231421455) -->
- <skip />
- <!-- no translation found for screen_pinning_toast (8177286912533744328) -->
- <skip />
- <!-- no translation found for screen_pinning_toast_recents_invisible (6850978077443052594) -->
- <skip />
- <!-- no translation found for screen_pinning_toast_gesture_nav (170699893395336705) -->
- <skip />
+ <string name="screen_pinning_exposes_personal_data" msgid="8189852022981524789">"Някои лични данни може да бъдат достъпни (като например контактите и съдържанието от имейлите)."</string>
+ <string name="screen_pinning_can_open_other_apps" msgid="7529756813231421455">"Фиксираните приложения може да отворят други приложения."</string>
+ <string name="screen_pinning_toast" msgid="8177286912533744328">"За да освободите това приложение, докоснете и задръжте бутона за връщане назад и този за общ преглед"</string>
+ <string name="screen_pinning_toast_recents_invisible" msgid="6850978077443052594">"За да освободите това приложение, докоснете и задръжте бутона за връщане назад и „Начало“"</string>
+ <string name="screen_pinning_toast_gesture_nav" msgid="170699893395336705">"За да освободите това приложение, прекарайте пръст нагоре и задръжте"</string>
<string name="screen_pinning_positive" msgid="3285785989665266984">"Разбрах"</string>
<string name="screen_pinning_negative" msgid="6882816864569211666">"Не, благодаря"</string>
- <!-- no translation found for screen_pinning_start (7483998671383371313) -->
- <skip />
- <!-- no translation found for screen_pinning_exit (4553787518387346893) -->
- <skip />
+ <string name="screen_pinning_start" msgid="7483998671383371313">"Приложението е фиксирано"</string>
+ <string name="screen_pinning_exit" msgid="4553787518387346893">"Приложението е освободено"</string>
<string name="quick_settings_reset_confirmation_title" msgid="463533331480997595">"Да се скрие ли „<xliff:g id="TILE_LABEL">%1$s</xliff:g>“?"</string>
<string name="quick_settings_reset_confirmation_message" msgid="2320586180785674186">"Бързите настройки ще се покажат отново следващия път, когато ги включите от „Настройки“."</string>
<string name="quick_settings_reset_confirmation_button" msgid="3341477479055016776">"Скриване"</string>
@@ -730,7 +719,7 @@
<string name="notification_channel_summary_priority" msgid="7952654515769021553">"Показва се като плаващо балонче в горната част на секцията с разговори и показва снимката на потребителския профил на заключения екран"</string>
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"Настройки"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"Приоритет"</string>
- <string name="no_shortcut" msgid="7176375126961212514">"<xliff:g id="APP_NAME">%1$s</xliff:g> не поддържа свързаните с разговорите настройки"</string>
+ <string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> не поддържа функциите за разговор"</string>
<string name="bubble_overflow_empty_title" msgid="3120029421991510842">"Няма скорошни балончета"</string>
<string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"Скорошните и отхвърлените балончета ще се показват тук"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"Тези известия не могат да бъдат променяни."</string>
@@ -1013,7 +1002,8 @@
<string name="bubble_accessibility_action_move_top_right" msgid="6916868852433483569">"Преместване горе вдясно"</string>
<string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"Преместване долу вляво"</string>
<string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"Преместване долу вдясно"</string>
- <string name="bubble_dismiss_text" msgid="7071770411580452911">"Отхвърляне"</string>
+ <!-- no translation found for bubble_dismiss_text (1314082410868930066) -->
+ <skip />
<string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"Без балончета за разговора"</string>
<string name="bubbles_user_education_title" msgid="5547017089271445797">"Разговаряне чрез балончета"</string>
<string name="bubbles_user_education_description" msgid="1160281719576715211">"Новите разговори се показват като плаващи икони, или балончета. Докоснете балонче, за да го отворите, или го плъзнете, за да го преместите."</string>
@@ -1024,11 +1014,14 @@
<string name="notification_content_system_nav_changed" msgid="5077913144844684544">"Режимът за навигиране в системата е актуализиран. За да извършите промени, отворете настройките."</string>
<string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"Отворете настройките, за да актуализирате режима за навигиране в системата"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Режим на готовност"</string>
+ <string name="priority_onboarding_title" msgid="2893070698479227616">"Разговорът е зададен като приоритетен"</string>
+ <string name="priority_onboarding_behavior" msgid="5342816047020432929">"Приоритетните разговори ще:"</string>
<string name="priority_onboarding_show_at_top_text" msgid="1678400241025513541">"Показване върху секцията с разговори"</string>
<string name="priority_onboarding_show_avatar_text" msgid="5756291381124091508">"Показване на снимката на потр. профил на закл. екран"</string>
<string name="priority_onboarding_appear_as_bubble_text" msgid="4227039772250263122">"Показва се като плаващо балонче върху приложенията"</string>
<string name="priority_onboarding_ignores_dnd_text" msgid="2918952762719600529">"Прекъсване на режима „Не безпокойте“"</string>
<string name="priority_onboarding_done_button_title" msgid="4569550984286506007">"Разбрах"</string>
+ <string name="priority_onboarding_settings_button_title" msgid="6663601574303585927">"Настройки"</string>
<string name="magnification_overlay_title" msgid="6584179429612427958">"Прозорец с наслагване за ниво на мащаба"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"Прозорец за ниво на мащаба"</string>
<string name="magnification_controls_title" msgid="8421106606708891519">"Контроли за прозореца за ниво на мащаба"</string>
@@ -1070,9 +1063,13 @@
<string name="controls_structure_tooltip" msgid="4355922222944447867">"Прекарайте пръст, за да видите повече"</string>
<string name="controls_seeding_in_progress" msgid="3033855341410264148">"Препоръките се зареждат"</string>
<string name="controls_media_close_session" msgid="9023534788828414585">"Затваряне на тази сесия за мултимедия"</string>
+ <string name="controls_media_resume" msgid="1933520684481586053">"Възобновяване"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"Неактивно, проверете прилож."</string>
<string name="controls_error_retryable" msgid="864025882878378470">"Грешка. Извършва се нов опит…"</string>
- <string name="controls_error_removed" msgid="6299213591234723805">"Устройството бе премахнато"</string>
+ <string name="controls_error_removed" msgid="6675638069846014366">"Не е намерено"</string>
+ <string name="controls_error_removed_title" msgid="1207794911208047818">"Контролата не е налице"</string>
+ <string name="controls_error_removed_message" msgid="2885911717034750542">"Няма достъп до <xliff:g id="DEVICE">%1$s</xliff:g>. Отворете приложението <xliff:g id="APPLICATION">%2$s</xliff:g> и проверете дали контролата още е налице и дали настройките му не са променени."</string>
+ <string name="controls_open_app" msgid="483650971094300141">"Към приложението"</string>
<string name="controls_error_generic" msgid="352500456918362905">"Състоян. не може да се зареди"</string>
<string name="controls_error_failed" msgid="960228639198558525">"Грешка. Опитайте отново"</string>
<string name="controls_in_progress" msgid="4421080500238215939">"В ход"</string>
diff --git a/packages/SystemUI/res/values-bn/strings.xml b/packages/SystemUI/res/values-bn/strings.xml
index f25890b26bb0..d5e827f6b618 100644
--- a/packages/SystemUI/res/values-bn/strings.xml
+++ b/packages/SystemUI/res/values-bn/strings.xml
@@ -77,9 +77,6 @@
<string name="compat_mode_on" msgid="4963711187149440884">"স্ক্রীণ পূরণ করতে জুম করুন"</string>
<string name="compat_mode_off" msgid="7682459748279487945">"ফুল স্ক্রিন করুন"</string>
<string name="global_action_screenshot" msgid="2760267567509131654">"স্ক্রিনশট"</string>
- <string name="global_action_lock_message" product="default" msgid="4466026255205186456">"আরও বিকল্প দেখতে আপনার ফোন আনলক করুন"</string>
- <string name="global_action_lock_message" product="tablet" msgid="7621167597240332986">"আরও বিকল্প দেখতে আপনার ট্যাবলেট আনলক করুন"</string>
- <string name="global_action_lock_message" product="device" msgid="538790401275363781">"আরও বিকল্প দেখতে আপনার ডিভাইস আনলক করুন"</string>
<string name="remote_input_image_insertion_text" msgid="4850791636452521123">"একটি ছবি পাঠানো হয়েছে"</string>
<string name="screenshot_saving_ticker" msgid="6519186952674544916">"স্ক্রিনশট সেভ করা হচ্ছে..."</string>
<string name="screenshot_saving_title" msgid="2298349784913287333">"স্ক্রিনশট সেভ করা হচ্ছে..."</string>
@@ -722,7 +719,7 @@
<string name="notification_channel_summary_priority" msgid="7952654515769021553">"কথোপকথন বিভাগের উপরে ভাসমান বাবলের মতো দেখা যাবে, লক স্ক্রিনে প্রোফাইল ছবি দেখাবে"</string>
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"সেটিংস"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"অগ্রাধিকার"</string>
- <string name="no_shortcut" msgid="7176375126961212514">"<xliff:g id="APP_NAME">%1$s</xliff:g> অ্যাপে কথোপকথনের ক্ষেত্রে প্রযোজ্য সেটিংস কাজ করে না"</string>
+ <string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g>-এ কথোপকথন ফিচার কাজ করে না"</string>
<string name="bubble_overflow_empty_title" msgid="3120029421991510842">"কোনও সাম্প্রতিক বাবল নেই"</string>
<string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"সাম্প্রতিক ও বাতিল করা বাবল এখানে দেখা যাবে"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"এই বিজ্ঞপ্তিগুলি পরিবর্তন করা যাবে না।"</string>
@@ -1005,7 +1002,8 @@
<string name="bubble_accessibility_action_move_top_right" msgid="6916868852433483569">"উপরে ডানদিকে সরান"</string>
<string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"নিচে বাঁদিকে সরান"</string>
<string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"নিচে ডান দিকে সরান"</string>
- <string name="bubble_dismiss_text" msgid="7071770411580452911">"খারিজ করুন"</string>
+ <!-- no translation found for bubble_dismiss_text (1314082410868930066) -->
+ <skip />
<string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"কথোপকথন বাবল হিসেবে দেখাবে না"</string>
<string name="bubbles_user_education_title" msgid="5547017089271445797">"বাবল ব্যবহার করে চ্যাট করুন"</string>
<string name="bubbles_user_education_description" msgid="1160281719576715211">"নতুন কথোপকথন ভেসে থাকা আইকন বা বাবল হিসেবে দেখানো হয়। বাবল খুলতে ট্যাপ করুন। সেটি সরাতে ধরে টেনে আনুন।"</string>
@@ -1016,11 +1014,14 @@
<string name="notification_content_system_nav_changed" msgid="5077913144844684544">"সিস্টেম নেভিগেশন আপডেট হয়েছে। পরিবর্তন করার জন্য সেটিংসে যান।"</string>
<string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"সিস্টেম নেভিগেশন আপডেট করতে সেটিংসে যান"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"স্ট্যান্ডবাই"</string>
+ <string name="priority_onboarding_title" msgid="2893070698479227616">"কথোপকথনকে \'গুরুত্বপূর্ণ\' হিসেবে সেট করা হয়েছে"</string>
+ <string name="priority_onboarding_behavior" msgid="5342816047020432929">"গুরুত্বপূর্ণ কথোপকথন:"</string>
<string name="priority_onboarding_show_at_top_text" msgid="1678400241025513541">"কথোপকথনের বিভাগের উপরে দেখান"</string>
<string name="priority_onboarding_show_avatar_text" msgid="5756291381124091508">"লক স্ক্রিনে প্রোফাইল ছবি দেখান"</string>
<string name="priority_onboarding_appear_as_bubble_text" msgid="4227039772250263122">"অ্যাপের উপরে একটি ভাসমান বুদবুদ হিসেবে দেখা যাবে"</string>
<string name="priority_onboarding_ignores_dnd_text" msgid="2918952762719600529">"বিরক্ত করবে না মোডে ব্যাঘাত ঘটাতে পারে"</string>
<string name="priority_onboarding_done_button_title" msgid="4569550984286506007">"বুঝেছি"</string>
+ <string name="priority_onboarding_settings_button_title" msgid="6663601574303585927">"সেটিংস"</string>
<string name="magnification_overlay_title" msgid="6584179429612427958">"ওভারলে উইন্ডো বড় করে দেখা"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"উইন্ডো বড় করে দেখা"</string>
<string name="magnification_controls_title" msgid="8421106606708891519">"উইন্ডো কন্ট্রোল বড় করে দেখা"</string>
@@ -1062,9 +1063,13 @@
<string name="controls_structure_tooltip" msgid="4355922222944447867">"আরও দেখতে সোয়াইপ করুন"</string>
<string name="controls_seeding_in_progress" msgid="3033855341410264148">"সাজেশন লোড করা হচ্ছে"</string>
<string name="controls_media_close_session" msgid="9023534788828414585">"এই মিডিয়া সেশন বেছে নিন"</string>
+ <string name="controls_media_resume" msgid="1933520684481586053">"আবার চালু করুন"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"বন্ধ আছে, অ্যাপ চেক করুন"</string>
<string name="controls_error_retryable" msgid="864025882878378470">"সমস্যা, আবার চেষ্টা করা হচ্ছে…"</string>
- <string name="controls_error_removed" msgid="6299213591234723805">"ডিভাইস সরিয়ে দেওয়া হয়েছে"</string>
+ <string name="controls_error_removed" msgid="6675638069846014366">"খুঁজে পাওয়া যায়নি"</string>
+ <string name="controls_error_removed_title" msgid="1207794911208047818">"কন্ট্রোল উপলভ্য নেই"</string>
+ <string name="controls_error_removed_message" msgid="2885911717034750542">"<xliff:g id="DEVICE">%1$s</xliff:g> ডিভাইস অ্যাক্সেস করা যায়নি। <xliff:g id="APPLICATION">%2$s</xliff:g> অ্যাপ চেক করে দেখুন যাতে এটি নিশ্চিত করে নিতে পারেন যে কন্ট্রোল এখনও উপলভ্য আছে এবং অ্যাপ সেটিংসে কোনও পরিবর্তন করা হয়নি।"</string>
+ <string name="controls_open_app" msgid="483650971094300141">"অ্যাপ খুলুন"</string>
<string name="controls_error_generic" msgid="352500456918362905">"স্ট্যাটাস লোড করা যাচ্ছে না"</string>
<string name="controls_error_failed" msgid="960228639198558525">"সমস্যা হয়েছে, আবার চেষ্টা করুন"</string>
<string name="controls_in_progress" msgid="4421080500238215939">"চলছে"</string>
diff --git a/packages/SystemUI/res/values-bs/strings.xml b/packages/SystemUI/res/values-bs/strings.xml
index a25a917b23ae..37397f959aea 100644
--- a/packages/SystemUI/res/values-bs/strings.xml
+++ b/packages/SystemUI/res/values-bs/strings.xml
@@ -77,9 +77,6 @@
<string name="compat_mode_on" msgid="4963711187149440884">"Uvećaj prikaz na ekran"</string>
<string name="compat_mode_off" msgid="7682459748279487945">"Razvuci prikaz na ekran"</string>
<string name="global_action_screenshot" msgid="2760267567509131654">"Snimak ekrana"</string>
- <string name="global_action_lock_message" product="default" msgid="4466026255205186456">"Otključajte telefon za više opcija"</string>
- <string name="global_action_lock_message" product="tablet" msgid="7621167597240332986">"Otključajte tablet za više opcija"</string>
- <string name="global_action_lock_message" product="device" msgid="538790401275363781">"Otključajte uređaj za više opcija"</string>
<string name="remote_input_image_insertion_text" msgid="4850791636452521123">"je poslao/la sliku"</string>
<string name="screenshot_saving_ticker" msgid="6519186952674544916">"Spašavanje snimka ekrana..."</string>
<string name="screenshot_saving_title" msgid="2298349784913287333">"Spašavanje snimka ekrana..."</string>
@@ -95,13 +92,13 @@
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Obrađivanje snimka ekrana"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"Obavještenje za sesiju snimanja ekrana je u toku"</string>
<string name="screenrecord_start_label" msgid="1750350278888217473">"Započeti snimanje?"</string>
- <string name="screenrecord_description" msgid="1123231719680353736">"Prilikom snimanja, sistem Android može snimiti sve osjetljive informacije koje su vidljive na vašem ekranu ili koje reproducirate na uređaju. To uključuje lozinke, informacije za plaćanje, fotografije, poruke i zvuk."</string>
+ <string name="screenrecord_description" msgid="1123231719680353736">"Prilikom snimanja, Android sistem može snimiti sve osjetljive informacije koje su vidljive na vašem ekranu ili koje reproducirate na uređaju. To uključuje lozinke, informacije za plaćanje, fotografije, poruke i zvuk."</string>
<string name="screenrecord_audio_label" msgid="6183558856175159629">"Snimi zvučni zapis"</string>
<string name="screenrecord_device_audio_label" msgid="9016927171280567791">"Zvuk uređaja"</string>
<string name="screenrecord_device_audio_description" msgid="4922694220572186193">"Zvuk s vašeg uređaja, naprimjer muzika, pozivi i melodije zvona"</string>
<string name="screenrecord_mic_label" msgid="2111264835791332350">"Mikrofon"</string>
<string name="screenrecord_device_audio_and_mic_label" msgid="1831323771978646841">"Zvuk i mikrofon uređaja"</string>
- <string name="screenrecord_start" msgid="330991441575775004">"Počni"</string>
+ <string name="screenrecord_start" msgid="330991441575775004">"Započni"</string>
<string name="screenrecord_ongoing_screen_only" msgid="4459670242451527727">"Snimanje ekrana"</string>
<string name="screenrecord_ongoing_screen_and_audio" msgid="5351133763125180920">"Snimanje ekrana i zvuka"</string>
<string name="screenrecord_taps_label" msgid="1595690528298857649">"Prikaži dodire na ekranu"</string>
@@ -727,7 +724,7 @@
<string name="notification_channel_summary_priority" msgid="7952654515769021553">"Prikazuje se na vrhu odjeljka za razgovor, pojavljuje se kao plutajući oblačić, prikazuje sliku profila na zaključanom ekranu"</string>
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"Postavke"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"Prioritetni"</string>
- <string name="no_shortcut" msgid="7176375126961212514">"Aplikacija <xliff:g id="APP_NAME">%1$s</xliff:g> ne podržava postavke za određeni razgovor"</string>
+ <string name="no_shortcut" msgid="8257177117568230126">"Aplikacija <xliff:g id="APP_NAME">%1$s</xliff:g> ne podržava funkcije razgovora"</string>
<string name="bubble_overflow_empty_title" msgid="3120029421991510842">"Nema nedavnih oblačića"</string>
<string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"Nedavni i odbačeni oblačići će se pojaviti ovdje"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"Ta obavještenja se ne mogu izmijeniti."</string>
@@ -1012,7 +1009,8 @@
<string name="bubble_accessibility_action_move_top_right" msgid="6916868852433483569">"Pomjerite gore desno"</string>
<string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"Pomjeri dolje lijevo"</string>
<string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"Pomjerite dolje desno"</string>
- <string name="bubble_dismiss_text" msgid="7071770411580452911">"Odbaci"</string>
+ <!-- no translation found for bubble_dismiss_text (1314082410868930066) -->
+ <skip />
<string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"Nemoj prikazivati razgovor u oblačićima"</string>
<string name="bubbles_user_education_title" msgid="5547017089271445797">"Chatajte koristeći oblačiće"</string>
<string name="bubbles_user_education_description" msgid="1160281719576715211">"Novi razgovori se prikazuju kao plutajuće ikone ili oblačići. Dodirnite da otvorite oblačić. Prevucite da ga premjestite."</string>
@@ -1023,16 +1021,19 @@
<string name="notification_content_system_nav_changed" msgid="5077913144844684544">"Navigiranje sistemom je ažurirano. Da izvršite promjene, idite u Postavke."</string>
<string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"Idite u Postavke da ažurirate navigiranje sistemom"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Stanje mirovanja"</string>
+ <string name="priority_onboarding_title" msgid="2893070698479227616">"Razgovor je postavljen kao prioritetan"</string>
+ <string name="priority_onboarding_behavior" msgid="5342816047020432929">"Prioritetni razgovori će:"</string>
<string name="priority_onboarding_show_at_top_text" msgid="1678400241025513541">"Prikazuje se na vrhu odjeljka za razgovor"</string>
<string name="priority_onboarding_show_avatar_text" msgid="5756291381124091508">"Prikazuje sliku profila na zaključanom ekranu"</string>
<string name="priority_onboarding_appear_as_bubble_text" msgid="4227039772250263122">"Izgleda kao plutajući oblačić iznad aplikacija"</string>
<string name="priority_onboarding_ignores_dnd_text" msgid="2918952762719600529">"Prekida način rada Ne ometaj"</string>
<string name="priority_onboarding_done_button_title" msgid="4569550984286506007">"Razumijem"</string>
+ <string name="priority_onboarding_settings_button_title" msgid="6663601574303585927">"Postavke"</string>
<string name="magnification_overlay_title" msgid="6584179429612427958">"Preklopni prozor za uvećavanje"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"Prozor za uvećavanje"</string>
<string name="magnification_controls_title" msgid="8421106606708891519">"Kontrole prozora za uvećavanje"</string>
<string name="quick_controls_title" msgid="6839108006171302273">"Kontrole uređaja"</string>
- <string name="quick_controls_subtitle" msgid="1667408093326318053">"Dodavanje kontrola za povezane uređaje"</string>
+ <string name="quick_controls_subtitle" msgid="1667408093326318053">"Dodajte kontrole za povezane uređaje"</string>
<string name="quick_controls_setup_title" msgid="8901436655997849822">"Postavite kontrole uređaja"</string>
<string name="quick_controls_setup_subtitle" msgid="1681506617879773824">"Držite dugme za uključivanje da pristupite kontrolama"</string>
<string name="controls_providers_title" msgid="6879775889857085056">"Odaberite aplikaciju da dodate kontrole"</string>
@@ -1060,7 +1061,7 @@
<string name="controls_dialog_message" msgid="342066938390663844">"Predlaže <xliff:g id="APP">%s</xliff:g>"</string>
<string name="controls_dialog_confirmation" msgid="586517302736263447">"Kontrole su ažurirane"</string>
<string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"PIN sadrži slova ili simbole"</string>
- <string name="controls_pin_verify" msgid="3452778292918877662">"Potvrdite <xliff:g id="DEVICE">%s</xliff:g>"</string>
+ <string name="controls_pin_verify" msgid="3452778292918877662">"Potvrdite uređaj <xliff:g id="DEVICE">%s</xliff:g>"</string>
<string name="controls_pin_wrong" msgid="6162694056042164211">"Pogrešan PIN"</string>
<string name="controls_pin_verifying" msgid="3755045989392131746">"Potvrđivanje…"</string>
<string name="controls_pin_instructions" msgid="6363309783822475238">"Unesite PIN"</string>
@@ -1070,13 +1071,17 @@
<string name="controls_structure_tooltip" msgid="4355922222944447867">"Prevucite da vidite više"</string>
<string name="controls_seeding_in_progress" msgid="3033855341410264148">"Učitavanje preporuka"</string>
<string name="controls_media_close_session" msgid="9023534788828414585">"Zatvori ovu medijsku sesiju"</string>
+ <string name="controls_media_resume" msgid="1933520684481586053">"Nastavi"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"Neaktivno, vidite aplikaciju"</string>
<string name="controls_error_retryable" msgid="864025882878378470">"Greška, ponovni pokušaj…"</string>
- <string name="controls_error_removed" msgid="6299213591234723805">"Uređaj je uklonjen"</string>
+ <string name="controls_error_removed" msgid="6675638069846014366">"Nije pronađeno"</string>
+ <string name="controls_error_removed_title" msgid="1207794911208047818">"Kontrola nije dostupna"</string>
+ <string name="controls_error_removed_message" msgid="2885911717034750542">"Pristup uređaju <xliff:g id="DEVICE">%1$s</xliff:g> nije uspio. Provjerite aplikaciju <xliff:g id="APPLICATION">%2$s</xliff:g> da se uvjerite da je kontrola i dalje dostupna i da se postavke aplikacije nisu promijenile."</string>
+ <string name="controls_open_app" msgid="483650971094300141">"Otvori aplikaciju"</string>
<string name="controls_error_generic" msgid="352500456918362905">"Nije moguće učitati status"</string>
<string name="controls_error_failed" msgid="960228639198558525">"Greška, pokušajte ponovo"</string>
<string name="controls_in_progress" msgid="4421080500238215939">"U toku"</string>
<string name="controls_added_tooltip" msgid="4842812921719153085">"Zadržite dugme za uključivanje da vidite nove kontrole"</string>
- <string name="controls_menu_add" msgid="4447246119229920050">"Dodavanje kontrola"</string>
- <string name="controls_menu_edit" msgid="890623986951347062">"Uređivanje kontrola"</string>
+ <string name="controls_menu_add" msgid="4447246119229920050">"Dodaj kontrole"</string>
+ <string name="controls_menu_edit" msgid="890623986951347062">"Uredi kontrole"</string>
</resources>
diff --git a/packages/SystemUI/res/values-ca/strings.xml b/packages/SystemUI/res/values-ca/strings.xml
index 436776f68414..2fdddf710e13 100644
--- a/packages/SystemUI/res/values-ca/strings.xml
+++ b/packages/SystemUI/res/values-ca/strings.xml
@@ -77,9 +77,6 @@
<string name="compat_mode_on" msgid="4963711187149440884">"Zoom per omplir pantalla"</string>
<string name="compat_mode_off" msgid="7682459748279487945">"Estira per omplir pant."</string>
<string name="global_action_screenshot" msgid="2760267567509131654">"Captura de pantalla"</string>
- <string name="global_action_lock_message" product="default" msgid="4466026255205186456">"Desbloqueja el teu telèfon per veure més opcions"</string>
- <string name="global_action_lock_message" product="tablet" msgid="7621167597240332986">"Desbloqueja la teva tauleta per veure més opcions"</string>
- <string name="global_action_lock_message" product="device" msgid="538790401275363781">"Desbloqueja el teu dispositiu per veure més opcions"</string>
<string name="remote_input_image_insertion_text" msgid="4850791636452521123">"ha enviat una imatge"</string>
<string name="screenshot_saving_ticker" msgid="6519186952674544916">"S\'està desant captura de pantalla..."</string>
<string name="screenshot_saving_title" msgid="2298349784913287333">"S\'està desant la captura de pantalla..."</string>
@@ -333,7 +330,7 @@
<item quantity="one"><xliff:g id="NUMBER_0">%s</xliff:g> notificació més a l\'interior.</item>
</plurals>
<string name="notification_summary_message_format" msgid="5158219088501909966">"<xliff:g id="CONTACT_NAME">%1$s</xliff:g>: <xliff:g id="MESSAGE_CONTENT">%2$s</xliff:g>"</string>
- <string name="status_bar_notification_inspect_item_title" msgid="6818779631806163080">"Configuració de les notificacions"</string>
+ <string name="status_bar_notification_inspect_item_title" msgid="6818779631806163080">"Configuració de notificacions"</string>
<string name="status_bar_notification_app_settings_title" msgid="5050006438806013903">"Configuració de l\'aplicació <xliff:g id="APP_NAME">%s</xliff:g>"</string>
<string name="accessibility_rotation_lock_off" msgid="3880436123632448930">"La pantalla girarà automàticament."</string>
<string name="accessibility_rotation_lock_on_landscape" msgid="936972553861524360">"La pantalla està bloquejada en orientació horitzontal."</string>
@@ -722,7 +719,7 @@
<string name="notification_channel_summary_priority" msgid="7952654515769021553">"Es mostra com a bombolla flotant a la part superior de la secció de converses i mostra la foto de perfil a la pantalla de bloqueig"</string>
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"Configuració"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"Prioritat"</string>
- <string name="no_shortcut" msgid="7176375126961212514">"<xliff:g id="APP_NAME">%1$s</xliff:g> no admet opcions de configuració específiques de converses"</string>
+ <string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> no admet les funcions de converses"</string>
<string name="bubble_overflow_empty_title" msgid="3120029421991510842">"No hi ha bombolles recents"</string>
<string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"Les bombolles recents i les ignorades es mostraran aquí"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"Aquestes notificacions no es poden modificar."</string>
@@ -1005,7 +1002,8 @@
<string name="bubble_accessibility_action_move_top_right" msgid="6916868852433483569">"Mou a dalt a la dreta"</string>
<string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"Mou a baix a l\'esquerra"</string>
<string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"Mou a baix a la dreta"</string>
- <string name="bubble_dismiss_text" msgid="7071770411580452911">"Omet"</string>
+ <!-- no translation found for bubble_dismiss_text (1314082410868930066) -->
+ <skip />
<string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"No mostris la conversa com a bombolla"</string>
<string name="bubbles_user_education_title" msgid="5547017089271445797">"Xateja utilitzant les bombolles"</string>
<string name="bubbles_user_education_description" msgid="1160281719576715211">"Les converses noves es mostren com a icones flotants o bombolles. Toca per obrir una bombolla. Arrossega-la per moure-la."</string>
@@ -1016,11 +1014,14 @@
<string name="notification_content_system_nav_changed" msgid="5077913144844684544">"S\'ha actualitzat el sistema de navegació. Per fer canvis, ves a Configuració."</string>
<string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"Ves a Configuració per actualitzar el sistema de navegació"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"En espera"</string>
+ <string name="priority_onboarding_title" msgid="2893070698479227616">"La conversa s\'ha definit com a prioritària"</string>
+ <string name="priority_onboarding_behavior" msgid="5342816047020432929">"Les converses prioritàries:"</string>
<string name="priority_onboarding_show_at_top_text" msgid="1678400241025513541">"Mostra a la part superior de la secció de converses"</string>
<string name="priority_onboarding_show_avatar_text" msgid="5756291381124091508">"Mostra la foto de perfil a la pantalla de bloqueig"</string>
<string name="priority_onboarding_appear_as_bubble_text" msgid="4227039772250263122">"Es mostra com a bombolla flotant en primer pla"</string>
<string name="priority_onboarding_ignores_dnd_text" msgid="2918952762719600529">"Interromp el mode No molestis"</string>
<string name="priority_onboarding_done_button_title" msgid="4569550984286506007">"Entesos"</string>
+ <string name="priority_onboarding_settings_button_title" msgid="6663601574303585927">"Configuració"</string>
<string name="magnification_overlay_title" msgid="6584179429612427958">"Finestra superposada d\'ampliació"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"Finestra d\'ampliació"</string>
<string name="magnification_controls_title" msgid="8421106606708891519">"Finestra de controls d\'ampliació"</string>
@@ -1062,9 +1063,13 @@
<string name="controls_structure_tooltip" msgid="4355922222944447867">"Llisca per veure\'n més"</string>
<string name="controls_seeding_in_progress" msgid="3033855341410264148">"Carregant les recomanacions"</string>
<string name="controls_media_close_session" msgid="9023534788828414585">"Tanca aquesta sessió multimèdia"</string>
+ <string name="controls_media_resume" msgid="1933520684481586053">"Reprèn"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"Inactiu; comprova l\'aplicació"</string>
<string name="controls_error_retryable" msgid="864025882878378470">"Error. S\'està tornant a provar…"</string>
- <string name="controls_error_removed" msgid="6299213591234723805">"El dispositiu s\'ha suprimit"</string>
+ <string name="controls_error_removed" msgid="6675638069846014366">"No s\'ha trobat"</string>
+ <string name="controls_error_removed_title" msgid="1207794911208047818">"El control no està disponible"</string>
+ <string name="controls_error_removed_message" msgid="2885911717034750542">"No s\'ha pogut accedir a <xliff:g id="DEVICE">%1$s</xliff:g>. Consulta l\'aplicació <xliff:g id="APPLICATION">%2$s</xliff:g> per assegurar-te que el control encara estigui disponible i que la configuració de l\'aplicació no hagi canviat."</string>
+ <string name="controls_open_app" msgid="483650971094300141">"Obre l\'aplicació"</string>
<string name="controls_error_generic" msgid="352500456918362905">"No es pot carregar l\'estat"</string>
<string name="controls_error_failed" msgid="960228639198558525">"Error; torna-ho a provar"</string>
<string name="controls_in_progress" msgid="4421080500238215939">"En curs"</string>
diff --git a/packages/SystemUI/res/values-cs/strings.xml b/packages/SystemUI/res/values-cs/strings.xml
index 1bd6dec8d7d3..18012b5e4280 100644
--- a/packages/SystemUI/res/values-cs/strings.xml
+++ b/packages/SystemUI/res/values-cs/strings.xml
@@ -77,9 +77,6 @@
<string name="compat_mode_on" msgid="4963711187149440884">"Přiblížit na celou obrazovku"</string>
<string name="compat_mode_off" msgid="7682459748279487945">"Na celou obrazovku"</string>
<string name="global_action_screenshot" msgid="2760267567509131654">"Snímek obrazovky"</string>
- <string name="global_action_lock_message" product="default" msgid="4466026255205186456">"Chcete-li zobrazit další možnosti, odemkněte telefon"</string>
- <string name="global_action_lock_message" product="tablet" msgid="7621167597240332986">"Chcete-li zobrazit další možnosti, odemkněte tablet"</string>
- <string name="global_action_lock_message" product="device" msgid="538790401275363781">"Chcete-li zobrazit další možnosti, odemkněte zařízení"</string>
<string name="remote_input_image_insertion_text" msgid="4850791636452521123">"odesílá obrázek"</string>
<string name="screenshot_saving_ticker" msgid="6519186952674544916">"Ukládání snímku obrazovky..."</string>
<string name="screenshot_saving_title" msgid="2298349784913287333">"Ukládání snímku obrazovky..."</string>
@@ -728,7 +725,7 @@
<string name="notification_channel_summary_priority" msgid="7952654515769021553">"Zobrazuje se v horní části sekce konverzace a má podobu plovoucí bubliny, zobrazuje profilovou fotku na obrazovce uzamčení"</string>
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"Nastavení"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"Priorita"</string>
- <string name="no_shortcut" msgid="7176375126961212514">"Aplikace <xliff:g id="APP_NAME">%1$s</xliff:g> nepodporuje nastavení specifická pro konverzaci"</string>
+ <string name="no_shortcut" msgid="8257177117568230126">"Aplikace <xliff:g id="APP_NAME">%1$s</xliff:g> funkce konverzace nepodporuje"</string>
<string name="bubble_overflow_empty_title" msgid="3120029421991510842">"Žádné nedávné bubliny"</string>
<string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"Zde se budou zobrazovat nedávné bubliny a zavřené bubliny"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"Tato oznámení nelze upravit."</string>
@@ -1015,7 +1012,8 @@
<string name="bubble_accessibility_action_move_top_right" msgid="6916868852433483569">"Přesunout vpravo nahoru"</string>
<string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"Přesunout vlevo dolů"</string>
<string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"Přesunout vpravo dolů"</string>
- <string name="bubble_dismiss_text" msgid="7071770411580452911">"Zavřít"</string>
+ <!-- no translation found for bubble_dismiss_text (1314082410868930066) -->
+ <skip />
<string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"Nezobrazovat konverzaci v bublinách"</string>
<string name="bubbles_user_education_title" msgid="5547017089271445797">"Chatujte pomocí bublin"</string>
<string name="bubbles_user_education_description" msgid="1160281719576715211">"Nové konverzace se zobrazují jako plovoucí ikony, neboli bubliny. Klepnutím bublinu otevřete. Přetažením ji posunete."</string>
@@ -1026,11 +1024,14 @@
<string name="notification_content_system_nav_changed" msgid="5077913144844684544">"Systémová navigace byla aktualizována. Chcete-li provést změny, přejděte do Nastavení."</string>
<string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"Přejděte do Nastavení a aktualizujte systémovou navigaci"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Pohotovostní režim"</string>
+ <string name="priority_onboarding_title" msgid="2893070698479227616">"Konverzace byla nastavena jako prioritní"</string>
+ <string name="priority_onboarding_behavior" msgid="5342816047020432929">"Chování prioritních konverzací:"</string>
<string name="priority_onboarding_show_at_top_text" msgid="1678400241025513541">"Zobrazovat v horní části sekce konverzace"</string>
<string name="priority_onboarding_show_avatar_text" msgid="5756291381124091508">"Zobrazovat profilovou fotku na zámku obrazovky"</string>
<string name="priority_onboarding_appear_as_bubble_text" msgid="4227039772250263122">"Zobrazuje se jako plovoucí bublina nad aplikacemi"</string>
<string name="priority_onboarding_ignores_dnd_text" msgid="2918952762719600529">"Přerušit režim Nerušit"</string>
<string name="priority_onboarding_done_button_title" msgid="4569550984286506007">"Rozumím"</string>
+ <string name="priority_onboarding_settings_button_title" msgid="6663601574303585927">"Nastavení"</string>
<string name="magnification_overlay_title" msgid="6584179429612427958">"Překryvné zvětšovací okno"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"Zvětšovací okno"</string>
<string name="magnification_controls_title" msgid="8421106606708891519">"Ovládací prvky zvětšovacího okna"</string>
@@ -1074,9 +1075,13 @@
<string name="controls_structure_tooltip" msgid="4355922222944447867">"Přejetím prstem zobrazíte další položky"</string>
<string name="controls_seeding_in_progress" msgid="3033855341410264148">"Načítání doporučení"</string>
<string name="controls_media_close_session" msgid="9023534788828414585">"Zavřít tuto mediální relaci"</string>
+ <string name="controls_media_resume" msgid="1933520684481586053">"Pokračovat"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"Neaktivní, zkontrolujte aplikaci"</string>
<string name="controls_error_retryable" msgid="864025882878378470">"Chyba. Nový pokus…"</string>
- <string name="controls_error_removed" msgid="6299213591234723805">"Zařízení bylo odebráno"</string>
+ <string name="controls_error_removed" msgid="6675638069846014366">"Nenalezeno"</string>
+ <string name="controls_error_removed_title" msgid="1207794911208047818">"Ovládání není k dispozici"</string>
+ <string name="controls_error_removed_message" msgid="2885911717034750542">"Zařízení <xliff:g id="DEVICE">%1$s</xliff:g> nelze použít. V aplikaci <xliff:g id="APPLICATION">%2$s</xliff:g> zkontrolujte, zda je ovládání stále k dispozici a zda se nezměnilo nastavení."</string>
+ <string name="controls_open_app" msgid="483650971094300141">"Otevřít aplikaci"</string>
<string name="controls_error_generic" msgid="352500456918362905">"Stav nelze načíst"</string>
<string name="controls_error_failed" msgid="960228639198558525">"Chyba, zkuste to znovu"</string>
<string name="controls_in_progress" msgid="4421080500238215939">"Probíhá"</string>
diff --git a/packages/SystemUI/res/values-da/strings.xml b/packages/SystemUI/res/values-da/strings.xml
index a463aac1fb6d..3f71e3d49137 100644
--- a/packages/SystemUI/res/values-da/strings.xml
+++ b/packages/SystemUI/res/values-da/strings.xml
@@ -77,9 +77,6 @@
<string name="compat_mode_on" msgid="4963711187149440884">"Zoom til fuld skærm"</string>
<string name="compat_mode_off" msgid="7682459748279487945">"Stræk til fuld skærm"</string>
<string name="global_action_screenshot" msgid="2760267567509131654">"Screenshot"</string>
- <string name="global_action_lock_message" product="default" msgid="4466026255205186456">"Lås din telefon op for at se flere valgmuligheder"</string>
- <string name="global_action_lock_message" product="tablet" msgid="7621167597240332986">"Lås din tablet op for at se flere valgmuligheder"</string>
- <string name="global_action_lock_message" product="device" msgid="538790401275363781">"Lås din enhed op for at se flere valgmuligheder"</string>
<string name="remote_input_image_insertion_text" msgid="4850791636452521123">"sendte et billede"</string>
<string name="screenshot_saving_ticker" msgid="6519186952674544916">"Gemmer screenshot..."</string>
<string name="screenshot_saving_title" msgid="2298349784913287333">"Gemmer screenshot..."</string>
@@ -595,29 +592,21 @@
<string name="volume_odi_captions_hint_enable" msgid="2073091194012843195">"aktivér"</string>
<string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"deaktiver"</string>
<string name="accessibility_output_chooser" msgid="7807898688967194183">"Skift enhed til lydudgang"</string>
- <!-- no translation found for screen_pinning_title (9058007390337841305) -->
- <skip />
+ <string name="screen_pinning_title" msgid="9058007390337841305">"Appen er fastgjort"</string>
<string name="screen_pinning_description" msgid="8699395373875667743">"Dette fastholder skærmen i visningen, indtil du frigør den. Tryk på Tilbage og Overblik, og hold fingeren nede for at frigøre skærmen."</string>
<string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"Dette fastholder skærmen i visningen, indtil du frigør den. Hold Tilbage og Startskærm nede for at frigøre skærmen."</string>
<string name="screen_pinning_description_gestural" msgid="7246323931831232068">"Dette fastholder skærmen i visningen, indtil du frigør den. Stryg opad, og hold fingeren nede for at frigøre den."</string>
<string name="screen_pinning_description_accessible" msgid="7386449191953535332">"Dette fastholder skærmen i visningen, indtil du frigør den. Tryk på Tilbage, og hold fingeren nede for at frigøre skærmen."</string>
<string name="screen_pinning_description_recents_invisible_accessible" msgid="2857071808674481986">"Dette fastholder skærmen i visningen, indtil du frigør den. Hold Startskærm nede for at frigøre skærmen."</string>
- <!-- no translation found for screen_pinning_exposes_personal_data (8189852022981524789) -->
- <skip />
- <!-- no translation found for screen_pinning_can_open_other_apps (7529756813231421455) -->
- <skip />
- <!-- no translation found for screen_pinning_toast (8177286912533744328) -->
- <skip />
- <!-- no translation found for screen_pinning_toast_recents_invisible (6850978077443052594) -->
- <skip />
- <!-- no translation found for screen_pinning_toast_gesture_nav (170699893395336705) -->
- <skip />
+ <string name="screen_pinning_exposes_personal_data" msgid="8189852022981524789">"Personoplysninger er muligvis tilgængelige (f.eks. kontakter og mailindhold)."</string>
+ <string name="screen_pinning_can_open_other_apps" msgid="7529756813231421455">"En fastgjort app kan åbne andre apps."</string>
+ <string name="screen_pinning_toast" msgid="8177286912533744328">"Du kan frigøre denne app ved at holde knapperne Tilbage og Oversigt nede"</string>
+ <string name="screen_pinning_toast_recents_invisible" msgid="6850978077443052594">"Du kan frigøre denne app ved at holde knapperne Tilbage og Hjem nede"</string>
+ <string name="screen_pinning_toast_gesture_nav" msgid="170699893395336705">"Du kan frigøre denne app ved at stryge opad og holde fingeren nede"</string>
<string name="screen_pinning_positive" msgid="3285785989665266984">"OK"</string>
<string name="screen_pinning_negative" msgid="6882816864569211666">"Nej tak"</string>
- <!-- no translation found for screen_pinning_start (7483998671383371313) -->
- <skip />
- <!-- no translation found for screen_pinning_exit (4553787518387346893) -->
- <skip />
+ <string name="screen_pinning_start" msgid="7483998671383371313">"Appen er fastgjort"</string>
+ <string name="screen_pinning_exit" msgid="4553787518387346893">"Appen er frigjort"</string>
<string name="quick_settings_reset_confirmation_title" msgid="463533331480997595">"Vil du skjule <xliff:g id="TILE_LABEL">%1$s</xliff:g>?"</string>
<string name="quick_settings_reset_confirmation_message" msgid="2320586180785674186">"Den vises igen, næste gang du aktiverer den i indstillingerne."</string>
<string name="quick_settings_reset_confirmation_button" msgid="3341477479055016776">"Skjul"</string>
@@ -730,7 +719,7 @@
<string name="notification_channel_summary_priority" msgid="7952654515769021553">"Vises øverst i samtalesektionen, som en svævende boble og med profilbillede på låseskærmen"</string>
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"Indstillinger"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"Prioritet"</string>
- <string name="no_shortcut" msgid="7176375126961212514">"<xliff:g id="APP_NAME">%1$s</xliff:g> understøtter ikke samtalespecifikke indstillinger"</string>
+ <string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> understøtter ikke samtalefunktioner"</string>
<string name="bubble_overflow_empty_title" msgid="3120029421991510842">"Ingen seneste bobler"</string>
<string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"Nye bobler og afviste bobler vises her"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"Disse notifikationer kan ikke redigeres."</string>
@@ -1013,7 +1002,8 @@
<string name="bubble_accessibility_action_move_top_right" msgid="6916868852433483569">"Flyt op til højre"</string>
<string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"Flyt ned til venstre"</string>
<string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"Flyt ned til højre"</string>
- <string name="bubble_dismiss_text" msgid="7071770411580452911">"Afvis"</string>
+ <!-- no translation found for bubble_dismiss_text (1314082410868930066) -->
+ <skip />
<string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"Vis ikke samtaler i bobler"</string>
<string name="bubbles_user_education_title" msgid="5547017089271445797">"Chat ved hjælp af bobler"</string>
<string name="bubbles_user_education_description" msgid="1160281719576715211">"Nye samtaler vises som svævende ikoner eller bobler. Tryk for at åbne boblen. Træk for at flytte den."</string>
@@ -1024,19 +1014,22 @@
<string name="notification_content_system_nav_changed" msgid="5077913144844684544">"Systemnavigationen blev opdateret. Gå til Indstillinger for at foretage ændringer."</string>
<string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"Gå til Indstillinger for at opdatere systemnavigationen"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Standby"</string>
+ <string name="priority_onboarding_title" msgid="2893070698479227616">"Samtalen er angivet som prioritet"</string>
+ <string name="priority_onboarding_behavior" msgid="5342816047020432929">"Følgende gælder for prioriterede samtaler:"</string>
<string name="priority_onboarding_show_at_top_text" msgid="1678400241025513541">"Vis i toppen af samtalesektionen"</string>
<string name="priority_onboarding_show_avatar_text" msgid="5756291381124091508">"Vis profilbillede på låseskærm"</string>
<string name="priority_onboarding_appear_as_bubble_text" msgid="4227039772250263122">"Vis som en boble oven på apps"</string>
<string name="priority_onboarding_ignores_dnd_text" msgid="2918952762719600529">"Afbryd Forstyr ikke"</string>
<string name="priority_onboarding_done_button_title" msgid="4569550984286506007">"OK"</string>
+ <string name="priority_onboarding_settings_button_title" msgid="6663601574303585927">"Indstillinger"</string>
<string name="magnification_overlay_title" msgid="6584179429612427958">"Vindue med overlejret forstørrelse"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"Vindue med forstørrelse"</string>
<string name="magnification_controls_title" msgid="8421106606708891519">"Vindue med forstørrelsesstyring"</string>
<string name="quick_controls_title" msgid="6839108006171302273">"Enhedsstyring"</string>
- <string name="quick_controls_subtitle" msgid="1667408093326318053">"Tilføj betjeningselementer på dine tilsluttede enheder"</string>
+ <string name="quick_controls_subtitle" msgid="1667408093326318053">"Tilføj styring af dine tilsluttede enheder"</string>
<string name="quick_controls_setup_title" msgid="8901436655997849822">"Konfigurer enhedsstyring"</string>
<string name="quick_controls_setup_subtitle" msgid="1681506617879773824">"Hold afbryderknappen nede for at få adgang til dine betjeningselementer"</string>
- <string name="controls_providers_title" msgid="6879775889857085056">"Vælg en app for at tilføje betjeningselementer"</string>
+ <string name="controls_providers_title" msgid="6879775889857085056">"Vælg en app for at tilføje styring"</string>
<plurals name="controls_number_of_favorites" formatted="false" msgid="1057347832073807380">
<item quantity="one"><xliff:g id="NUMBER_1">%s</xliff:g> styringselement er tilføjet.</item>
<item quantity="other"><xliff:g id="NUMBER_1">%s</xliff:g> styringselementer er tilføjet.</item>
@@ -1070,13 +1063,17 @@
<string name="controls_structure_tooltip" msgid="4355922222944447867">"Stryg for at se mere"</string>
<string name="controls_seeding_in_progress" msgid="3033855341410264148">"Indlæser anbefalinger"</string>
<string name="controls_media_close_session" msgid="9023534788828414585">"Luk denne mediesession"</string>
+ <string name="controls_media_resume" msgid="1933520684481586053">"Genoptag"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"Inaktiv. Tjek appen"</string>
<string name="controls_error_retryable" msgid="864025882878378470">"Fejl. Prøver igen…"</string>
- <string name="controls_error_removed" msgid="6299213591234723805">"Enheden er fjernet"</string>
+ <string name="controls_error_removed" msgid="6675638069846014366">"Ikke fundet"</string>
+ <string name="controls_error_removed_title" msgid="1207794911208047818">"Styringselement ikke tilgængeligt"</string>
+ <string name="controls_error_removed_message" msgid="2885911717034750542">"Der kunne ikke skaffes adgang til <xliff:g id="DEVICE">%1$s</xliff:g>. Tjek <xliff:g id="APPLICATION">%2$s</xliff:g>-appen for at sikre at styringselementet stadig er tilgængeligt, og at appens indstillinger ikke er blevet ændret."</string>
+ <string name="controls_open_app" msgid="483650971094300141">"Åbn app"</string>
<string name="controls_error_generic" msgid="352500456918362905">"Statussen kan ikke indlæses"</string>
<string name="controls_error_failed" msgid="960228639198558525">"Der opstod en fejl. Prøv igen"</string>
<string name="controls_in_progress" msgid="4421080500238215939">"I gang"</string>
<string name="controls_added_tooltip" msgid="4842812921719153085">"Hold afbryderknappen nede for at se nye betjeningselementer"</string>
- <string name="controls_menu_add" msgid="4447246119229920050">"Tilføj betjeningselementer"</string>
- <string name="controls_menu_edit" msgid="890623986951347062">"Rediger betjeningselementer"</string>
+ <string name="controls_menu_add" msgid="4447246119229920050">"Tilføj styring"</string>
+ <string name="controls_menu_edit" msgid="890623986951347062">"Rediger styring"</string>
</resources>
diff --git a/packages/SystemUI/res/values-de/strings.xml b/packages/SystemUI/res/values-de/strings.xml
index 1a796e3291f4..075a496c244b 100644
--- a/packages/SystemUI/res/values-de/strings.xml
+++ b/packages/SystemUI/res/values-de/strings.xml
@@ -77,9 +77,6 @@
<string name="compat_mode_on" msgid="4963711187149440884">"Zoom auf Bildschirmgröße"</string>
<string name="compat_mode_off" msgid="7682459748279487945">"Auf Bildschirmgröße anpassen"</string>
<string name="global_action_screenshot" msgid="2760267567509131654">"Screenshot"</string>
- <string name="global_action_lock_message" product="default" msgid="4466026255205186456">"Entsperre dein Smartphone für weitere Optionen"</string>
- <string name="global_action_lock_message" product="tablet" msgid="7621167597240332986">"Entsperre dein Tablet für weitere Optionen"</string>
- <string name="global_action_lock_message" product="device" msgid="538790401275363781">"Entsperre dein Gerät für weitere Optionen"</string>
<string name="remote_input_image_insertion_text" msgid="4850791636452521123">"Bild gesendet"</string>
<string name="screenshot_saving_ticker" msgid="6519186952674544916">"Screenshot wird gespeichert..."</string>
<string name="screenshot_saving_title" msgid="2298349784913287333">"Screenshot wird gespeichert..."</string>
@@ -595,29 +592,21 @@
<string name="volume_odi_captions_hint_enable" msgid="2073091194012843195">"aktivieren"</string>
<string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"deaktivieren"</string>
<string name="accessibility_output_chooser" msgid="7807898688967194183">"Ausgabegerät wechseln"</string>
- <!-- no translation found for screen_pinning_title (9058007390337841305) -->
- <skip />
- <string name="screen_pinning_description" msgid="8699395373875667743">"Der Bildschirm bleibt so lange eingeblendet, bis du die Fixierung aufhebst. Berühre und halte dazu \"Zurück\" und \"Übersicht\"."</string>
- <string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"Der Bildschirm wird so lange angezeigt, bis du die Fixierung aufhebst. Berühre und halte dazu \"Zurück\" und \"Startbildschirm\"."</string>
- <string name="screen_pinning_description_gestural" msgid="7246323931831232068">"Der Bildschirm wird so lange angezeigt, bis du die Fixierung aufhebst. Dazu wischst du nach oben und hältst den Bildschirm gedrückt"</string>
- <string name="screen_pinning_description_accessible" msgid="7386449191953535332">"Der Bildschirm bleibt so lange eingeblendet, bis du die Fixierung aufhebst. Berühre und halte dazu \"Übersicht\"."</string>
- <string name="screen_pinning_description_recents_invisible_accessible" msgid="2857071808674481986">"Der Bildschirm wird so lange angezeigt, bis du die Fixierung aufhebst. Berühre und halte dazu \"Startbildschirm\"."</string>
- <!-- no translation found for screen_pinning_exposes_personal_data (8189852022981524789) -->
- <skip />
- <!-- no translation found for screen_pinning_can_open_other_apps (7529756813231421455) -->
- <skip />
- <!-- no translation found for screen_pinning_toast (8177286912533744328) -->
- <skip />
- <!-- no translation found for screen_pinning_toast_recents_invisible (6850978077443052594) -->
- <skip />
- <!-- no translation found for screen_pinning_toast_gesture_nav (170699893395336705) -->
- <skip />
+ <string name="screen_pinning_title" msgid="9058007390337841305">"App ist auf dem Bildschirm fixiert"</string>
+ <string name="screen_pinning_description" msgid="8699395373875667743">"Die App bleibt so lange auf dem Bildschirm fixiert, bis du die Fixierung aufhebst. Berühre und halte dazu \"Zurück\" und \"Übersicht\"."</string>
+ <string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"Die App bleibt so lange auf dem Bildschirm fixiert, bis du die Fixierung aufhebst. Berühre und halte dazu \"Zurück\" und \"Startbildschirm\"."</string>
+ <string name="screen_pinning_description_gestural" msgid="7246323931831232068">"Die App bleibt so lange auf dem Bildschirm fixiert, bis du die Fixierung aufhebst. Wische dazu nach oben und halte den Bildschirm gedrückt."</string>
+ <string name="screen_pinning_description_accessible" msgid="7386449191953535332">"Die App bleibt so lange auf dem Bildschirm fixiert, bis du die Fixierung aufhebst. Berühre und halte dazu \"Übersicht\"."</string>
+ <string name="screen_pinning_description_recents_invisible_accessible" msgid="2857071808674481986">"Die App bleibt so lange auf dem Bildschirm fixiert, bis du die Fixierung aufhebst. Berühre und halte dazu \"Startbildschirm\"."</string>
+ <string name="screen_pinning_exposes_personal_data" msgid="8189852022981524789">"Möglicherweise kann auf personenbezogene Daten (Kontakte, E-Mails usw.) zugegriffen werden."</string>
+ <string name="screen_pinning_can_open_other_apps" msgid="7529756813231421455">"Die fixierte App kann ggf. andere Apps öffnen."</string>
+ <string name="screen_pinning_toast" msgid="8177286912533744328">"Zum Aufheben der Fixierung dieser App \"Zurück\" und \"Übersicht\" halten"</string>
+ <string name="screen_pinning_toast_recents_invisible" msgid="6850978077443052594">"Zum Aufheben der Fixierung dieser App \"Zurück\" und \"Startbildschirm\" halten"</string>
+ <string name="screen_pinning_toast_gesture_nav" msgid="170699893395336705">"Zum Aufheben der Fixierung nach oben wischen und halten"</string>
<string name="screen_pinning_positive" msgid="3285785989665266984">"Ok"</string>
<string name="screen_pinning_negative" msgid="6882816864569211666">"Nein danke"</string>
- <!-- no translation found for screen_pinning_start (7483998671383371313) -->
- <skip />
- <!-- no translation found for screen_pinning_exit (4553787518387346893) -->
- <skip />
+ <string name="screen_pinning_start" msgid="7483998671383371313">"Bildschirm wurde fixiert"</string>
+ <string name="screen_pinning_exit" msgid="4553787518387346893">"Bildschirmfixierung aufgehoben"</string>
<string name="quick_settings_reset_confirmation_title" msgid="463533331480997595">"<xliff:g id="TILE_LABEL">%1$s</xliff:g> ausblenden?"</string>
<string name="quick_settings_reset_confirmation_message" msgid="2320586180785674186">"Sie wird wieder eingeblendet, wenn du sie in den Einstellungen erneut aktivierst."</string>
<string name="quick_settings_reset_confirmation_button" msgid="3341477479055016776">"Ausblenden"</string>
@@ -730,7 +719,7 @@
<string name="notification_channel_summary_priority" msgid="7952654515769021553">"Wird oben im Bereich \"Unterhaltungen\" als unverankerte Bubble mit einem Profilbild auf dem Sperrbildschirm angezeigt"</string>
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"Einstellungen"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"Priorität"</string>
- <string name="no_shortcut" msgid="7176375126961212514">"<xliff:g id="APP_NAME">%1$s</xliff:g> unterstützt keine unterhaltungsspezifischen Einstellungen"</string>
+ <string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> unterstützt keine Funktionen für Unterhaltungen"</string>
<string name="bubble_overflow_empty_title" msgid="3120029421991510842">"Keine kürzlich geschlossenen Bubbles"</string>
<string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"Hier werden aktuelle und geschlossene Bubbles angezeigt"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"Diese Benachrichtigungen können nicht geändert werden."</string>
@@ -1013,7 +1002,8 @@
<string name="bubble_accessibility_action_move_top_right" msgid="6916868852433483569">"Nach rechts oben verschieben"</string>
<string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"Nach unten links verschieben"</string>
<string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"Nach unten rechts verschieben"</string>
- <string name="bubble_dismiss_text" msgid="7071770411580452911">"Schließen"</string>
+ <!-- no translation found for bubble_dismiss_text (1314082410868930066) -->
+ <skip />
<string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"Unterhaltung nicht als Bubble anzeigen"</string>
<string name="bubbles_user_education_title" msgid="5547017089271445797">"Bubbles zum Chatten verwenden"</string>
<string name="bubbles_user_education_description" msgid="1160281719576715211">"Neue Unterhaltungen erscheinen als unverankerte Symbole, \"Bubbles\" genannt. Wenn du die Bubble öffnen möchtest, tippe sie an. Wenn du sie verschieben möchtest, zieh an ihr."</string>
@@ -1024,16 +1014,19 @@
<string name="notification_content_system_nav_changed" msgid="5077913144844684544">"Systemsteuerungseinstellungen wurden angepasst. Änderungen kannst du in den Einstellungen vornehmen."</string>
<string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"Gehe zu den Einstellungen, um die Systemsteuerung anzupassen"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Standby"</string>
+ <string name="priority_onboarding_title" msgid="2893070698479227616">"Unterhaltung als vorrangig eingestuft"</string>
+ <string name="priority_onboarding_behavior" msgid="5342816047020432929">"Vorrangige Unterhaltungen:"</string>
<string name="priority_onboarding_show_at_top_text" msgid="1678400241025513541">"Oben im Bereich \"Unterhaltungen\" anzeigen"</string>
<string name="priority_onboarding_show_avatar_text" msgid="5756291381124091508">"Profilbild auf Sperrbildschirm anzeigen"</string>
<string name="priority_onboarding_appear_as_bubble_text" msgid="4227039772250263122">"Unverankertes Infofeld über anderen Apps"</string>
<string name="priority_onboarding_ignores_dnd_text" msgid="2918952762719600529">"\"Bitte nicht stören\" unterbrechen"</string>
<string name="priority_onboarding_done_button_title" msgid="4569550984286506007">"OK"</string>
+ <string name="priority_onboarding_settings_button_title" msgid="6663601574303585927">"Einstellungen"</string>
<string name="magnification_overlay_title" msgid="6584179429612427958">"Overlay-Vergrößerungsfenster"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"Vergrößerungsfenster"</string>
<string name="magnification_controls_title" msgid="8421106606708891519">"Einstellungen für Vergrößerungsfenster"</string>
<string name="quick_controls_title" msgid="6839108006171302273">"Gerätesteuerung"</string>
- <string name="quick_controls_subtitle" msgid="1667408093326318053">"Karten für deine verbundenen Geräte hinzufügen"</string>
+ <string name="quick_controls_subtitle" msgid="1667408093326318053">"Steuerelemente für verbundene Geräte hinzufügen"</string>
<string name="quick_controls_setup_title" msgid="8901436655997849822">"Gerätesteuerung einrichten"</string>
<string name="quick_controls_setup_subtitle" msgid="1681506617879773824">"Halte die Ein-/Aus-Taste gedrückt, um auf die Steuerelemente zuzugreifen."</string>
<string name="controls_providers_title" msgid="6879775889857085056">"App zum Hinzufügen von Steuerelementen auswählen"</string>
@@ -1049,7 +1042,7 @@
<string name="accessibility_control_change_unfavorite" msgid="6997408061750740327">"Zum Entfernen aus Favoriten"</string>
<string name="accessibility_control_move" msgid="8980344493796647792">"Auf Position <xliff:g id="NUMBER">%d</xliff:g> verschieben"</string>
<string name="controls_favorite_default_title" msgid="967742178688938137">"Steuerelemente"</string>
- <string name="controls_favorite_subtitle" msgid="6604402232298443956">"Karten auswählen, auf die man über das Ein-/Aus-Menü zugreifen kann"</string>
+ <string name="controls_favorite_subtitle" msgid="6604402232298443956">"Steuerelemente auswählen, auf die man über das Ein-/Aus-Menü zugreifen kann"</string>
<string name="controls_favorite_rearrange" msgid="5616952398043063519">"Zum Verschieben von Steuerelementen halten und ziehen"</string>
<string name="controls_favorite_removed" msgid="5276978408529217272">"Alle Steuerelemente entfernt"</string>
<string name="controls_favorite_toast_no_changes" msgid="7094494210840877931">"Änderungen nicht gespeichert"</string>
@@ -1070,13 +1063,17 @@
<string name="controls_structure_tooltip" msgid="4355922222944447867">"Wischen, um weitere zu sehen"</string>
<string name="controls_seeding_in_progress" msgid="3033855341410264148">"Empfehlungen werden geladen"</string>
<string name="controls_media_close_session" msgid="9023534788828414585">"Diese Mediensitzung schließen"</string>
+ <string name="controls_media_resume" msgid="1933520684481586053">"Fortsetzen"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"Inaktiv – sieh in der App nach"</string>
<string name="controls_error_retryable" msgid="864025882878378470">"Fehler. Neuer Versuch…"</string>
- <string name="controls_error_removed" msgid="6299213591234723805">"Gerät entfernt"</string>
+ <string name="controls_error_removed" msgid="6675638069846014366">"Nicht gefunden"</string>
+ <string name="controls_error_removed_title" msgid="1207794911208047818">"Steuerelement nicht verfügbar"</string>
+ <string name="controls_error_removed_message" msgid="2885911717034750542">"Zugriff auf <xliff:g id="DEVICE">%1$s</xliff:g> nicht möglich. Prüfe, ob das Steuerelement in der App \"<xliff:g id="APPLICATION">%2$s</xliff:g>\" noch verfügbar ist und die App-Einstellungen nicht geändert wurden."</string>
+ <string name="controls_open_app" msgid="483650971094300141">"App öffnen"</string>
<string name="controls_error_generic" msgid="352500456918362905">"Status kann nicht geladen werden"</string>
<string name="controls_error_failed" msgid="960228639198558525">"Fehler – versuch es noch mal"</string>
<string name="controls_in_progress" msgid="4421080500238215939">"Läuft"</string>
<string name="controls_added_tooltip" msgid="4842812921719153085">"Zum Anzeigen der Karten für neue Geräte Ein-/Aus-Taste gedrückt halten"</string>
- <string name="controls_menu_add" msgid="4447246119229920050">"Gerätekarten hinzufügen"</string>
- <string name="controls_menu_edit" msgid="890623986951347062">"Gerätekarten bearbeiten"</string>
+ <string name="controls_menu_add" msgid="4447246119229920050">"Steuerelemente hinzufügen"</string>
+ <string name="controls_menu_edit" msgid="890623986951347062">"Steuerelemente bearbeiten"</string>
</resources>
diff --git a/packages/SystemUI/res/values-el/strings.xml b/packages/SystemUI/res/values-el/strings.xml
index 49a4dac968f2..c8db318dfb65 100644
--- a/packages/SystemUI/res/values-el/strings.xml
+++ b/packages/SystemUI/res/values-el/strings.xml
@@ -77,9 +77,6 @@
<string name="compat_mode_on" msgid="4963711187149440884">"Ζουμ σε πλήρη οθόνη"</string>
<string name="compat_mode_off" msgid="7682459748279487945">"Προβoλή σε πλήρη οθ."</string>
<string name="global_action_screenshot" msgid="2760267567509131654">"Στιγμιότυπο οθόνης"</string>
- <string name="global_action_lock_message" product="default" msgid="4466026255205186456">"Ξεκλειδώστε το τηλέφωνό σας για περισσότερες επιλογές."</string>
- <string name="global_action_lock_message" product="tablet" msgid="7621167597240332986">"Ξεκλειδώστε το tablet για περισσότερες επιλογές."</string>
- <string name="global_action_lock_message" product="device" msgid="538790401275363781">"Ξεκλειδώστε τη συσκευή σας για περισσότερες επιλογές."</string>
<string name="remote_input_image_insertion_text" msgid="4850791636452521123">"έστειλε μια εικόνα"</string>
<string name="screenshot_saving_ticker" msgid="6519186952674544916">"Αποθήκ. στιγμιότυπου οθόνης..."</string>
<string name="screenshot_saving_title" msgid="2298349784913287333">"Αποθήκευση στιγμιότυπου οθόνης..."</string>
@@ -722,7 +719,7 @@
<string name="notification_channel_summary_priority" msgid="7952654515769021553">"Εμφανίζεται στο επάνω μέρος της ενότητας συζητήσεων, προβάλλεται ως κινούμενο συννεφάκι, εμφανίζει τη φωτογραφία προφίλ στην οθόνη κλειδώματος"</string>
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"Ρυθμίσεις"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"Προτεραιότητα"</string>
- <string name="no_shortcut" msgid="7176375126961212514">"Η εφαρμογή <xliff:g id="APP_NAME">%1$s</xliff:g> δεν υποστηρίζει ρυθμίσεις για συγκεκριμένη συνομιλία"</string>
+ <string name="no_shortcut" msgid="8257177117568230126">"Η εφαρμογή <xliff:g id="APP_NAME">%1$s</xliff:g> δεν υποστηρίζει τις λειτουργίες συζήτησης"</string>
<string name="bubble_overflow_empty_title" msgid="3120029421991510842">"Δεν υπάρχουν πρόσφατα συννεφάκια"</string>
<string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"Τα πρόσφατα συννεφάκια και τα συννεφάκια που παραβλέψατε θα εμφανίζονται εδώ."</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"Δεν είναι δυνατή η τροποποίηση αυτών των ειδοποιήσεων"</string>
@@ -1005,7 +1002,8 @@
<string name="bubble_accessibility_action_move_top_right" msgid="6916868852433483569">"Μετακίνηση επάνω δεξιά"</string>
<string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"Μετακίνηση κάτω αριστερά"</string>
<string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"Μετακίνηση κάτω δεξιά"</string>
- <string name="bubble_dismiss_text" msgid="7071770411580452911">"Παράβλεψη"</string>
+ <!-- no translation found for bubble_dismiss_text (1314082410868930066) -->
+ <skip />
<string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"Να μην γίνει προβολή της συζήτησης σε συννεφάκια."</string>
<string name="bubbles_user_education_title" msgid="5547017089271445797">"Συζητήστε χρησιμοποιώντας συννεφάκια."</string>
<string name="bubbles_user_education_description" msgid="1160281719576715211">"Οι νέες συζητήσεις εμφανίζονται ως κινούμενα εικονίδια ή φούσκες. Πατήστε για να ανοίξετε τη φούσκα. Σύρετε για να το μετακινήσετε."</string>
@@ -1016,11 +1014,14 @@
<string name="notification_content_system_nav_changed" msgid="5077913144844684544">"Η πλοήγηση συστήματος ενημερώθηκε. Για να κάνετε αλλαγές, μεταβείτε στις Ρυθμίσεις."</string>
<string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"Μεταβείτε στις Ρυθμίσεις για να ενημερώσετε την πλοήγηση συστήματος"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Κατάσταση αναμονής"</string>
+ <string name="priority_onboarding_title" msgid="2893070698479227616">"Ορίστηκε ως συζήτηση προτεραιότητας"</string>
+ <string name="priority_onboarding_behavior" msgid="5342816047020432929">"Οι συζητήσεις προτεραιότητας θα:"</string>
<string name="priority_onboarding_show_at_top_text" msgid="1678400241025513541">"Εμφάνιση στο επάνω μέρος της ενότητας συνομιλιών"</string>
<string name="priority_onboarding_show_avatar_text" msgid="5756291381124091508">"Εμφάνιση εικόνας προφίλ στην οθόνη κλειδώματος"</string>
<string name="priority_onboarding_appear_as_bubble_text" msgid="4227039772250263122">"Κινούμενο συννεφάκι στο επάνω μέρος των εφαρμογών"</string>
<string name="priority_onboarding_ignores_dnd_text" msgid="2918952762719600529">"Διακοπή λειτουργίας Μην ενοχλείτε"</string>
<string name="priority_onboarding_done_button_title" msgid="4569550984286506007">"Το κατάλαβα"</string>
+ <string name="priority_onboarding_settings_button_title" msgid="6663601574303585927">"Ρυθμίσεις"</string>
<string name="magnification_overlay_title" msgid="6584179429612427958">"Παράθυρο επικάλυψης μεγέθυνσης"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"Παράθυρο μεγέθυνσης"</string>
<string name="magnification_controls_title" msgid="8421106606708891519">"Στοιχεία ελέγχου παραθύρου μεγέθυνσης"</string>
@@ -1062,9 +1063,13 @@
<string name="controls_structure_tooltip" msgid="4355922222944447867">"Σύρετε για να δείτε περισσότερα."</string>
<string name="controls_seeding_in_progress" msgid="3033855341410264148">"Φόρτωση προτάσεων"</string>
<string name="controls_media_close_session" msgid="9023534788828414585">"Κλείσιμο αυτής της περιόδου λειτουργίας μέσων."</string>
+ <string name="controls_media_resume" msgid="1933520684481586053">"Συνέχιση"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"Ανενεργό, έλεγχος εφαρμογής"</string>
<string name="controls_error_retryable" msgid="864025882878378470">"Προέκυψε σφάλμα. Επανάληψη…"</string>
- <string name="controls_error_removed" msgid="6299213591234723805">"Η συσκευή καταργήθηκε"</string>
+ <string name="controls_error_removed" msgid="6675638069846014366">"Δεν βρέθηκε."</string>
+ <string name="controls_error_removed_title" msgid="1207794911208047818">"Μη διαθέσιμο στοιχείο ελέγχου"</string>
+ <string name="controls_error_removed_message" msgid="2885911717034750542">"Δεν ήταν δυνατή η πρόσβαση στη συσκευή <xliff:g id="DEVICE">%1$s</xliff:g>. Ελέγξτε την εφαρμογή <xliff:g id="APPLICATION">%2$s</xliff:g> για να βεβαιωθείτε ότι το στοιχείο ελέγχου εξακολουθεί να είναι διαθέσιμο και ότι οι ρυθμίσεις της εφαρμογής δεν έχουν αλλάξει."</string>
+ <string name="controls_open_app" msgid="483650971094300141">"Άνοιγμα εφαρμογής"</string>
<string name="controls_error_generic" msgid="352500456918362905">"Αδυναμία φόρτωσης κατάστασης"</string>
<string name="controls_error_failed" msgid="960228639198558525">"Σφάλμα, προσπαθήστε ξανά."</string>
<string name="controls_in_progress" msgid="4421080500238215939">"Σε εξέλιξη"</string>
diff --git a/packages/SystemUI/res/values-en-rAU/strings.xml b/packages/SystemUI/res/values-en-rAU/strings.xml
index 626b06782e4a..708f2f4f017a 100644
--- a/packages/SystemUI/res/values-en-rAU/strings.xml
+++ b/packages/SystemUI/res/values-en-rAU/strings.xml
@@ -77,9 +77,6 @@
<string name="compat_mode_on" msgid="4963711187149440884">"Zoom to fill screen"</string>
<string name="compat_mode_off" msgid="7682459748279487945">"Stretch to fill screen"</string>
<string name="global_action_screenshot" msgid="2760267567509131654">"Screenshot"</string>
- <string name="global_action_lock_message" product="default" msgid="4466026255205186456">"Unlock your phone for more options"</string>
- <string name="global_action_lock_message" product="tablet" msgid="7621167597240332986">"Unlock your tablet for more options"</string>
- <string name="global_action_lock_message" product="device" msgid="538790401275363781">"Unlock your device for more options"</string>
<string name="remote_input_image_insertion_text" msgid="4850791636452521123">"sent an image"</string>
<string name="screenshot_saving_ticker" msgid="6519186952674544916">"Saving screenshot…"</string>
<string name="screenshot_saving_title" msgid="2298349784913287333">"Saving screenshot…"</string>
@@ -722,7 +719,7 @@
<string name="notification_channel_summary_priority" msgid="7952654515769021553">"Shows at top of conversation section, appears as floating bubble, displays profile picture on lock screen"</string>
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"Settings"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"Priority"</string>
- <string name="no_shortcut" msgid="7176375126961212514">"<xliff:g id="APP_NAME">%1$s</xliff:g> does not support conversation-specific settings"</string>
+ <string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> doesn’t support conversation features"</string>
<string name="bubble_overflow_empty_title" msgid="3120029421991510842">"No recent bubbles"</string>
<string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"Recent bubbles and dismissed bubbles will appear here"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"These notifications can\'t be modified."</string>
@@ -1005,7 +1002,8 @@
<string name="bubble_accessibility_action_move_top_right" msgid="6916868852433483569">"Move top right"</string>
<string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"Move bottom left"</string>
<string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"Move bottom right"</string>
- <string name="bubble_dismiss_text" msgid="7071770411580452911">"Dismiss"</string>
+ <!-- no translation found for bubble_dismiss_text (1314082410868930066) -->
+ <skip />
<string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"Don’t bubble conversation"</string>
<string name="bubbles_user_education_title" msgid="5547017089271445797">"Chat using bubbles"</string>
<string name="bubbles_user_education_description" msgid="1160281719576715211">"New conversations appear as floating icons, or bubbles. Tap to open bubble. Drag to move it."</string>
@@ -1016,11 +1014,14 @@
<string name="notification_content_system_nav_changed" msgid="5077913144844684544">"System navigation updated. To make changes, go to Settings."</string>
<string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"Go to Settings to update system navigation"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Standby"</string>
+ <string name="priority_onboarding_title" msgid="2893070698479227616">"Conversation set to priority"</string>
+ <string name="priority_onboarding_behavior" msgid="5342816047020432929">"Priority conversations will:"</string>
<string name="priority_onboarding_show_at_top_text" msgid="1678400241025513541">"Show at top of conversation section"</string>
<string name="priority_onboarding_show_avatar_text" msgid="5756291381124091508">"Show profile picture on lock screen"</string>
<string name="priority_onboarding_appear_as_bubble_text" msgid="4227039772250263122">"Appear as a floating bubble on top of apps"</string>
<string name="priority_onboarding_ignores_dnd_text" msgid="2918952762719600529">"Interrupt Do Not Disturb"</string>
<string name="priority_onboarding_done_button_title" msgid="4569550984286506007">"OK"</string>
+ <string name="priority_onboarding_settings_button_title" msgid="6663601574303585927">"Settings"</string>
<string name="magnification_overlay_title" msgid="6584179429612427958">"Magnification overlay window"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"Magnification window"</string>
<string name="magnification_controls_title" msgid="8421106606708891519">"Magnification window controls"</string>
@@ -1062,9 +1063,13 @@
<string name="controls_structure_tooltip" msgid="4355922222944447867">"Swipe to see more"</string>
<string name="controls_seeding_in_progress" msgid="3033855341410264148">"Loading recommendations"</string>
<string name="controls_media_close_session" msgid="9023534788828414585">"Close this media session"</string>
+ <string name="controls_media_resume" msgid="1933520684481586053">"Resume"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"Inactive, check app"</string>
<string name="controls_error_retryable" msgid="864025882878378470">"Error, retrying…"</string>
- <string name="controls_error_removed" msgid="6299213591234723805">"Device removed"</string>
+ <string name="controls_error_removed" msgid="6675638069846014366">"Not found"</string>
+ <string name="controls_error_removed_title" msgid="1207794911208047818">"Control is unavailable"</string>
+ <string name="controls_error_removed_message" msgid="2885911717034750542">"Couldn’t access <xliff:g id="DEVICE">%1$s</xliff:g>. Check the <xliff:g id="APPLICATION">%2$s</xliff:g> app to make sure that the control is still available and that the app settings haven’t changed."</string>
+ <string name="controls_open_app" msgid="483650971094300141">"Open app"</string>
<string name="controls_error_generic" msgid="352500456918362905">"Can’t load status"</string>
<string name="controls_error_failed" msgid="960228639198558525">"Error, try again"</string>
<string name="controls_in_progress" msgid="4421080500238215939">"In progress"</string>
diff --git a/packages/SystemUI/res/values-en-rCA/strings.xml b/packages/SystemUI/res/values-en-rCA/strings.xml
index e4646f18709e..313c604953ea 100644
--- a/packages/SystemUI/res/values-en-rCA/strings.xml
+++ b/packages/SystemUI/res/values-en-rCA/strings.xml
@@ -77,9 +77,6 @@
<string name="compat_mode_on" msgid="4963711187149440884">"Zoom to fill screen"</string>
<string name="compat_mode_off" msgid="7682459748279487945">"Stretch to fill screen"</string>
<string name="global_action_screenshot" msgid="2760267567509131654">"Screenshot"</string>
- <string name="global_action_lock_message" product="default" msgid="4466026255205186456">"Unlock your phone for more options"</string>
- <string name="global_action_lock_message" product="tablet" msgid="7621167597240332986">"Unlock your tablet for more options"</string>
- <string name="global_action_lock_message" product="device" msgid="538790401275363781">"Unlock your device for more options"</string>
<string name="remote_input_image_insertion_text" msgid="4850791636452521123">"sent an image"</string>
<string name="screenshot_saving_ticker" msgid="6519186952674544916">"Saving screenshot…"</string>
<string name="screenshot_saving_title" msgid="2298349784913287333">"Saving screenshot…"</string>
@@ -722,7 +719,7 @@
<string name="notification_channel_summary_priority" msgid="7952654515769021553">"Shows at top of conversation section, appears as floating bubble, displays profile picture on lock screen"</string>
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"Settings"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"Priority"</string>
- <string name="no_shortcut" msgid="7176375126961212514">"<xliff:g id="APP_NAME">%1$s</xliff:g> does not support conversation-specific settings"</string>
+ <string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> doesn’t support conversation features"</string>
<string name="bubble_overflow_empty_title" msgid="3120029421991510842">"No recent bubbles"</string>
<string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"Recent bubbles and dismissed bubbles will appear here"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"These notifications can\'t be modified."</string>
@@ -1005,7 +1002,8 @@
<string name="bubble_accessibility_action_move_top_right" msgid="6916868852433483569">"Move top right"</string>
<string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"Move bottom left"</string>
<string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"Move bottom right"</string>
- <string name="bubble_dismiss_text" msgid="7071770411580452911">"Dismiss"</string>
+ <!-- no translation found for bubble_dismiss_text (1314082410868930066) -->
+ <skip />
<string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"Don’t bubble conversation"</string>
<string name="bubbles_user_education_title" msgid="5547017089271445797">"Chat using bubbles"</string>
<string name="bubbles_user_education_description" msgid="1160281719576715211">"New conversations appear as floating icons, or bubbles. Tap to open bubble. Drag to move it."</string>
@@ -1016,11 +1014,14 @@
<string name="notification_content_system_nav_changed" msgid="5077913144844684544">"System navigation updated. To make changes, go to Settings."</string>
<string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"Go to Settings to update system navigation"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Standby"</string>
+ <string name="priority_onboarding_title" msgid="2893070698479227616">"Conversation set to priority"</string>
+ <string name="priority_onboarding_behavior" msgid="5342816047020432929">"Priority conversations will:"</string>
<string name="priority_onboarding_show_at_top_text" msgid="1678400241025513541">"Show at top of conversation section"</string>
<string name="priority_onboarding_show_avatar_text" msgid="5756291381124091508">"Show profile picture on lock screen"</string>
<string name="priority_onboarding_appear_as_bubble_text" msgid="4227039772250263122">"Appear as a floating bubble on top of apps"</string>
<string name="priority_onboarding_ignores_dnd_text" msgid="2918952762719600529">"Interrupt Do Not Disturb"</string>
<string name="priority_onboarding_done_button_title" msgid="4569550984286506007">"OK"</string>
+ <string name="priority_onboarding_settings_button_title" msgid="6663601574303585927">"Settings"</string>
<string name="magnification_overlay_title" msgid="6584179429612427958">"Magnification overlay window"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"Magnification window"</string>
<string name="magnification_controls_title" msgid="8421106606708891519">"Magnification window controls"</string>
@@ -1062,9 +1063,13 @@
<string name="controls_structure_tooltip" msgid="4355922222944447867">"Swipe to see more"</string>
<string name="controls_seeding_in_progress" msgid="3033855341410264148">"Loading recommendations"</string>
<string name="controls_media_close_session" msgid="9023534788828414585">"Close this media session"</string>
+ <string name="controls_media_resume" msgid="1933520684481586053">"Resume"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"Inactive, check app"</string>
<string name="controls_error_retryable" msgid="864025882878378470">"Error, retrying…"</string>
- <string name="controls_error_removed" msgid="6299213591234723805">"Device removed"</string>
+ <string name="controls_error_removed" msgid="6675638069846014366">"Not found"</string>
+ <string name="controls_error_removed_title" msgid="1207794911208047818">"Control is unavailable"</string>
+ <string name="controls_error_removed_message" msgid="2885911717034750542">"Couldn’t access <xliff:g id="DEVICE">%1$s</xliff:g>. Check the <xliff:g id="APPLICATION">%2$s</xliff:g> app to make sure that the control is still available and that the app settings haven’t changed."</string>
+ <string name="controls_open_app" msgid="483650971094300141">"Open app"</string>
<string name="controls_error_generic" msgid="352500456918362905">"Can’t load status"</string>
<string name="controls_error_failed" msgid="960228639198558525">"Error, try again"</string>
<string name="controls_in_progress" msgid="4421080500238215939">"In progress"</string>
diff --git a/packages/SystemUI/res/values-en-rGB/strings.xml b/packages/SystemUI/res/values-en-rGB/strings.xml
index 626b06782e4a..708f2f4f017a 100644
--- a/packages/SystemUI/res/values-en-rGB/strings.xml
+++ b/packages/SystemUI/res/values-en-rGB/strings.xml
@@ -77,9 +77,6 @@
<string name="compat_mode_on" msgid="4963711187149440884">"Zoom to fill screen"</string>
<string name="compat_mode_off" msgid="7682459748279487945">"Stretch to fill screen"</string>
<string name="global_action_screenshot" msgid="2760267567509131654">"Screenshot"</string>
- <string name="global_action_lock_message" product="default" msgid="4466026255205186456">"Unlock your phone for more options"</string>
- <string name="global_action_lock_message" product="tablet" msgid="7621167597240332986">"Unlock your tablet for more options"</string>
- <string name="global_action_lock_message" product="device" msgid="538790401275363781">"Unlock your device for more options"</string>
<string name="remote_input_image_insertion_text" msgid="4850791636452521123">"sent an image"</string>
<string name="screenshot_saving_ticker" msgid="6519186952674544916">"Saving screenshot…"</string>
<string name="screenshot_saving_title" msgid="2298349784913287333">"Saving screenshot…"</string>
@@ -722,7 +719,7 @@
<string name="notification_channel_summary_priority" msgid="7952654515769021553">"Shows at top of conversation section, appears as floating bubble, displays profile picture on lock screen"</string>
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"Settings"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"Priority"</string>
- <string name="no_shortcut" msgid="7176375126961212514">"<xliff:g id="APP_NAME">%1$s</xliff:g> does not support conversation-specific settings"</string>
+ <string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> doesn’t support conversation features"</string>
<string name="bubble_overflow_empty_title" msgid="3120029421991510842">"No recent bubbles"</string>
<string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"Recent bubbles and dismissed bubbles will appear here"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"These notifications can\'t be modified."</string>
@@ -1005,7 +1002,8 @@
<string name="bubble_accessibility_action_move_top_right" msgid="6916868852433483569">"Move top right"</string>
<string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"Move bottom left"</string>
<string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"Move bottom right"</string>
- <string name="bubble_dismiss_text" msgid="7071770411580452911">"Dismiss"</string>
+ <!-- no translation found for bubble_dismiss_text (1314082410868930066) -->
+ <skip />
<string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"Don’t bubble conversation"</string>
<string name="bubbles_user_education_title" msgid="5547017089271445797">"Chat using bubbles"</string>
<string name="bubbles_user_education_description" msgid="1160281719576715211">"New conversations appear as floating icons, or bubbles. Tap to open bubble. Drag to move it."</string>
@@ -1016,11 +1014,14 @@
<string name="notification_content_system_nav_changed" msgid="5077913144844684544">"System navigation updated. To make changes, go to Settings."</string>
<string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"Go to Settings to update system navigation"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Standby"</string>
+ <string name="priority_onboarding_title" msgid="2893070698479227616">"Conversation set to priority"</string>
+ <string name="priority_onboarding_behavior" msgid="5342816047020432929">"Priority conversations will:"</string>
<string name="priority_onboarding_show_at_top_text" msgid="1678400241025513541">"Show at top of conversation section"</string>
<string name="priority_onboarding_show_avatar_text" msgid="5756291381124091508">"Show profile picture on lock screen"</string>
<string name="priority_onboarding_appear_as_bubble_text" msgid="4227039772250263122">"Appear as a floating bubble on top of apps"</string>
<string name="priority_onboarding_ignores_dnd_text" msgid="2918952762719600529">"Interrupt Do Not Disturb"</string>
<string name="priority_onboarding_done_button_title" msgid="4569550984286506007">"OK"</string>
+ <string name="priority_onboarding_settings_button_title" msgid="6663601574303585927">"Settings"</string>
<string name="magnification_overlay_title" msgid="6584179429612427958">"Magnification overlay window"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"Magnification window"</string>
<string name="magnification_controls_title" msgid="8421106606708891519">"Magnification window controls"</string>
@@ -1062,9 +1063,13 @@
<string name="controls_structure_tooltip" msgid="4355922222944447867">"Swipe to see more"</string>
<string name="controls_seeding_in_progress" msgid="3033855341410264148">"Loading recommendations"</string>
<string name="controls_media_close_session" msgid="9023534788828414585">"Close this media session"</string>
+ <string name="controls_media_resume" msgid="1933520684481586053">"Resume"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"Inactive, check app"</string>
<string name="controls_error_retryable" msgid="864025882878378470">"Error, retrying…"</string>
- <string name="controls_error_removed" msgid="6299213591234723805">"Device removed"</string>
+ <string name="controls_error_removed" msgid="6675638069846014366">"Not found"</string>
+ <string name="controls_error_removed_title" msgid="1207794911208047818">"Control is unavailable"</string>
+ <string name="controls_error_removed_message" msgid="2885911717034750542">"Couldn’t access <xliff:g id="DEVICE">%1$s</xliff:g>. Check the <xliff:g id="APPLICATION">%2$s</xliff:g> app to make sure that the control is still available and that the app settings haven’t changed."</string>
+ <string name="controls_open_app" msgid="483650971094300141">"Open app"</string>
<string name="controls_error_generic" msgid="352500456918362905">"Can’t load status"</string>
<string name="controls_error_failed" msgid="960228639198558525">"Error, try again"</string>
<string name="controls_in_progress" msgid="4421080500238215939">"In progress"</string>
diff --git a/packages/SystemUI/res/values-en-rIN/strings.xml b/packages/SystemUI/res/values-en-rIN/strings.xml
index 626b06782e4a..708f2f4f017a 100644
--- a/packages/SystemUI/res/values-en-rIN/strings.xml
+++ b/packages/SystemUI/res/values-en-rIN/strings.xml
@@ -77,9 +77,6 @@
<string name="compat_mode_on" msgid="4963711187149440884">"Zoom to fill screen"</string>
<string name="compat_mode_off" msgid="7682459748279487945">"Stretch to fill screen"</string>
<string name="global_action_screenshot" msgid="2760267567509131654">"Screenshot"</string>
- <string name="global_action_lock_message" product="default" msgid="4466026255205186456">"Unlock your phone for more options"</string>
- <string name="global_action_lock_message" product="tablet" msgid="7621167597240332986">"Unlock your tablet for more options"</string>
- <string name="global_action_lock_message" product="device" msgid="538790401275363781">"Unlock your device for more options"</string>
<string name="remote_input_image_insertion_text" msgid="4850791636452521123">"sent an image"</string>
<string name="screenshot_saving_ticker" msgid="6519186952674544916">"Saving screenshot…"</string>
<string name="screenshot_saving_title" msgid="2298349784913287333">"Saving screenshot…"</string>
@@ -722,7 +719,7 @@
<string name="notification_channel_summary_priority" msgid="7952654515769021553">"Shows at top of conversation section, appears as floating bubble, displays profile picture on lock screen"</string>
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"Settings"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"Priority"</string>
- <string name="no_shortcut" msgid="7176375126961212514">"<xliff:g id="APP_NAME">%1$s</xliff:g> does not support conversation-specific settings"</string>
+ <string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> doesn’t support conversation features"</string>
<string name="bubble_overflow_empty_title" msgid="3120029421991510842">"No recent bubbles"</string>
<string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"Recent bubbles and dismissed bubbles will appear here"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"These notifications can\'t be modified."</string>
@@ -1005,7 +1002,8 @@
<string name="bubble_accessibility_action_move_top_right" msgid="6916868852433483569">"Move top right"</string>
<string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"Move bottom left"</string>
<string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"Move bottom right"</string>
- <string name="bubble_dismiss_text" msgid="7071770411580452911">"Dismiss"</string>
+ <!-- no translation found for bubble_dismiss_text (1314082410868930066) -->
+ <skip />
<string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"Don’t bubble conversation"</string>
<string name="bubbles_user_education_title" msgid="5547017089271445797">"Chat using bubbles"</string>
<string name="bubbles_user_education_description" msgid="1160281719576715211">"New conversations appear as floating icons, or bubbles. Tap to open bubble. Drag to move it."</string>
@@ -1016,11 +1014,14 @@
<string name="notification_content_system_nav_changed" msgid="5077913144844684544">"System navigation updated. To make changes, go to Settings."</string>
<string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"Go to Settings to update system navigation"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Standby"</string>
+ <string name="priority_onboarding_title" msgid="2893070698479227616">"Conversation set to priority"</string>
+ <string name="priority_onboarding_behavior" msgid="5342816047020432929">"Priority conversations will:"</string>
<string name="priority_onboarding_show_at_top_text" msgid="1678400241025513541">"Show at top of conversation section"</string>
<string name="priority_onboarding_show_avatar_text" msgid="5756291381124091508">"Show profile picture on lock screen"</string>
<string name="priority_onboarding_appear_as_bubble_text" msgid="4227039772250263122">"Appear as a floating bubble on top of apps"</string>
<string name="priority_onboarding_ignores_dnd_text" msgid="2918952762719600529">"Interrupt Do Not Disturb"</string>
<string name="priority_onboarding_done_button_title" msgid="4569550984286506007">"OK"</string>
+ <string name="priority_onboarding_settings_button_title" msgid="6663601574303585927">"Settings"</string>
<string name="magnification_overlay_title" msgid="6584179429612427958">"Magnification overlay window"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"Magnification window"</string>
<string name="magnification_controls_title" msgid="8421106606708891519">"Magnification window controls"</string>
@@ -1062,9 +1063,13 @@
<string name="controls_structure_tooltip" msgid="4355922222944447867">"Swipe to see more"</string>
<string name="controls_seeding_in_progress" msgid="3033855341410264148">"Loading recommendations"</string>
<string name="controls_media_close_session" msgid="9023534788828414585">"Close this media session"</string>
+ <string name="controls_media_resume" msgid="1933520684481586053">"Resume"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"Inactive, check app"</string>
<string name="controls_error_retryable" msgid="864025882878378470">"Error, retrying…"</string>
- <string name="controls_error_removed" msgid="6299213591234723805">"Device removed"</string>
+ <string name="controls_error_removed" msgid="6675638069846014366">"Not found"</string>
+ <string name="controls_error_removed_title" msgid="1207794911208047818">"Control is unavailable"</string>
+ <string name="controls_error_removed_message" msgid="2885911717034750542">"Couldn’t access <xliff:g id="DEVICE">%1$s</xliff:g>. Check the <xliff:g id="APPLICATION">%2$s</xliff:g> app to make sure that the control is still available and that the app settings haven’t changed."</string>
+ <string name="controls_open_app" msgid="483650971094300141">"Open app"</string>
<string name="controls_error_generic" msgid="352500456918362905">"Can’t load status"</string>
<string name="controls_error_failed" msgid="960228639198558525">"Error, try again"</string>
<string name="controls_in_progress" msgid="4421080500238215939">"In progress"</string>
diff --git a/packages/SystemUI/res/values-en-rXC/strings.xml b/packages/SystemUI/res/values-en-rXC/strings.xml
index 99ca7806bf11..5d2e3eb16780 100644
--- a/packages/SystemUI/res/values-en-rXC/strings.xml
+++ b/packages/SystemUI/res/values-en-rXC/strings.xml
@@ -719,7 +719,7 @@
<string name="notification_channel_summary_priority" msgid="7952654515769021553">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‏‏‏‎‎‏‎‏‏‏‎‏‏‎‎‎‎‎‎‏‎‎‏‎‎‏‎‏‏‎‏‎‏‎‎‏‏‏‎‏‎‎‎‏‏‎‎‏‎‏‎‎‎‏‏‏‎‎‎‏‎Shows at top of conversation section, appears as floating bubble, displays profile picture on lock screen‎‏‎‎‏‎"</string>
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‎‎‎‏‎‏‏‏‎‎‎‏‏‏‏‏‎‏‎‏‏‏‏‏‎‎‎‎‎‏‏‎‎‎‏‏‏‎‎‎‎‏‎‏‏‏‏‏‏‎‎‏‏‏‏‏‎‎‏‏‎Settings‎‏‎‎‏‎"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‏‏‎‎‏‏‎‏‏‏‎‎‏‎‎‏‏‏‎‎‎‎‏‏‎‎‎‏‏‏‏‏‎‏‏‎‎‎‎‎‏‎‏‎‎‏‏‏‎‎‏‏‎‏‎‎‎‏‎‏‎Priority‎‏‎‎‏‎"</string>
- <string name="no_shortcut" msgid="7176375126961212514">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‎‎‏‏‏‎‎‏‎‏‏‏‏‎‎‏‏‎‏‏‎‎‏‎‎‏‏‏‏‏‏‎‏‎‎‏‎‏‏‏‏‎‎‎‏‏‎‎‏‏‎‎‎‏‏‎‎‎‏‎‎‎‏‎‎‏‏‎<xliff:g id="APP_NAME">%1$s</xliff:g>‎‏‎‎‏‏‏‎ does not support conversation specific settings‎‏‎‎‏‎"</string>
+ <string name="no_shortcut" msgid="8257177117568230126">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‎‎‏‎‏‎‎‏‎‏‏‏‎‏‏‎‎‎‏‎‏‏‎‏‎‏‏‏‎‎‎‎‏‏‎‎‎‎‏‎‎‎‏‏‎‏‏‎‎‎‏‎‏‏‏‎‏‏‏‎‎‎‏‎‎‏‏‎<xliff:g id="APP_NAME">%1$s</xliff:g>‎‏‎‎‏‏‏‎ doesn’t support conversation features‎‏‎‎‏‎"</string>
<string name="bubble_overflow_empty_title" msgid="3120029421991510842">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‏‎‏‏‎‏‎‎‏‏‎‎‏‎‎‏‎‎‏‎‎‎‏‏‏‎‏‎‏‎‎‎‏‎‏‎‏‎‎‏‎‎‏‎‎‏‎‎‎‎‏‏‎‎‏‏‏‎‏‎‎No recent bubbles‎‏‎‎‏‎"</string>
<string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‏‏‎‎‎‎‏‎‏‏‏‏‎‎‎‏‏‏‎‏‏‎‎‏‎‎‎‏‏‏‏‎‏‎‏‎‏‎‎‏‎‏‎‏‎‏‎‎‎‏‎‎‎‏‏‏‎‏‎‏‎Recent bubbles and dismissed bubbles will appear here‎‏‎‎‏‎"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‏‏‎‎‏‏‎‎‎‏‎‎‏‏‏‎‎‎‏‎‏‎‎‏‏‎‏‏‏‎‎‎‎‎‎‎‏‏‎‎‏‏‏‏‏‏‏‏‎‎‏‎‏‏‎‏‎‏‎‎‎These notifications can\'t be modified.‎‏‎‎‏‎"</string>
@@ -1002,7 +1002,7 @@
<string name="bubble_accessibility_action_move_top_right" msgid="6916868852433483569">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‏‏‏‏‏‏‏‏‏‏‎‏‏‎‏‎‎‏‏‏‏‎‎‏‎‎‏‎‏‏‏‏‏‎‏‏‎‏‎‎‎‎‏‎‏‏‏‏‎‏‏‏‎‎‏‏‎‎‎‏‎Move top right‎‏‎‎‏‎"</string>
<string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‎‏‏‏‏‏‏‏‏‎‎‎‏‎‏‏‎‏‎‏‎‏‏‎‎‎‎‎‏‎‏‏‎‏‎‏‏‏‎‎‏‎‏‏‏‏‏‏‏‎‎‏‎‏‎‎‏‎‏‏‎Move bottom left‎‏‎‎‏‎"</string>
<string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‎‏‏‏‏‎‏‏‎‎‎‎‎‏‎‏‏‎‏‎‏‏‏‎‎‎‎‎‎‎‏‎‏‎‎‏‏‏‎‏‎‎‎‎‎‏‎‏‎‏‎‏‎‏‏‎‎‏‎‎‎Move bottom right‎‏‎‎‏‎"</string>
- <string name="bubble_dismiss_text" msgid="7071770411580452911">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‎‎‏‎‎‎‏‎‎‎‏‏‏‏‏‏‏‎‎‏‏‎‏‏‏‎‎‎‏‎‏‏‎‎‏‏‎‏‎‏‏‏‏‎‏‏‏‏‎‎‎‎‎‎‏‎‏‏‏‏‎Dismiss‎‏‎‎‏‎"</string>
+ <string name="bubble_dismiss_text" msgid="1314082410868930066">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‎‎‏‎‎‎‏‏‏‏‎‎‏‎‎‎‏‏‏‎‏‏‏‏‏‏‎‏‏‎‎‎‏‎‎‏‎‏‏‎‏‏‏‎‎‏‏‏‎‏‏‎‎‎‎‏‎‎‏‎‎Dismiss bubble‎‏‎‎‏‎"</string>
<string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‎‏‏‏‎‎‏‎‏‎‏‏‎‎‎‎‏‏‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‏‎‏‎‎‏‏‏‏‎‎‎‏‎‎‏‎‎‎‎‏‎‏‎‏‏‎‎Don’t bubble conversation‎‏‎‎‏‎"</string>
<string name="bubbles_user_education_title" msgid="5547017089271445797">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‏‏‎‎‏‏‏‏‏‎‏‎‏‏‏‏‎‏‏‎‏‎‏‎‎‏‏‏‎‏‎‎‎‎‎‏‎‎‎‎‏‎‏‏‏‎‏‏‏‎‎‏‎‎‏‎‎‏‎‏‎Chat using bubbles‎‏‎‎‏‎"</string>
<string name="bubbles_user_education_description" msgid="1160281719576715211">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‎‎‎‎‎‎‎‏‏‎‏‎‎‎‏‎‎‏‏‎‎‎‎‏‎‎‏‏‏‎‎‏‎‏‏‎‏‎‏‏‏‏‏‏‏‏‎‏‏‏‏‏‏‏‎‎‏‎‏‏‎New conversations appear as floating icons, or bubbles. Tap to open bubble. Drag to move it.‎‏‎‎‏‎"</string>
@@ -1013,11 +1013,14 @@
<string name="notification_content_system_nav_changed" msgid="5077913144844684544">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‎‏‏‎‎‏‏‏‏‎‎‎‎‏‎‏‏‏‏‏‎‎‎‏‏‎‎‏‏‏‏‎‏‏‏‎‏‏‎‎‎‎‎‏‎‎‎‎‏‏‎‏‎‎‎‎‎‎‎‎‎System navigation updated. To make changes, go to Settings.‎‏‎‎‏‎"</string>
<string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‏‏‎‏‎‏‏‏‏‏‏‏‏‎‏‏‎‏‏‎‎‎‎‏‏‏‏‏‎‎‎‏‎‏‏‏‎‎‏‎‏‎‎‎‏‏‏‏‏‎‎‎‏‎‏‏‎‎‎‎‎Go to Settings to update system navigation‎‏‎‎‏‎"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‎‏‏‎‎‎‎‎‎‎‎‎‏‏‏‎‏‏‎‏‏‏‎‏‏‎‎‎‎‏‏‎‎‏‎‏‎‎‏‎‏‎‎‎‏‎‏‎‎‏‏‎‏‏‏‎‎‏‎‏‎Standby‎‏‎‎‏‎"</string>
+ <string name="priority_onboarding_title" msgid="2893070698479227616">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‏‎‎‎‎‎‏‎‎‏‏‎‎‏‎‎‎‎‎‎‎‏‏‏‏‎‎‎‏‏‎‏‏‏‎‎‏‏‏‏‎‎‏‎‎‎‎‏‎‎‏‎‏‏‏‎‎‎‎‎‎Conversation set to priority‎‏‎‎‏‎"</string>
+ <string name="priority_onboarding_behavior" msgid="5342816047020432929">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‏‎‏‎‎‎‏‎‎‏‎‏‎‏‏‏‏‏‏‎‏‏‏‎‎‎‏‏‎‎‏‎‎‏‏‎‏‏‏‎‏‎‎‎‏‏‎‏‏‏‏‎‎‎‏‎‎‎‎‏‎Priority conversations will:‎‏‎‎‏‎"</string>
<string name="priority_onboarding_show_at_top_text" msgid="1678400241025513541">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‎‏‏‏‎‏‎‎‏‎‏‎‏‏‏‎‎‎‎‎‎‎‏‎‎‎‎‎‎‏‏‎‏‏‎‏‎‏‎‎‎‎‎‏‎‏‏‏‏‎‎‎‎‏‎‎‎‏‎‏‎Show at top of conversation section‎‏‎‎‏‎"</string>
<string name="priority_onboarding_show_avatar_text" msgid="5756291381124091508">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‏‏‏‏‏‏‏‎‎‎‏‎‎‏‏‏‎‏‎‎‏‎‎‎‎‎‏‏‎‏‎‏‎‎‏‏‏‎‎‎‏‎‏‏‎‏‎‎‏‏‏‎‎‏‏‏‎‏‎‎‎Show profile picture on lock screen‎‏‎‎‏‎"</string>
<string name="priority_onboarding_appear_as_bubble_text" msgid="4227039772250263122">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‏‎‏‎‏‎‏‎‏‎‎‏‎‏‏‏‎‏‏‎‎‏‎‎‎‏‏‎‏‏‏‎‏‏‎‎‎‏‏‎‏‏‎‎‏‏‎‎‏‏‏‎‎‏‎‏‎‎‏‎‎Appear as a floating bubble on top of apps‎‏‎‎‏‎"</string>
<string name="priority_onboarding_ignores_dnd_text" msgid="2918952762719600529">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‏‎‎‎‏‎‎‎‎‎‏‎‎‎‏‏‎‏‎‎‎‎‎‏‎‎‏‎‏‎‎‎‏‎‏‎‎‎‎‎‏‎‏‏‏‏‏‏‏‏‏‏‏‎‎‏‎‎‎‏‎Interrupt Do Not Disturb‎‏‎‎‏‎"</string>
<string name="priority_onboarding_done_button_title" msgid="4569550984286506007">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‏‏‏‏‎‏‏‎‏‎‏‎‎‏‎‎‏‏‏‎‎‏‏‎‏‎‎‎‏‏‏‎‎‎‎‏‎‏‏‎‏‏‏‏‎‎‎‎‏‏‎‎‎‎‎‏‎‏‏‏‎Got it‎‏‎‎‏‎"</string>
+ <string name="priority_onboarding_settings_button_title" msgid="6663601574303585927">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‏‏‎‎‎‏‏‏‏‎‎‏‏‏‎‏‏‏‏‎‎‏‎‏‎‎‏‏‏‎‎‏‏‎‎‏‎‎‎‏‏‎‎‏‎‏‎‏‎‏‏‎‏‎‎‎‎‏‏‏‎Settings‎‏‎‎‏‎"</string>
<string name="magnification_overlay_title" msgid="6584179429612427958">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‏‎‏‏‎‏‎‏‏‏‏‏‏‎‏‏‎‏‎‎‎‏‎‎‏‏‏‎‏‎‎‎‎‏‏‏‎‏‏‏‏‎‏‏‏‎‎‏‏‎‏‎‏‎‏‏‎‏‏‎‎Magnification Overlay Window‎‏‎‎‏‎"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‎‎‏‏‏‎‎‎‎‎‎‎‎‎‎‏‏‎‎‎‎‏‎‏‎‏‏‏‎‏‎‏‎‎‎‎‎‎‏‏‏‎‎‎‏‏‎‏‎‎‏‎‏‏‎‏‏‏‎‏‎Magnification Window‎‏‎‎‏‎"</string>
<string name="magnification_controls_title" msgid="8421106606708891519">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‎‏‎‎‏‏‎‏‏‏‎‏‏‏‎‎‎‏‏‏‏‏‎‏‎‏‏‏‏‎‎‎‎‏‎‎‏‎‎‏‎‏‎‎‎‎‎‏‏‏‏‏‎‏‏‏‏‏‏‏‎Magnification Window Controls‎‏‎‎‏‎"</string>
@@ -1059,9 +1062,13 @@
<string name="controls_structure_tooltip" msgid="4355922222944447867">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‏‏‎‎‎‏‏‏‎‎‏‏‎‏‎‏‏‎‎‎‎‎‏‎‏‏‏‎‏‏‎‏‏‏‏‏‏‏‎‏‎‏‎‏‎‏‏‎‏‏‎‏‎‏‏‏‏‎‏‏‎Swipe to see more‎‏‎‎‏‎"</string>
<string name="controls_seeding_in_progress" msgid="3033855341410264148">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‏‎‏‎‎‎‎‏‏‎‏‎‎‏‏‎‏‎‏‏‎‏‎‏‏‎‏‏‏‏‏‎‎‏‎‎‏‎‏‎‏‏‏‎‎‎‏‎‎‏‎‎‎‏‎‏‎‏‎‎‎Loading recommendations‎‏‎‎‏‎"</string>
<string name="controls_media_close_session" msgid="9023534788828414585">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‏‎‏‎‎‏‏‏‎‏‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‎‎‏‏‏‎‏‎‏‎‎‏‏‏‏‏‏‏‎‏‎‎‎‎‏‎‎‏‏‏‏‎‎‏‎Close this media session‎‏‎‎‏‎"</string>
+ <string name="controls_media_resume" msgid="1933520684481586053">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‏‎‏‎‏‏‎‏‎‏‎‏‎‎‏‏‏‏‏‎‏‏‎‏‎‎‎‏‎‏‏‏‏‏‎‎‎‏‏‎‎‏‎‏‎‎‏‎‎‎‏‏‏‎‎‎‎‏‎‏‎Resume‎‏‎‎‏‎"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‎‏‎‏‏‎‎‎‎‎‏‎‏‏‎‎‎‏‏‏‎‎‎‏‏‏‎‏‎‎‎‏‎‏‎‏‎‎‏‏‏‏‎‏‏‎‏‎‎‎‎‏‎‎‏‏‏‏‏‏‎‎Inactive, check app‎‏‎‎‏‎"</string>
<string name="controls_error_retryable" msgid="864025882878378470">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‎‏‎‏‏‏‏‏‏‏‏‎‏‏‎‏‎‎‎‏‎‏‏‏‏‎‏‏‎‎‏‏‏‎‎‎‏‏‎‏‏‎‏‎‏‏‎‎‎‎‎‎‏‏‏‏‎‎‏‏‎‎Error, retrying…‎‏‎‎‏‎"</string>
- <string name="controls_error_removed" msgid="6299213591234723805">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‎‏‏‏‎‏‏‎‏‎‏‏‎‏‎‎‏‏‎‏‎‏‏‎‎‎‏‎‏‏‏‏‎‏‎‏‏‏‎‏‏‎‏‏‏‎‏‏‏‏‏‏‏‏‎‏‏‏‎‏‎Device removed‎‏‎‎‏‎"</string>
+ <string name="controls_error_removed" msgid="6675638069846014366">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‏‏‎‎‏‎‏‎‎‏‎‎‏‎‏‎‎‎‎‏‎‏‏‏‎‏‎‎‏‎‎‏‏‎‏‎‎‎‏‏‏‏‏‎‏‏‏‏‏‎‎‏‏‎‎‏‏‏‏‎‎Not found‎‏‎‎‏‎"</string>
+ <string name="controls_error_removed_title" msgid="1207794911208047818">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‎‎‎‎‏‏‎‎‎‎‏‎‏‏‏‏‎‎‏‏‎‎‎‏‎‎‏‎‏‎‎‏‎‏‎‎‎‎‎‏‎‏‎‎‏‎‎‎‎‏‎‎‏‏‎‎‏‎‏‎‎Control is unavailable‎‏‎‎‏‎"</string>
+ <string name="controls_error_removed_message" msgid="2885911717034750542">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‏‎‎‎‎‎‎‎‏‏‎‎‏‏‎‏‎‎‎‏‎‏‏‎‏‎‏‎‏‎‎‏‏‎‏‎‏‏‏‏‏‏‏‎‎‏‏‏‎‎‏‎‎‏‎‎‏‏‏‎‎Couldn’t access ‎‏‎‎‏‏‎<xliff:g id="DEVICE">%1$s</xliff:g>‎‏‎‎‏‏‏‎. Check the ‎‏‎‎‏‏‎<xliff:g id="APPLICATION">%2$s</xliff:g>‎‏‎‎‏‏‏‎ app to make sure the control is still available and that the app settings haven’t changed.‎‏‎‎‏‎"</string>
+ <string name="controls_open_app" msgid="483650971094300141">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‎‏‏‏‏‎‏‎‏‏‎‏‏‎‎‏‎‎‎‏‎‏‏‏‏‏‏‏‏‎‏‏‏‎‎‏‏‏‎‏‎‏‏‎‎‏‎‎‏‏‎‏‎‏‏‏‏‎‏‏‎‏‎Open app‎‏‎‎‏‎"</string>
<string name="controls_error_generic" msgid="352500456918362905">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‎‏‏‏‎‎‏‏‏‎‎‏‎‎‎‏‎‏‎‏‎‏‎‏‎‎‏‏‎‎‎‏‎‎‎‏‎‏‏‏‎‎‏‎‎‎‎‎‏‎‏‎‏‏‎‎‎‏‏‎‎‏‎Can’t load status‎‏‎‎‏‎"</string>
<string name="controls_error_failed" msgid="960228639198558525">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‎‏‏‎‏‎‏‎‏‎‎‏‏‎‏‏‎‏‎‏‎‏‏‎‏‏‏‎‎‎‎‎‏‏‏‏‎‏‎‎‏‎‏‏‎‎‎‏‏‏‎‎‏‎‎‏‏‏‏‎‏‎Error, try again‎‏‎‎‏‎"</string>
<string name="controls_in_progress" msgid="4421080500238215939">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‏‏‎‏‎‏‎‏‏‎‏‎‏‏‎‏‎‏‎‏‎‏‎‎‏‎‏‎‏‎‎‎‎‏‎‎‎‎‎‏‏‎‏‎‏‏‏‎‏‎‏‏‎‎‎‎‎‎‏‏‎In progress‎‏‎‎‏‎"</string>
diff --git a/packages/SystemUI/res/values-es-rUS/strings.xml b/packages/SystemUI/res/values-es-rUS/strings.xml
index 31b48d9c8ebd..db5b68c0dd15 100644
--- a/packages/SystemUI/res/values-es-rUS/strings.xml
+++ b/packages/SystemUI/res/values-es-rUS/strings.xml
@@ -77,9 +77,6 @@
<string name="compat_mode_on" msgid="4963711187149440884">"Zoom para ocupar la pantalla"</string>
<string name="compat_mode_off" msgid="7682459748279487945">"Estirar p/ ocupar la pantalla"</string>
<string name="global_action_screenshot" msgid="2760267567509131654">"Captura de pantalla"</string>
- <string name="global_action_lock_message" product="default" msgid="4466026255205186456">"Desbloquea el teléfono para ver más opciones"</string>
- <string name="global_action_lock_message" product="tablet" msgid="7621167597240332986">"Desbloquea la tablet para ver más opciones"</string>
- <string name="global_action_lock_message" product="device" msgid="538790401275363781">"Desbloquea el dispositivo para ver más opciones"</string>
<string name="remote_input_image_insertion_text" msgid="4850791636452521123">"envió una imagen"</string>
<string name="screenshot_saving_ticker" msgid="6519186952674544916">"Guardando captura de pantalla"</string>
<string name="screenshot_saving_title" msgid="2298349784913287333">"Guardando la captura de pantalla..."</string>
@@ -722,7 +719,7 @@
<string name="notification_channel_summary_priority" msgid="7952654515769021553">"Aparece en la parte superior de la sección de conversaciones, en forma de burbuja flotante, y muestra la foto de perfil en la pantalla de bloqueo"</string>
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"Configuración"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"Prioridad"</string>
- <string name="no_shortcut" msgid="7176375126961212514">"<xliff:g id="APP_NAME">%1$s</xliff:g> no admite opciones de configuración específicas de conversaciones"</string>
+ <string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> no admite funciones de conversación"</string>
<string name="bubble_overflow_empty_title" msgid="3120029421991510842">"No hay burbujas recientes"</string>
<string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"Las burbujas recientes y las que se descartaron aparecerán aquí"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"No se pueden modificar estas notificaciones."</string>
@@ -1005,7 +1002,8 @@
<string name="bubble_accessibility_action_move_top_right" msgid="6916868852433483569">"Ubicar arriba a la derecha"</string>
<string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"Ubicar abajo a la izquierda"</string>
<string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"Ubicar abajo a la derecha"</string>
- <string name="bubble_dismiss_text" msgid="7071770411580452911">"Ignorar"</string>
+ <!-- no translation found for bubble_dismiss_text (1314082410868930066) -->
+ <skip />
<string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"No mostrar la conversación en burbujas"</string>
<string name="bubbles_user_education_title" msgid="5547017089271445797">"Chat con burbujas"</string>
<string name="bubbles_user_education_description" msgid="1160281719576715211">"Las conversaciones nuevas aparecen como elementos flotantes o burbujas. Presiona para abrir la burbuja. Arrástrala para moverla."</string>
@@ -1016,11 +1014,14 @@
<string name="notification_content_system_nav_changed" msgid="5077913144844684544">"Se actualizó el sistema de navegación. Para hacer cambios, ve a Configuración."</string>
<string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"Ve a Configuración para actualizar la navegación del sistema"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"En espera"</string>
+ <string name="priority_onboarding_title" msgid="2893070698479227616">"Se estableció la conversación como prioritaria"</string>
+ <string name="priority_onboarding_behavior" msgid="5342816047020432929">"Las conversaciones prioritarias harán lo siguiente:"</string>
<string name="priority_onboarding_show_at_top_text" msgid="1678400241025513541">"Se muestran en la parte superior de conversaciones"</string>
<string name="priority_onboarding_show_avatar_text" msgid="5756291381124091508">"Muestran una foto de perfil en pantalla de bloqueo"</string>
<string name="priority_onboarding_appear_as_bubble_text" msgid="4227039772250263122">"Aparecen como burbujas flotantes encima de apps"</string>
<string name="priority_onboarding_ignores_dnd_text" msgid="2918952762719600529">"Suspender No interrumpir"</string>
<string name="priority_onboarding_done_button_title" msgid="4569550984286506007">"Entendido"</string>
+ <string name="priority_onboarding_settings_button_title" msgid="6663601574303585927">"Configuración"</string>
<string name="magnification_overlay_title" msgid="6584179429612427958">"Ventana superpuesta de ampliación"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"Ventana de ampliación"</string>
<string name="magnification_controls_title" msgid="8421106606708891519">"Controles de ampliación de la ventana"</string>
@@ -1042,7 +1043,7 @@
<string name="accessibility_control_move" msgid="8980344493796647792">"Mover a la posición <xliff:g id="NUMBER">%d</xliff:g>"</string>
<string name="controls_favorite_default_title" msgid="967742178688938137">"Controles"</string>
<string name="controls_favorite_subtitle" msgid="6604402232298443956">"Elige los controles a los que quieres acceder desde el menú de encendido"</string>
- <string name="controls_favorite_rearrange" msgid="5616952398043063519">"Mantén presionado y arrastra para reorganizar los controles"</string>
+ <string name="controls_favorite_rearrange" msgid="5616952398043063519">"Mantén presionado y arrastra un control para reubicarlo"</string>
<string name="controls_favorite_removed" msgid="5276978408529217272">"Se quitaron todos los controles"</string>
<string name="controls_favorite_toast_no_changes" msgid="7094494210840877931">"No se guardaron los cambios"</string>
<string name="controls_favorite_load_error" msgid="2533215155804455348">"No se cargó la lista completa de controles."</string>
@@ -1062,9 +1063,13 @@
<string name="controls_structure_tooltip" msgid="4355922222944447867">"Desliza el dedo para ver más elementos"</string>
<string name="controls_seeding_in_progress" msgid="3033855341410264148">"Cargando recomendaciones"</string>
<string name="controls_media_close_session" msgid="9023534788828414585">"Cerrar esta sesión multimedia"</string>
+ <string name="controls_media_resume" msgid="1933520684481586053">"Reanudar"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"Inactivo. Verifica la app"</string>
<string name="controls_error_retryable" msgid="864025882878378470">"Hubo un error. Reintentando…"</string>
- <string name="controls_error_removed" msgid="6299213591234723805">"Se quitó el dispositivo"</string>
+ <string name="controls_error_removed" msgid="6675638069846014366">"No se encontró"</string>
+ <string name="controls_error_removed_title" msgid="1207794911208047818">"El control no está disponible."</string>
+ <string name="controls_error_removed_message" msgid="2885911717034750542">"No se pudo acceder a <xliff:g id="DEVICE">%1$s</xliff:g>. Revisa la app de <xliff:g id="APPLICATION">%2$s</xliff:g> para asegurarte de que el control siga estando disponible y de que no haya cambiado la configuración de la app."</string>
+ <string name="controls_open_app" msgid="483650971094300141">"Abrir app"</string>
<string name="controls_error_generic" msgid="352500456918362905">"No se pudo cargar el estado"</string>
<string name="controls_error_failed" msgid="960228639198558525">"Error. Vuelve a intentarlo."</string>
<string name="controls_in_progress" msgid="4421080500238215939">"En curso"</string>
diff --git a/packages/SystemUI/res/values-es/strings.xml b/packages/SystemUI/res/values-es/strings.xml
index cdfad83af199..1d8549a78efa 100644
--- a/packages/SystemUI/res/values-es/strings.xml
+++ b/packages/SystemUI/res/values-es/strings.xml
@@ -77,9 +77,6 @@
<string name="compat_mode_on" msgid="4963711187149440884">"Zoom para ajustar"</string>
<string name="compat_mode_off" msgid="7682459748279487945">"Expandir para ajustar"</string>
<string name="global_action_screenshot" msgid="2760267567509131654">"Captura de pantalla"</string>
- <string name="global_action_lock_message" product="default" msgid="4466026255205186456">"Desbloquea el teléfono para ver más opciones"</string>
- <string name="global_action_lock_message" product="tablet" msgid="7621167597240332986">"Desbloquea el tablet para ver más opciones"</string>
- <string name="global_action_lock_message" product="device" msgid="538790401275363781">"Desbloquea el dispositivo para ver más opciones"</string>
<string name="remote_input_image_insertion_text" msgid="4850791636452521123">"ha enviado una imagen"</string>
<string name="screenshot_saving_ticker" msgid="6519186952674544916">"Guardando captura..."</string>
<string name="screenshot_saving_title" msgid="2298349784913287333">"Guardando captura..."</string>
@@ -451,7 +448,7 @@
<string name="zen_alarms_introduction" msgid="3987266042682300470">"No te molestarán los sonidos ni las vibraciones, excepto las alarmas. Seguirás escuchando el contenido que quieras reproducir, como música, vídeos y juegos."</string>
<string name="zen_priority_customize_button" msgid="4119213187257195047">"Personalizar"</string>
<string name="zen_silence_introduction_voice" msgid="853573681302712348">"Esta opción bloqueará TODOS los sonidos y todas las vibraciones, por ejemplo, los vídeos, los juegos, las alarmas y la música. Seguirás pudiendo hacer llamadas."</string>
- <string name="zen_silence_introduction" msgid="6117517737057344014">"Este modo permite bloquear TODOS los sonidos y todas las vibraciones (p. ej., los de alarmas, música, vídeos y juegos)."</string>
+ <string name="zen_silence_introduction" msgid="6117517737057344014">"Este modo bloquea TODOS los sonidos y todas las vibraciones, lo que incluye alarmas, música, vídeos y juegos."</string>
<string name="keyguard_more_overflow_text" msgid="5819512373606638727">"+<xliff:g id="NUMBER_OF_NOTIFICATIONS">%d</xliff:g>"</string>
<string name="speed_bump_explanation" msgid="7248696377626341060">"Notificaciones menos urgente abajo"</string>
<string name="notification_tap_again" msgid="4477318164947497249">"Toca de nuevo para abrir"</string>
@@ -517,7 +514,7 @@
<string name="notification_section_header_gentle" msgid="6804099527336337197">"Silenciadas"</string>
<string name="notification_section_header_alerting" msgid="5581175033680477651">"Notificaciones"</string>
<string name="notification_section_header_conversations" msgid="821834744538345661">"Conversaciones"</string>
- <string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"Borrar todas las notificaciones silenciadas"</string>
+ <string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"Borrar todas las notificaciones silenciosas"</string>
<string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"Notificaciones pausadas por el modo No molestar"</string>
<string name="media_projection_action_text" msgid="3634906766918186440">"Empezar ahora"</string>
<string name="empty_shade_text" msgid="8935967157319717412">"No hay notificaciones"</string>
@@ -601,11 +598,11 @@
<string name="screen_pinning_description_gestural" msgid="7246323931831232068">"Se mantiene visible hasta que dejas de fijarla. Para ello, desliza el dedo hacia arriba y mantén pulsado."</string>
<string name="screen_pinning_description_accessible" msgid="7386449191953535332">"La pantalla se mantiene visible hasta que dejas de fijarla. Para ello, mantén pulsado el botón Aplicaciones recientes."</string>
<string name="screen_pinning_description_recents_invisible_accessible" msgid="2857071808674481986">"La pantalla se mantiene visible hasta que dejas de fijarla. Para ello, mantén pulsado el botón Inicio."</string>
- <string name="screen_pinning_exposes_personal_data" msgid="8189852022981524789">"Quizá se pueda acceder a datos personales, como contactos o el contenido de correos."</string>
+ <string name="screen_pinning_exposes_personal_data" msgid="8189852022981524789">"Es posible que se revelen datos personales, como contactos o el contenido de correos."</string>
<string name="screen_pinning_can_open_other_apps" msgid="7529756813231421455">"Se pueden abrir otras aplicaciones desde aplicaciones fijadas."</string>
<string name="screen_pinning_toast" msgid="8177286912533744328">"Para dejar de fijar esta aplicación, mantén pulsados los botones Atrás y Aplicaciones recientes"</string>
<string name="screen_pinning_toast_recents_invisible" msgid="6850978077443052594">"Para dejar de fijar esta aplicación, mantén pulsados los botones Atrás e Inicio"</string>
- <string name="screen_pinning_toast_gesture_nav" msgid="170699893395336705">"Para dejar de fijar esta aplicación, desliza el dedo hacia arriba y mantén pulsada la pantalla"</string>
+ <string name="screen_pinning_toast_gesture_nav" msgid="170699893395336705">"Para dejar de fijar esta aplicación, desliza el dedo hacia arriba y mantenlo pulsado"</string>
<string name="screen_pinning_positive" msgid="3285785989665266984">"Entendido"</string>
<string name="screen_pinning_negative" msgid="6882816864569211666">"No, gracias"</string>
<string name="screen_pinning_start" msgid="7483998671383371313">"Aplicación fijada"</string>
@@ -712,17 +709,17 @@
<string name="inline_turn_off_notifications" msgid="8543989584403106071">"Desactivar notificaciones"</string>
<string name="inline_keep_showing_app" msgid="4393429060390649757">"¿Quieres seguir viendo las notificaciones de esta aplicación?"</string>
<string name="notification_silence_title" msgid="8608090968400832335">"Silencio"</string>
- <string name="notification_alert_title" msgid="3656229781017543655">"Predeterminada"</string>
+ <string name="notification_alert_title" msgid="3656229781017543655">"Predeterminado"</string>
<string name="notification_bubble_title" msgid="8330481035191903164">"Burbuja"</string>
<string name="notification_channel_summary_low" msgid="4860617986908931158">"Sin sonido ni vibración"</string>
<string name="notification_conversation_summary_low" msgid="1734433426085468009">"Sin sonido ni vibración y se muestra más abajo en la sección de conversaciones"</string>
- <string name="notification_channel_summary_default" msgid="3282930979307248890">"Según los ajustes definidos en el teléfono, es posible que suene o vibre"</string>
- <string name="notification_channel_summary_default_with_bubbles" msgid="1782419896613644568">"Según los ajustes definidos en el teléfono, es posible que suene o vibre. Las conversaciones de <xliff:g id="APP_NAME">%1$s</xliff:g> aparecen como burbujas de forma predeterminada."</string>
+ <string name="notification_channel_summary_default" msgid="3282930979307248890">"Es posible que suene o vibre según los ajustes del teléfono"</string>
+ <string name="notification_channel_summary_default_with_bubbles" msgid="1782419896613644568">"Es posible que suene o vibre según los ajustes del teléfono. Las conversaciones de <xliff:g id="APP_NAME">%1$s</xliff:g> aparecen como burbujas de forma predeterminada."</string>
<string name="notification_channel_summary_bubble" msgid="7235935211580860537">"Llama tu atención con un acceso directo flotante a este contenido."</string>
<string name="notification_channel_summary_priority" msgid="7952654515769021553">"Se muestra en la parte superior de la sección de conversaciones en forma de burbuja flotante, y la imagen de perfil aparece en la pantalla de bloqueo"</string>
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"Ajustes"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"Prioridad"</string>
- <string name="no_shortcut" msgid="7176375126961212514">"<xliff:g id="APP_NAME">%1$s</xliff:g> no es compatible con ajustes específicos de conversaciones"</string>
+ <string name="no_shortcut" msgid="8257177117568230126">"No se pueden usar funciones de conversación con <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
<string name="bubble_overflow_empty_title" msgid="3120029421991510842">"No hay burbujas recientes"</string>
<string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"Las burbujas recientes y las cerradas aparecerán aquí"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"Estas notificaciones no se pueden modificar."</string>
@@ -1005,10 +1002,11 @@
<string name="bubble_accessibility_action_move_top_right" msgid="6916868852433483569">"Mover arriba a la derecha"</string>
<string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"Mover abajo a la izquierda."</string>
<string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"Mover abajo a la derecha"</string>
- <string name="bubble_dismiss_text" msgid="7071770411580452911">"Cerrar"</string>
+ <!-- no translation found for bubble_dismiss_text (1314082410868930066) -->
+ <skip />
<string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"No mostrar conversación en burbujas"</string>
- <string name="bubbles_user_education_title" msgid="5547017089271445797">"Chatear mediante burbujas"</string>
- <string name="bubbles_user_education_description" msgid="1160281719576715211">"Las conversaciones nuevas aparecen como iconos flotantes o burbujas. Toca para abrir la burbuja. Arrastra para moverla."</string>
+ <string name="bubbles_user_education_title" msgid="5547017089271445797">"Chatea con burbujas"</string>
+ <string name="bubbles_user_education_description" msgid="1160281719576715211">"Las conversaciones nuevas aparecen como iconos flotantes llamadas \"burbujas\". Toca para abrir la burbuja. Arrastra para moverla."</string>
<string name="bubbles_user_education_manage_title" msgid="2848511858160342320">"Controla las burbujas en cualquier momento"</string>
<string name="bubbles_user_education_manage" msgid="1391639189507036423">"Toca Gestionar para desactivar las burbujas de esta aplicación"</string>
<string name="bubbles_user_education_got_it" msgid="8282812431953161143">"Entendido"</string>
@@ -1016,16 +1014,19 @@
<string name="notification_content_system_nav_changed" msgid="5077913144844684544">"Se ha actualizado la navegación del sistema. Para hacer cambios, ve a Ajustes."</string>
<string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"Ve a Ajustes para actualizar la navegación del sistema"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"En espera"</string>
+ <string name="priority_onboarding_title" msgid="2893070698479227616">"Conversación marcada como prioritaria"</string>
+ <string name="priority_onboarding_behavior" msgid="5342816047020432929">"Las conversaciones prioritarias:"</string>
<string name="priority_onboarding_show_at_top_text" msgid="1678400241025513541">"Se muestran en la parte superior de la sección de conversaciones"</string>
- <string name="priority_onboarding_show_avatar_text" msgid="5756291381124091508">"Muestran tu imagen de perfil en la pantalla de bloqueo"</string>
+ <string name="priority_onboarding_show_avatar_text" msgid="5756291381124091508">"Muestran la imagen de perfil en la pantalla de bloqueo"</string>
<string name="priority_onboarding_appear_as_bubble_text" msgid="4227039772250263122">"Aparecen como burbuja sobre las aplicaciones"</string>
<string name="priority_onboarding_ignores_dnd_text" msgid="2918952762719600529">"Interrumpen el modo No molestar"</string>
<string name="priority_onboarding_done_button_title" msgid="4569550984286506007">"Entendido"</string>
+ <string name="priority_onboarding_settings_button_title" msgid="6663601574303585927">"Ajustes"</string>
<string name="magnification_overlay_title" msgid="6584179429612427958">"Ventana de superposición de ampliación"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"Ventana de ampliación"</string>
<string name="magnification_controls_title" msgid="8421106606708891519">"Ventana de controles de ampliación"</string>
<string name="quick_controls_title" msgid="6839108006171302273">"Control de dispositivos"</string>
- <string name="quick_controls_subtitle" msgid="1667408093326318053">"Añade controles a tus dispositivos conectados"</string>
+ <string name="quick_controls_subtitle" msgid="1667408093326318053">"Añade controles para tus dispositivos conectados"</string>
<string name="quick_controls_setup_title" msgid="8901436655997849822">"Configurar control de dispositivos"</string>
<string name="quick_controls_setup_subtitle" msgid="1681506617879773824">"Mantén pulsado el botón de encendido para acceder a tus controles"</string>
<string name="controls_providers_title" msgid="6879775889857085056">"Elige una aplicación para añadir controles"</string>
@@ -1052,7 +1053,7 @@
<string name="controls_dialog_message" msgid="342066938390663844">"Sugerido por <xliff:g id="APP">%s</xliff:g>"</string>
<string name="controls_dialog_confirmation" msgid="586517302736263447">"Controles actualizados"</string>
<string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"El PIN contiene letras o símbolos"</string>
- <string name="controls_pin_verify" msgid="3452778292918877662">"Verificar <xliff:g id="DEVICE">%s</xliff:g>"</string>
+ <string name="controls_pin_verify" msgid="3452778292918877662">"Verifica <xliff:g id="DEVICE">%s</xliff:g>"</string>
<string name="controls_pin_wrong" msgid="6162694056042164211">"PIN incorrecto"</string>
<string name="controls_pin_verifying" msgid="3755045989392131746">"Verificando…"</string>
<string name="controls_pin_instructions" msgid="6363309783822475238">"Introduce el PIN"</string>
@@ -1062,9 +1063,13 @@
<string name="controls_structure_tooltip" msgid="4355922222944447867">"Desliza el dedo para ver más"</string>
<string name="controls_seeding_in_progress" msgid="3033855341410264148">"Cargando recomendaciones"</string>
<string name="controls_media_close_session" msgid="9023534788828414585">"Cerrar esta sesión multimedia"</string>
+ <string name="controls_media_resume" msgid="1933520684481586053">"Reanudar"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"Inactivo, comprobar aplicación"</string>
<string name="controls_error_retryable" msgid="864025882878378470">"Error; reintentando…"</string>
- <string name="controls_error_removed" msgid="6299213591234723805">"Dispositivo quitado"</string>
+ <string name="controls_error_removed" msgid="6675638069846014366">"No se ha encontrado"</string>
+ <string name="controls_error_removed_title" msgid="1207794911208047818">"El control no está disponible"</string>
+ <string name="controls_error_removed_message" msgid="2885911717034750542">"No se ha podido acceder a <xliff:g id="DEVICE">%1$s</xliff:g>. Comprueba que el control siga disponible en la aplicación <xliff:g id="APPLICATION">%2$s</xliff:g> y que no se haya modificado su configuración."</string>
+ <string name="controls_open_app" msgid="483650971094300141">"Abrir aplicación"</string>
<string name="controls_error_generic" msgid="352500456918362905">"No se ha podido cargar el estado"</string>
<string name="controls_error_failed" msgid="960228639198558525">"Se ha producido un error. Vuelve a intentarlo."</string>
<string name="controls_in_progress" msgid="4421080500238215939">"En curso"</string>
diff --git a/packages/SystemUI/res/values-et/strings.xml b/packages/SystemUI/res/values-et/strings.xml
index 2e29befd6189..ede01b7f191c 100644
--- a/packages/SystemUI/res/values-et/strings.xml
+++ b/packages/SystemUI/res/values-et/strings.xml
@@ -77,9 +77,6 @@
<string name="compat_mode_on" msgid="4963711187149440884">"Suumi ekraani täitmiseks"</string>
<string name="compat_mode_off" msgid="7682459748279487945">"Venita ekraani täitmiseks"</string>
<string name="global_action_screenshot" msgid="2760267567509131654">"Ekraanipilt"</string>
- <string name="global_action_lock_message" product="default" msgid="4466026255205186456">"Lisavalikute nägemiseks avage oma telefon"</string>
- <string name="global_action_lock_message" product="tablet" msgid="7621167597240332986">"Lisavalikute nägemiseks avage oma tahvelarvuti"</string>
- <string name="global_action_lock_message" product="device" msgid="538790401275363781">"Lisavalikute nägemiseks avage oma seade"</string>
<string name="remote_input_image_insertion_text" msgid="4850791636452521123">"saatis kujutise"</string>
<string name="screenshot_saving_ticker" msgid="6519186952674544916">"Kuvatõmmise salvestamine ..."</string>
<string name="screenshot_saving_title" msgid="2298349784913287333">"Kuvatõmmise salvestamine ..."</string>
@@ -95,7 +92,7 @@
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Ekraanisalvestuse töötlemine"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"Pooleli märguanne ekraanikuva salvestamise seansi puhul"</string>
<string name="screenrecord_start_label" msgid="1750350278888217473">"Kas alustada salvestamist?"</string>
- <string name="screenrecord_description" msgid="1123231719680353736">"Heli salvestamise ajal võib Androidi süsteem jäädvustada tundlikku teavet, mis on ekraanikuval nähtav või mida seadmes esitatakse. See hõlmab paroole, makseteavet, fotosid, sõnumeid ja heli."</string>
+ <string name="screenrecord_description" msgid="1123231719680353736">"Salvestamise ajal võib Androidi süsteem jäädvustada tundlikku teavet, mis on ekraanikuval nähtav või mida seadmes esitatakse. See hõlmab paroole, makseteavet, fotosid, sõnumeid ja heli."</string>
<string name="screenrecord_audio_label" msgid="6183558856175159629">"Heli salvestamine"</string>
<string name="screenrecord_device_audio_label" msgid="9016927171280567791">"Seadme heli"</string>
<string name="screenrecord_device_audio_description" msgid="4922694220572186193">"Seadmest pärinev heli, nt muusika, kõned ja helinad"</string>
@@ -595,29 +592,21 @@
<string name="volume_odi_captions_hint_enable" msgid="2073091194012843195">"luba"</string>
<string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"keela"</string>
<string name="accessibility_output_chooser" msgid="7807898688967194183">"Väljundseadme vahetamine"</string>
- <!-- no translation found for screen_pinning_title (9058007390337841305) -->
- <skip />
+ <string name="screen_pinning_title" msgid="9058007390337841305">"Rakendus on kinnitatud"</string>
<string name="screen_pinning_description" msgid="8699395373875667743">"See hoitakse kuval, kuni selle vabastate. Vabastamiseks puudutage pikalt nuppe Tagasi ja Ülevaade."</string>
<string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"See hoitakse kuval, kuni selle vabastate. Vabastamiseks puudutage pikalt nuppe Tagasi ja Avakuva."</string>
<string name="screen_pinning_description_gestural" msgid="7246323931831232068">"See hoitakse kuval, kuni selle vabastate. Vabastamiseks pühkige üles ja hoidke sõrme ekraanil."</string>
<string name="screen_pinning_description_accessible" msgid="7386449191953535332">"See hoitakse kuval, kuni selle vabastate. Vabastamiseks puudutage pikalt nuppu Ülevaade."</string>
<string name="screen_pinning_description_recents_invisible_accessible" msgid="2857071808674481986">"See hoitakse kuval, kuni selle vabastate. Vabastamiseks puudutage pikalt nuppu Avakuva."</string>
- <!-- no translation found for screen_pinning_exposes_personal_data (8189852022981524789) -->
- <skip />
- <!-- no translation found for screen_pinning_can_open_other_apps (7529756813231421455) -->
- <skip />
- <!-- no translation found for screen_pinning_toast (8177286912533744328) -->
- <skip />
- <!-- no translation found for screen_pinning_toast_recents_invisible (6850978077443052594) -->
- <skip />
- <!-- no translation found for screen_pinning_toast_gesture_nav (170699893395336705) -->
- <skip />
+ <string name="screen_pinning_exposes_personal_data" msgid="8189852022981524789">"Isiklikud andmed (nt kontaktid ja meilide sisu) võivad olla juurdepääsetavad."</string>
+ <string name="screen_pinning_can_open_other_apps" msgid="7529756813231421455">"Kinnitatud rakendused võivad avada muid rakendusi."</string>
+ <string name="screen_pinning_toast" msgid="8177286912533744328">"Rakenduse vabastamiseks puudutage pikalt nuppe Tagasi ja Ülevaade"</string>
+ <string name="screen_pinning_toast_recents_invisible" msgid="6850978077443052594">"Rakenduse vabastamiseks puudutage pikalt nuppe Tagasi ja Avaekraan"</string>
+ <string name="screen_pinning_toast_gesture_nav" msgid="170699893395336705">"Rakenduse vabastamiseks pühkige üles ja hoidke sõrme ekraanil"</string>
<string name="screen_pinning_positive" msgid="3285785989665266984">"Selge"</string>
<string name="screen_pinning_negative" msgid="6882816864569211666">"Tänan, ei"</string>
- <!-- no translation found for screen_pinning_start (7483998671383371313) -->
- <skip />
- <!-- no translation found for screen_pinning_exit (4553787518387346893) -->
- <skip />
+ <string name="screen_pinning_start" msgid="7483998671383371313">"Rakendus on kinnitatud"</string>
+ <string name="screen_pinning_exit" msgid="4553787518387346893">"Rakendus on vabastatud"</string>
<string name="quick_settings_reset_confirmation_title" msgid="463533331480997595">"Kas peita <xliff:g id="TILE_LABEL">%1$s</xliff:g>?"</string>
<string name="quick_settings_reset_confirmation_message" msgid="2320586180785674186">"See kuvatakse uuesti järgmisel korral, kui selle seadetes sisse lülitate."</string>
<string name="quick_settings_reset_confirmation_button" msgid="3341477479055016776">"Peida"</string>
@@ -730,7 +719,7 @@
<string name="notification_channel_summary_priority" msgid="7952654515769021553">"Kuvatakse vestluste jaotise ülaosas hõljuva mullina ja lukustuskuval kuvatakse profiilipilt"</string>
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"Seaded"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"Prioriteetne"</string>
- <string name="no_shortcut" msgid="7176375126961212514">"<xliff:g id="APP_NAME">%1$s</xliff:g> ei toeta vestluspõhiseid seadeid"</string>
+ <string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> ei toeta vestlusfunktsioone"</string>
<string name="bubble_overflow_empty_title" msgid="3120029421991510842">"Hiljutisi mulle pole"</string>
<string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"Siin kuvatakse hiljutised ja suletud mullid."</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"Neid märguandeid ei saa muuta."</string>
@@ -1013,7 +1002,8 @@
<string name="bubble_accessibility_action_move_top_right" msgid="6916868852433483569">"Teisalda üles paremale"</string>
<string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"Teisalda alla vasakule"</string>
<string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"Teisalda alla paremale"</string>
- <string name="bubble_dismiss_text" msgid="7071770411580452911">"Loobu"</string>
+ <!-- no translation found for bubble_dismiss_text (1314082410868930066) -->
+ <skip />
<string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"Ära kuva vestlust mullina"</string>
<string name="bubbles_user_education_title" msgid="5547017089271445797">"Vestelge mullide abil"</string>
<string name="bubbles_user_education_description" msgid="1160281719576715211">"Uued vestlused kuvatakse hõljuvate ikoonidena ehk mullidena. Puudutage mulli avamiseks. Lohistage mulli, et seda liigutada."</string>
@@ -1024,11 +1014,14 @@
<string name="notification_content_system_nav_changed" msgid="5077913144844684544">"Süsteemis navigeerimine on värskendatud. Muutmiseks avage jaotis Seaded."</string>
<string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"Süsteemi navigeerimise värskendamiseks avage jaotis Seaded"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Ooterežiim"</string>
+ <string name="priority_onboarding_title" msgid="2893070698479227616">"Vestlus määrati prioriteetseks"</string>
+ <string name="priority_onboarding_behavior" msgid="5342816047020432929">"Prioriteetsed vestlused teevad järgmist."</string>
<string name="priority_onboarding_show_at_top_text" msgid="1678400241025513541">"Kuvatakse vestluste jaotise kohal"</string>
<string name="priority_onboarding_show_avatar_text" msgid="5756291381124091508">"Lukustuskuval kuvatakse profiilipilt"</string>
<string name="priority_onboarding_appear_as_bubble_text" msgid="4227039772250263122">"Kuvatakse rakenduste kohal hõljuva mullina"</string>
<string name="priority_onboarding_ignores_dnd_text" msgid="2918952762719600529">"Funktsioon Mitte segada katkestatakse"</string>
<string name="priority_onboarding_done_button_title" msgid="4569550984286506007">"Selge"</string>
+ <string name="priority_onboarding_settings_button_title" msgid="6663601574303585927">"Seaded"</string>
<string name="magnification_overlay_title" msgid="6584179429612427958">"Suurendamisakna ülekate"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"Suurendamisaken"</string>
<string name="magnification_controls_title" msgid="8421106606708891519">"Suurendamisakna juhtelemendid"</string>
@@ -1050,8 +1043,8 @@
<string name="accessibility_control_move" msgid="8980344493796647792">"Teisalda asendisse <xliff:g id="NUMBER">%d</xliff:g>"</string>
<string name="controls_favorite_default_title" msgid="967742178688938137">"Juhtnupud"</string>
<string name="controls_favorite_subtitle" msgid="6604402232298443956">"Valige toitemenüüs saadaolevad juhtelemendid"</string>
- <string name="controls_favorite_rearrange" msgid="5616952398043063519">"Juhtnuppude ümberpaigutamiseks hoidke neid all ja lohistage"</string>
- <string name="controls_favorite_removed" msgid="5276978408529217272">"Kõik juhtnupud eemaldati"</string>
+ <string name="controls_favorite_rearrange" msgid="5616952398043063519">"Juhtelementide ümberpaigutamiseks hoidke neid all ja lohistage"</string>
+ <string name="controls_favorite_removed" msgid="5276978408529217272">"Kõik juhtelemendid eemaldati"</string>
<string name="controls_favorite_toast_no_changes" msgid="7094494210840877931">"Muudatusi ei salvestatud"</string>
<string name="controls_favorite_load_error" msgid="2533215155804455348">"Kõikide juhtelementide loendit ei saanud laadida."</string>
<string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Muu"</string>
@@ -1070,9 +1063,13 @@
<string name="controls_structure_tooltip" msgid="4355922222944447867">"Pühkige sõrmega, et näha rohkem"</string>
<string name="controls_seeding_in_progress" msgid="3033855341410264148">"Soovituste laadimine"</string>
<string name="controls_media_close_session" msgid="9023534788828414585">"Sulge see meediaseanss"</string>
+ <string name="controls_media_resume" msgid="1933520684481586053">"Jätka"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"Passiivne, vaadake rakendust"</string>
<string name="controls_error_retryable" msgid="864025882878378470">"Viga, proovitakse uuesti …"</string>
- <string name="controls_error_removed" msgid="6299213591234723805">"Seade on eemaldatud"</string>
+ <string name="controls_error_removed" msgid="6675638069846014366">"Ei leitud"</string>
+ <string name="controls_error_removed_title" msgid="1207794911208047818">"Juhtelement pole saadaval"</string>
+ <string name="controls_error_removed_message" msgid="2885911717034750542">"Seadmele <xliff:g id="DEVICE">%1$s</xliff:g> ei pääsenud juurde. Kontrollige rakendust <xliff:g id="APPLICATION">%2$s</xliff:g> ja veenduge, et juhtelement oleks endiselt saadaval ning rakenduse seaded poleks muutunud."</string>
+ <string name="controls_open_app" msgid="483650971094300141">"Ava rakendus"</string>
<string name="controls_error_generic" msgid="352500456918362905">"Olekut ei saa laadida"</string>
<string name="controls_error_failed" msgid="960228639198558525">"Ilmnes viga, proovige uuesti"</string>
<string name="controls_in_progress" msgid="4421080500238215939">"Pooleli"</string>
diff --git a/packages/SystemUI/res/values-eu/strings.xml b/packages/SystemUI/res/values-eu/strings.xml
index 8e38736ecbdf..641d031ef4aa 100644
--- a/packages/SystemUI/res/values-eu/strings.xml
+++ b/packages/SystemUI/res/values-eu/strings.xml
@@ -77,9 +77,6 @@
<string name="compat_mode_on" msgid="4963711187149440884">"Handiagotu pantaila betetzeko"</string>
<string name="compat_mode_off" msgid="7682459748279487945">"Luzatu pantaila betetzeko"</string>
<string name="global_action_screenshot" msgid="2760267567509131654">"Pantaila-argazkia"</string>
- <string name="global_action_lock_message" product="default" msgid="4466026255205186456">"Desblokeatu telefonoa aukera gehiago ikusteko"</string>
- <string name="global_action_lock_message" product="tablet" msgid="7621167597240332986">"Desblokeatu tableta aukera gehiago ikusteko"</string>
- <string name="global_action_lock_message" product="device" msgid="538790401275363781">"Desblokeatu gailua aukera gehiago ikusteko"</string>
<string name="remote_input_image_insertion_text" msgid="4850791636452521123">"erabiltzaileak irudi bat bidali du"</string>
<string name="screenshot_saving_ticker" msgid="6519186952674544916">"Pantaila-argazkia gordetzen…"</string>
<string name="screenshot_saving_title" msgid="2298349784913287333">"Pantaila-argazkia gordetzen…"</string>
@@ -714,15 +711,15 @@
<string name="notification_silence_title" msgid="8608090968400832335">"Isila"</string>
<string name="notification_alert_title" msgid="3656229781017543655">"Balio lehenetsia"</string>
<string name="notification_bubble_title" msgid="8330481035191903164">"Burbuila"</string>
- <string name="notification_channel_summary_low" msgid="4860617986908931158">"Ez du jotzen tonua edo egiten dar-dar"</string>
- <string name="notification_conversation_summary_low" msgid="1734433426085468009">"Ez du jotzen tonua edo egiten dar-dar, eta elkarrizketaren atalaren behealdean agertzen da"</string>
+ <string name="notification_channel_summary_low" msgid="4860617986908931158">"Ez du tonurik jotzen edo dar-dar egiten"</string>
+ <string name="notification_conversation_summary_low" msgid="1734433426085468009">"Ez du tonurik jotzen edo dar-dar egiten, eta elkarrizketaren atalaren behealdean agertzen da"</string>
<string name="notification_channel_summary_default" msgid="3282930979307248890">"Tonua jo edo dar-dar egin dezake, telefonoaren ezarpenen arabera"</string>
<string name="notification_channel_summary_default_with_bubbles" msgid="1782419896613644568">"Tonua jo edo dar-dar egin dezake, telefonoaren ezarpenen arabera. Modu lehenetsian, <xliff:g id="APP_NAME">%1$s</xliff:g> aplikazioko elkarrizketak burbuila gisa agertzen dira."</string>
<string name="notification_channel_summary_bubble" msgid="7235935211580860537">"Eduki honetarako lasterbide gainerakor bat eskaintzen dizu, arretarik gal ez dezazun."</string>
<string name="notification_channel_summary_priority" msgid="7952654515769021553">"Burbuila gisa agertzen da elkarrizketen atalaren goialdean, eta profileko argazkia bistaratzen du pantaila blokeatuta dagoenean"</string>
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"Ezarpenak"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"Lehentasuna"</string>
- <string name="no_shortcut" msgid="7176375126961212514">"<xliff:g id="APP_NAME">%1$s</xliff:g> aplikazioak ez du onartzen elkarrizketen berariazko ezarpenik"</string>
+ <string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> aplikazioak ez ditu onartzen elkarrizketetarako eginbideak"</string>
<string name="bubble_overflow_empty_title" msgid="3120029421991510842">"Ez dago azkenaldiko burbuilarik"</string>
<string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"Azken burbuilak eta baztertutakoak agertuko dira hemen"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"Jakinarazpen horiek ezin dira aldatu."</string>
@@ -1005,7 +1002,8 @@
<string name="bubble_accessibility_action_move_top_right" msgid="6916868852433483569">"Eraman goialdera, eskuinetara"</string>
<string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"Eraman behealdera, ezkerretara"</string>
<string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"Eraman behealdera, eskuinetara"</string>
- <string name="bubble_dismiss_text" msgid="7071770411580452911">"Baztertu"</string>
+ <!-- no translation found for bubble_dismiss_text (1314082410868930066) -->
+ <skip />
<string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"Ez erakutsi elkarrizketak burbuila gisa"</string>
<string name="bubbles_user_education_title" msgid="5547017089271445797">"Txateatu burbuilen bidez"</string>
<string name="bubbles_user_education_description" msgid="1160281719576715211">"Elkarrizketa berriak ikono gainerakor edo burbuila gisa agertzen dira. Sakatu burbuila irekitzeko. Arrasta ezazu mugitzeko."</string>
@@ -1016,11 +1014,14 @@
<string name="notification_content_system_nav_changed" msgid="5077913144844684544">"Eguneratu da sistemaren nabigazioa. Aldaketak egiteko, joan Ezarpenak atalera."</string>
<string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"Sistemaren nabigazioa eguneratzeko, joan Ezarpenak atalera"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Egonean"</string>
+ <string name="priority_onboarding_title" msgid="2893070698479227616">"Lehentasunezko gisa ezarritako elkarrizketa"</string>
+ <string name="priority_onboarding_behavior" msgid="5342816047020432929">"Hau gertatuko da lehentasunezko elkarrizketekin:"</string>
<string name="priority_onboarding_show_at_top_text" msgid="1678400241025513541">"Erakutsi elkarrizketen atalaren goialdean"</string>
<string name="priority_onboarding_show_avatar_text" msgid="5756291381124091508">"Erakutsi profileko argazkia pantaila blokeatuan"</string>
<string name="priority_onboarding_appear_as_bubble_text" msgid="4227039772250263122">"Burbuila gainerakor gisa agertuko da aplikazioen gainean"</string>
<string name="priority_onboarding_ignores_dnd_text" msgid="2918952762719600529">"Eten ez molestatzeko modua"</string>
<string name="priority_onboarding_done_button_title" msgid="4569550984286506007">"Ados"</string>
+ <string name="priority_onboarding_settings_button_title" msgid="6663601574303585927">"Ezarpenak"</string>
<string name="magnification_overlay_title" msgid="6584179429612427958">"Lupa-leiho gainjarria"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"Lupa-leihoa"</string>
<string name="magnification_controls_title" msgid="8421106606708891519">"Lupa-leihoaren aukerak"</string>
@@ -1043,7 +1044,7 @@
<string name="controls_favorite_default_title" msgid="967742178688938137">"Kontrolatzeko aukerak"</string>
<string name="controls_favorite_subtitle" msgid="6604402232298443956">"Aukeratu itzaltzeko menutik atzitu nahi dituzun kontrolatzeko aukerak"</string>
<string name="controls_favorite_rearrange" msgid="5616952398043063519">"Kontrolatzeko aukerak antolatzeko, eduki itzazu sakatuta, eta arrastatu"</string>
- <string name="controls_favorite_removed" msgid="5276978408529217272">"Kontrolatzeko aukera guztiak kendu dira"</string>
+ <string name="controls_favorite_removed" msgid="5276978408529217272">"Kendu dira kontrolatzeko aukera guztiak"</string>
<string name="controls_favorite_toast_no_changes" msgid="7094494210840877931">"Ez dira gorde aldaketak"</string>
<string name="controls_favorite_load_error" msgid="2533215155804455348">"Ezin izan da kargatu kontrol guztien zerrenda."</string>
<string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Beste bat"</string>
@@ -1056,19 +1057,23 @@
<string name="controls_pin_wrong" msgid="6162694056042164211">"PIN okerra"</string>
<string name="controls_pin_verifying" msgid="3755045989392131746">"Egiaztatzen…"</string>
<string name="controls_pin_instructions" msgid="6363309783822475238">"Idatzi PIN kodea"</string>
- <string name="controls_pin_instructions_retry" msgid="1566667581012131046">"Saiatu beste PIN kode batekin"</string>
+ <string name="controls_pin_instructions_retry" msgid="1566667581012131046">"Saiatu beste PIN batekin"</string>
<string name="controls_confirmation_confirming" msgid="2596071302617310665">"Berresten…"</string>
<string name="controls_confirmation_message" msgid="7744104992609594859">"Berretsi <xliff:g id="DEVICE">%s</xliff:g> gailuaren aldaketa"</string>
<string name="controls_structure_tooltip" msgid="4355922222944447867">"Pasatu hatza aukera gehiago ikusteko"</string>
<string name="controls_seeding_in_progress" msgid="3033855341410264148">"Gomendioak kargatzen"</string>
<string name="controls_media_close_session" msgid="9023534788828414585">"Itxi multimedia-saio hau"</string>
+ <string name="controls_media_resume" msgid="1933520684481586053">"Berrekin"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"Inaktibo; egiaztatu aplikazioa"</string>
<string name="controls_error_retryable" msgid="864025882878378470">"Errorea. Berriro saiatzen…"</string>
- <string name="controls_error_removed" msgid="6299213591234723805">"Gailua kendu da"</string>
+ <string name="controls_error_removed" msgid="6675638069846014366">"Ez da aurkitu"</string>
+ <string name="controls_error_removed_title" msgid="1207794911208047818">"Ez dago erabilgarri kontrolatzeko aukera"</string>
+ <string name="controls_error_removed_message" msgid="2885911717034750542">"Ezin izan da atzitu <xliff:g id="DEVICE">%1$s</xliff:g>. Joan <xliff:g id="APPLICATION">%2$s</xliff:g> aplikaziora, eta ziurtatu kontrolatzeko aukera oraindik ere erabilgarri dagoela eta aplikazioaren ezarpenak ez direla aldatu."</string>
+ <string name="controls_open_app" msgid="483650971094300141">"Ireki aplikazioa"</string>
<string name="controls_error_generic" msgid="352500456918362905">"Ezin da kargatu egoera"</string>
<string name="controls_error_failed" msgid="960228639198558525">"Errorea. Saiatu berriro."</string>
<string name="controls_in_progress" msgid="4421080500238215939">"Abian"</string>
<string name="controls_added_tooltip" msgid="4842812921719153085">"Eduki sakatuta etengailua kontrolatzeko aukera berriak ikusteko"</string>
- <string name="controls_menu_add" msgid="4447246119229920050">"Gehitu kontrolatzeko aukerak"</string>
- <string name="controls_menu_edit" msgid="890623986951347062">"Editatu kontrolatzeko aukerak"</string>
+ <string name="controls_menu_add" msgid="4447246119229920050">"Gehitu aukerak"</string>
+ <string name="controls_menu_edit" msgid="890623986951347062">"Editatu aukerak"</string>
</resources>
diff --git a/packages/SystemUI/res/values-fa/strings.xml b/packages/SystemUI/res/values-fa/strings.xml
index b9472344f595..eec54deb2b8e 100644
--- a/packages/SystemUI/res/values-fa/strings.xml
+++ b/packages/SystemUI/res/values-fa/strings.xml
@@ -77,9 +77,6 @@
<string name="compat_mode_on" msgid="4963711187149440884">"بزرگ‌نمایی برای پر کردن صفحه"</string>
<string name="compat_mode_off" msgid="7682459748279487945">"گسترده کردن برای پر کردن صفحه"</string>
<string name="global_action_screenshot" msgid="2760267567509131654">"نماگرفت"</string>
- <string name="global_action_lock_message" product="default" msgid="4466026255205186456">"برای گزینه‌های بیشتر، قفل تلفن را باز کنید"</string>
- <string name="global_action_lock_message" product="tablet" msgid="7621167597240332986">"برای گزینه‌های بیشتر، قفل رایانه لوحی را باز کنید"</string>
- <string name="global_action_lock_message" product="device" msgid="538790401275363781">"برای گزینه‌های بیشتر، قفل دستگاه را باز کنید"</string>
<string name="remote_input_image_insertion_text" msgid="4850791636452521123">"تصویری ارسال کرد"</string>
<string name="screenshot_saving_ticker" msgid="6519186952674544916">"در حال ذخیره نماگرفت..."</string>
<string name="screenshot_saving_title" msgid="2298349784913287333">"درحال ذخیره نماگرفت…"</string>
@@ -722,7 +719,7 @@
<string name="notification_channel_summary_priority" msgid="7952654515769021553">"در بالای بخش مکالمه به‌صورت حبابک شناور نشان داده می‌شود و تصویر نمایه را در صفحه قفل نمایش می‌دهد"</string>
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"تنظیمات"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"اولویت"</string>
- <string name="no_shortcut" msgid="7176375126961212514">"<xliff:g id="APP_NAME">%1$s</xliff:g> از تنظیمات خاص مکالمه پشتیبانی نمی‌کند"</string>
+ <string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> از ویژگی‌های مکالمه پشتیبانی نمی‌کند"</string>
<string name="bubble_overflow_empty_title" msgid="3120029421991510842">"هیچ ابزارک اعلان جدیدی وجود ندارد"</string>
<string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"ابزارک اعلان اخیر و ابزارک اعلان ردشده اینجا ظاهر خواهند شد"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"این اعلان‌ها قابل اصلاح نیستند."</string>
@@ -1005,7 +1002,8 @@
<string name="bubble_accessibility_action_move_top_right" msgid="6916868852433483569">"انتقال به بالا سمت چپ"</string>
<string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"انتقال به پایین سمت راست"</string>
<string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"انتقال به پایین سمت چپ"</string>
- <string name="bubble_dismiss_text" msgid="7071770411580452911">"رد کردن"</string>
+ <!-- no translation found for bubble_dismiss_text (1314082410868930066) -->
+ <skip />
<string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"مکالمه در حباب نشان داده نشود"</string>
<string name="bubbles_user_education_title" msgid="5547017089271445797">"گپ بااستفاده از ابزارک اعلان"</string>
<string name="bubbles_user_education_description" msgid="1160281719576715211">"مکالمه‌های جدید به‌صورت نمادهای شناور یا ابزارک اعلان نشان داده شوند. برای باز کردن ابزارک اعلان ضربه بزنید. برای جابه‌جایی، آن را بکشید."</string>
@@ -1016,11 +1014,14 @@
<string name="notification_content_system_nav_changed" msgid="5077913144844684544">"پیمایش سیستم به‌روزرسانی شد. برای انجام تغییرات به «تنظیمات» بروید."</string>
<string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"برای به‌روزرسانی پیمایش سیستم، به «تنظیمات» بروید"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"آماده‌به‌کار"</string>
+ <string name="priority_onboarding_title" msgid="2893070698479227616">"مکالمه روی اولویت تنظیم شده است"</string>
+ <string name="priority_onboarding_behavior" msgid="5342816047020432929">"مکالمه‌های اولویت‌دار:"</string>
<string name="priority_onboarding_show_at_top_text" msgid="1678400241025513541">"نمایش در بالای بخش مکالمه"</string>
<string name="priority_onboarding_show_avatar_text" msgid="5756291381124091508">"نمایش تصویر نمایه در صفحه قفل"</string>
<string name="priority_onboarding_appear_as_bubble_text" msgid="4227039772250263122">"به‌شکل ابزارک اعلان شناور روی برنامه‌ها ظاهر می‌شود"</string>
<string name="priority_onboarding_ignores_dnd_text" msgid="2918952762719600529">"وقفه در «مزاحم نشوید»"</string>
<string name="priority_onboarding_done_button_title" msgid="4569550984286506007">"متوجه‌ام"</string>
+ <string name="priority_onboarding_settings_button_title" msgid="6663601574303585927">"تنظیمات"</string>
<string name="magnification_overlay_title" msgid="6584179429612427958">"پنجره همپوشانی بزرگ‌نمایی"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"پنجره بزرگ‌نمایی"</string>
<string name="magnification_controls_title" msgid="8421106606708891519">"کنترل‌های پنجره بزرگ‌نمایی"</string>
@@ -1062,9 +1063,13 @@
<string name="controls_structure_tooltip" msgid="4355922222944447867">"برای دیدن موارد بیشتر، تند بکشید"</string>
<string name="controls_seeding_in_progress" msgid="3033855341410264148">"درحال بار کردن توصیه‌ها"</string>
<string name="controls_media_close_session" msgid="9023534788828414585">"بستن این جلسه رسانه"</string>
+ <string name="controls_media_resume" msgid="1933520684481586053">"ازسرگیری"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"غیرفعال، برنامه را بررسی کنید"</string>
<string name="controls_error_retryable" msgid="864025882878378470">"خطا، درحال تلاش مجدد…"</string>
- <string name="controls_error_removed" msgid="6299213591234723805">"دستگاه برداشته شد"</string>
+ <string name="controls_error_removed" msgid="6675638069846014366">"پیدا نشد"</string>
+ <string name="controls_error_removed_title" msgid="1207794911208047818">"کنترل دردسترس نیست"</string>
+ <string name="controls_error_removed_message" msgid="2885911717034750542">"دسترسی به <xliff:g id="DEVICE">%1$s</xliff:g> ممکن نیست. برنامه <xliff:g id="APPLICATION">%2$s</xliff:g> را بررسی کنید تا مطمئن شوید کنترل هنوز دردسترس باشد و تنظیمات برنامه تغییر نکرده باشد."</string>
+ <string name="controls_open_app" msgid="483650971094300141">"بازکردن برنامه"</string>
<string name="controls_error_generic" msgid="352500456918362905">"وضعیت بار نشد"</string>
<string name="controls_error_failed" msgid="960228639198558525">"خطا، دوباره امتحان کنید"</string>
<string name="controls_in_progress" msgid="4421080500238215939">"درحال انجام"</string>
diff --git a/packages/SystemUI/res/values-fi/strings.xml b/packages/SystemUI/res/values-fi/strings.xml
index 7a83222754ec..ee7ed70718a1 100644
--- a/packages/SystemUI/res/values-fi/strings.xml
+++ b/packages/SystemUI/res/values-fi/strings.xml
@@ -77,9 +77,6 @@
<string name="compat_mode_on" msgid="4963711187149440884">"Zoomaa koko näyttöön"</string>
<string name="compat_mode_off" msgid="7682459748279487945">"Venytä koko näyttöön"</string>
<string name="global_action_screenshot" msgid="2760267567509131654">"Kuvakaappaus"</string>
- <string name="global_action_lock_message" product="default" msgid="4466026255205186456">"Avaa puhelimen lukitus, niin näet enemmän vaihtoehtoja"</string>
- <string name="global_action_lock_message" product="tablet" msgid="7621167597240332986">"Avaa tabletin lukitus, niin näet enemmän vaihtoehtoja"</string>
- <string name="global_action_lock_message" product="device" msgid="538790401275363781">"Avaa laitteen lukitus, niin näet enemmän vaihtoehtoja"</string>
<string name="remote_input_image_insertion_text" msgid="4850791636452521123">"lähetti kuvan"</string>
<string name="screenshot_saving_ticker" msgid="6519186952674544916">"Tallennetaan kuvakaappausta..."</string>
<string name="screenshot_saving_title" msgid="2298349784913287333">"Tallennetaan kuvakaappausta..."</string>
@@ -595,29 +592,21 @@
<string name="volume_odi_captions_hint_enable" msgid="2073091194012843195">"ota käyttöön"</string>
<string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"poista käytöstä"</string>
<string name="accessibility_output_chooser" msgid="7807898688967194183">"Vaihda toistolaitetta"</string>
- <!-- no translation found for screen_pinning_title (9058007390337841305) -->
- <skip />
+ <string name="screen_pinning_title" msgid="9058007390337841305">"Sovellus on kiinnitetty"</string>
<string name="screen_pinning_description" msgid="8699395373875667743">"Pysyy näkyvissä, kunnes irrotat sen. Irrota painamalla pitkään Edellinen ja Viimeisimmät."</string>
<string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"Pysyy näkyvissä, kunnes irrotat sen. Irrota painamalla pitkään Edellinen ja Aloitusnäyttö."</string>
<string name="screen_pinning_description_gestural" msgid="7246323931831232068">"Pysyy näkyvissä, kunnes irrotat sen. Irrota pyyhkäisemällä ylös ja painamalla pitkään."</string>
<string name="screen_pinning_description_accessible" msgid="7386449191953535332">"Pysyy näkyvissä, kunnes irrotat sen. Irrota painamalla pitkään Viimeisimmät."</string>
<string name="screen_pinning_description_recents_invisible_accessible" msgid="2857071808674481986">"Pysyy näkyvissä, kunnes irrotat sen. Irrota painamalla pitkään Aloitusnäyttö."</string>
- <!-- no translation found for screen_pinning_exposes_personal_data (8189852022981524789) -->
- <skip />
- <!-- no translation found for screen_pinning_can_open_other_apps (7529756813231421455) -->
- <skip />
- <!-- no translation found for screen_pinning_toast (8177286912533744328) -->
- <skip />
- <!-- no translation found for screen_pinning_toast_recents_invisible (6850978077443052594) -->
- <skip />
- <!-- no translation found for screen_pinning_toast_gesture_nav (170699893395336705) -->
- <skip />
+ <string name="screen_pinning_exposes_personal_data" msgid="8189852022981524789">"Henkilökohtaisiin tietoihin (esim. yhteystietoihin ja sähköpostin sisältöön) voi saada pääsyn."</string>
+ <string name="screen_pinning_can_open_other_apps" msgid="7529756813231421455">"Kiinnitetty sovellus voi avata muita sovelluksia."</string>
+ <string name="screen_pinning_toast" msgid="8177286912533744328">"Irrota sovellus koskettamalla pitkään Takaisin- ja Viimeisimmät-painikkeita"</string>
+ <string name="screen_pinning_toast_recents_invisible" msgid="6850978077443052594">"Irrota sovellus koskettamalla pitkään Takaisin- ja Aloitusnäyttö-painikkeita"</string>
+ <string name="screen_pinning_toast_gesture_nav" msgid="170699893395336705">"Irrota sovellus pyyhkäisemällä ylös ja painamalla pitkään"</string>
<string name="screen_pinning_positive" msgid="3285785989665266984">"Selvä"</string>
<string name="screen_pinning_negative" msgid="6882816864569211666">"Ei kiitos"</string>
- <!-- no translation found for screen_pinning_start (7483998671383371313) -->
- <skip />
- <!-- no translation found for screen_pinning_exit (4553787518387346893) -->
- <skip />
+ <string name="screen_pinning_start" msgid="7483998671383371313">"Sovellus kiinnitetty"</string>
+ <string name="screen_pinning_exit" msgid="4553787518387346893">"Sovellus irrotettu"</string>
<string name="quick_settings_reset_confirmation_title" msgid="463533331480997595">"Piilotetaanko <xliff:g id="TILE_LABEL">%1$s</xliff:g>?"</string>
<string name="quick_settings_reset_confirmation_message" msgid="2320586180785674186">"Se tulee takaisin näkyviin, kun seuraavan kerran otat sen käyttöön asetuksissa."</string>
<string name="quick_settings_reset_confirmation_button" msgid="3341477479055016776">"Piilota"</string>
@@ -730,7 +719,7 @@
<string name="notification_channel_summary_priority" msgid="7952654515769021553">"Näkyy keskusteluosion yläosassa kelluvana kuplana, profiilikuva näkyy lukitusnäytöllä"</string>
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"Asetukset"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"Tärkeä"</string>
- <string name="no_shortcut" msgid="7176375126961212514">"<xliff:g id="APP_NAME">%1$s</xliff:g> ei tue keskustelukohtaisia asetuksia"</string>
+ <string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> ei tue keskusteluominaisuuksia"</string>
<string name="bubble_overflow_empty_title" msgid="3120029421991510842">"Ei viimeaikaisia kuplia"</string>
<string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"Viimeaikaiset ja äskettäin ohitetut kuplat näkyvät täällä"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"Näitä ilmoituksia ei voi muokata"</string>
@@ -1013,7 +1002,8 @@
<string name="bubble_accessibility_action_move_top_right" msgid="6916868852433483569">"Siirrä oikeaan yläreunaan"</string>
<string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"Siirrä vasempaan alareunaan"</string>
<string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"Siirrä oikeaan alareunaan"</string>
- <string name="bubble_dismiss_text" msgid="7071770411580452911">"Ohita"</string>
+ <!-- no translation found for bubble_dismiss_text (1314082410868930066) -->
+ <skip />
<string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"Älä näytä kuplia keskusteluista"</string>
<string name="bubbles_user_education_title" msgid="5547017089271445797">"Chattaile kuplien avulla"</string>
<string name="bubbles_user_education_description" msgid="1160281719576715211">"Uudet keskustelut näkyvät kelluvina kuvakkeina tai kuplina. Avaa kupla napauttamalla. Siirrä sitä vetämällä."</string>
@@ -1024,11 +1014,14 @@
<string name="notification_content_system_nav_changed" msgid="5077913144844684544">"Järjestelmän navigointitapa vaihdettu. Voit muuttaa sitä asetuksista."</string>
<string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"Vaihda järjestelmän navigointitapaa asetuksista"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Virransäästötila"</string>
+ <string name="priority_onboarding_title" msgid="2893070698479227616">"Tärkeäksi merkitty keskustelu"</string>
+ <string name="priority_onboarding_behavior" msgid="5342816047020432929">"Tärkeät keskustelut"</string>
<string name="priority_onboarding_show_at_top_text" msgid="1678400241025513541">"Näkyy keskustelukohdan yläosassa"</string>
<string name="priority_onboarding_show_avatar_text" msgid="5756291381124091508">"Profiilikuva näkyy lukitusnäytöllä"</string>
<string name="priority_onboarding_appear_as_bubble_text" msgid="4227039772250263122">"Näkyy kelluvana kuplana sovellusten päällä"</string>
<string name="priority_onboarding_ignores_dnd_text" msgid="2918952762719600529">"Keskeyttää Älä häiritse ‑tilan"</string>
<string name="priority_onboarding_done_button_title" msgid="4569550984286506007">"Selvä"</string>
+ <string name="priority_onboarding_settings_button_title" msgid="6663601574303585927">"Asetukset"</string>
<string name="magnification_overlay_title" msgid="6584179429612427958">"Suurennuksen peittoikkuna"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"Suurennusikkuna"</string>
<string name="magnification_controls_title" msgid="8421106606708891519">"Suurennusikkunan ohjaimet"</string>
@@ -1070,9 +1063,13 @@
<string name="controls_structure_tooltip" msgid="4355922222944447867">"Pyyhkäise nähdäksesi lisää"</string>
<string name="controls_seeding_in_progress" msgid="3033855341410264148">"Ladataan suosituksia"</string>
<string name="controls_media_close_session" msgid="9023534788828414585">"Sulje tämä median käyttökerta"</string>
+ <string name="controls_media_resume" msgid="1933520684481586053">"Jatka"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"Epäaktiivinen, tarkista sovellus"</string>
<string name="controls_error_retryable" msgid="864025882878378470">"Virhe, yritetään uudelleen…"</string>
- <string name="controls_error_removed" msgid="6299213591234723805">"Laite poistettu"</string>
+ <string name="controls_error_removed" msgid="6675638069846014366">"Ei löydy"</string>
+ <string name="controls_error_removed_title" msgid="1207794911208047818">"Ohjain ei ole käytettävissä"</string>
+ <string name="controls_error_removed_message" msgid="2885911717034750542">"Ei pääsyä: <xliff:g id="DEVICE">%1$s</xliff:g>. Avaa <xliff:g id="APPLICATION">%2$s</xliff:g> ja tarkista, että ohjain on edelleen käytettävissä ja että sovelluksen asetukset eivät ole muuttuneet."</string>
+ <string name="controls_open_app" msgid="483650971094300141">"Avaa sovellus"</string>
<string name="controls_error_generic" msgid="352500456918362905">"Tilaa ei voi ladata"</string>
<string name="controls_error_failed" msgid="960228639198558525">"Virhe, yritä uudelleen"</string>
<string name="controls_in_progress" msgid="4421080500238215939">"Käynnissä"</string>
diff --git a/packages/SystemUI/res/values-fr-rCA/strings.xml b/packages/SystemUI/res/values-fr-rCA/strings.xml
index 901d1e687004..c71ab7ee4894 100644
--- a/packages/SystemUI/res/values-fr-rCA/strings.xml
+++ b/packages/SystemUI/res/values-fr-rCA/strings.xml
@@ -77,9 +77,6 @@
<string name="compat_mode_on" msgid="4963711187149440884">"Zoomer pour remplir l\'écran"</string>
<string name="compat_mode_off" msgid="7682459748279487945">"Étirer pour remplir l\'écran"</string>
<string name="global_action_screenshot" msgid="2760267567509131654">"Capture d\'écran"</string>
- <string name="global_action_lock_message" product="default" msgid="4466026255205186456">"Déverrouillez votre téléphone pour afficher davantage d\'options"</string>
- <string name="global_action_lock_message" product="tablet" msgid="7621167597240332986">"Déverrouillez votre tablette pour afficher davantage d\'options"</string>
- <string name="global_action_lock_message" product="device" msgid="538790401275363781">"Déverrouillez votre appareil pour afficher davantage d\'options"</string>
<string name="remote_input_image_insertion_text" msgid="4850791636452521123">"a envoyé une image"</string>
<string name="screenshot_saving_ticker" msgid="6519186952674544916">"Enregistrement capture écran…"</string>
<string name="screenshot_saving_title" msgid="2298349784913287333">"Enregistrement capture écran…"</string>
@@ -595,29 +592,21 @@
<string name="volume_odi_captions_hint_enable" msgid="2073091194012843195">"activer"</string>
<string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"désactiver"</string>
<string name="accessibility_output_chooser" msgid="7807898688967194183">"Changer d\'appareil de sortie"</string>
- <!-- no translation found for screen_pinning_title (9058007390337841305) -->
- <skip />
+ <string name="screen_pinning_title" msgid="9058007390337841305">"L\'application est épinglée"</string>
<string name="screen_pinning_description" msgid="8699395373875667743">"Cet écran est épinglé jusqu\'à ce que vous annuliez l\'opération. Pour annuler l\'épinglage, maintenez le doigt sur « Retour » et « Aperçu »."</string>
<string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"Cet écran est épinglé jusqu\'à ce que vous annuliez l\'opération. Pour annuler l\'épinglage, maintenez le doigt sur les touches Retour et Accueil."</string>
<string name="screen_pinning_description_gestural" msgid="7246323931831232068">"Cet écran est épinglé jusqu\'à ce que vous annuliez l\'épinglage. Pour annuler l\'épinglage, balayez l\'écran vers le haut et gardez le doigt dessus."</string>
<string name="screen_pinning_description_accessible" msgid="7386449191953535332">"Cet écran est épinglé jusqu\'à ce que vous annuliez l\'opération. Pour annuler l\'épinglage, maintenez le doigt sur « Aperçu »."</string>
<string name="screen_pinning_description_recents_invisible_accessible" msgid="2857071808674481986">"Cet écran est épinglé jusqu\'à ce que vous annuliez l\'opération. Pour annuler l\'épinglage, maintenez le doigt sur la touche Accueil."</string>
- <!-- no translation found for screen_pinning_exposes_personal_data (8189852022981524789) -->
- <skip />
- <!-- no translation found for screen_pinning_can_open_other_apps (7529756813231421455) -->
- <skip />
- <!-- no translation found for screen_pinning_toast (8177286912533744328) -->
- <skip />
- <!-- no translation found for screen_pinning_toast_recents_invisible (6850978077443052594) -->
- <skip />
- <!-- no translation found for screen_pinning_toast_gesture_nav (170699893395336705) -->
- <skip />
+ <string name="screen_pinning_exposes_personal_data" msgid="8189852022981524789">"Certaines données personnelles pourraient être accessibles (comme les contacts et le contenu des courriels)."</string>
+ <string name="screen_pinning_can_open_other_apps" msgid="7529756813231421455">"L\'application épinglée peut ouvrir d\'autres applications."</string>
+ <string name="screen_pinning_toast" msgid="8177286912533744328">"Pour annuler l\'épinglage de cette application, maintenez un doigt sur les touches Retour et Aperçu"</string>
+ <string name="screen_pinning_toast_recents_invisible" msgid="6850978077443052594">"Pour annuler l\'épinglage de cette application, maintenez un doigt sur les touches Retour et Accueil"</string>
+ <string name="screen_pinning_toast_gesture_nav" msgid="170699893395336705">"Pour annuler l\'épinglage de cette application, balayez-la vers le haut et gardez le doigt dessus"</string>
<string name="screen_pinning_positive" msgid="3285785989665266984">"OK"</string>
<string name="screen_pinning_negative" msgid="6882816864569211666">"Non, merci"</string>
- <!-- no translation found for screen_pinning_start (7483998671383371313) -->
- <skip />
- <!-- no translation found for screen_pinning_exit (4553787518387346893) -->
- <skip />
+ <string name="screen_pinning_start" msgid="7483998671383371313">"Application épinglée"</string>
+ <string name="screen_pinning_exit" msgid="4553787518387346893">"L\'épinglage de l\'application a été annulé"</string>
<string name="quick_settings_reset_confirmation_title" msgid="463533331480997595">"Masquer <xliff:g id="TILE_LABEL">%1$s</xliff:g>?"</string>
<string name="quick_settings_reset_confirmation_message" msgid="2320586180785674186">"Cet élément réapparaîtra la prochaine fois que vous l\'activerez dans les paramètres."</string>
<string name="quick_settings_reset_confirmation_button" msgid="3341477479055016776">"Masquer"</string>
@@ -730,7 +719,7 @@
<string name="notification_channel_summary_priority" msgid="7952654515769021553">"S\'affiche en haut de la section des conversations sous forme de bulle flottante et affiche la photo du profil sur l\'écran de verrouillage"</string>
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"Paramètres"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"Priorité"</string>
- <string name="no_shortcut" msgid="7176375126961212514">"<xliff:g id="APP_NAME">%1$s</xliff:g> ne prend pas en charge les paramètres propres aux conversations"</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>
<string name="bubble_overflow_empty_title" msgid="3120029421991510842">"Aucune bulle récente"</string>
<string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"Les bulles récentes et les bulles ignorées s\'afficheront ici"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"Ces notifications ne peuvent pas être modifiées"</string>
@@ -1013,7 +1002,8 @@
<string name="bubble_accessibility_action_move_top_right" msgid="6916868852433483569">"Déplacer dans coin sup. droit"</string>
<string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"Déplacer dans coin inf. gauche"</string>
<string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"Déplacer dans coin inf. droit"</string>
- <string name="bubble_dismiss_text" msgid="7071770411580452911">"Fermer"</string>
+ <!-- no translation found for bubble_dismiss_text (1314082410868930066) -->
+ <skip />
<string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"Ne pas afficher les conversations dans des bulles"</string>
<string name="bubbles_user_education_title" msgid="5547017089271445797">"Clavarder en utilisant des bulles"</string>
<string name="bubbles_user_education_description" msgid="1160281719576715211">"Les nouvelles conversations s\'affichent sous forme d\'icônes flottantes (de bulles). Touchez une bulle pour l\'ouvrir. Faites-la glisser pour la déplacer."</string>
@@ -1024,17 +1014,20 @@
<string name="notification_content_system_nav_changed" msgid="5077913144844684544">"La navigation système a été mise à jour. Pour apporter des modifications, accédez au menu Paramètres."</string>
<string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"Accédez au menu Paramètres pour mettre à jour la navigation système"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Veille"</string>
+ <string name="priority_onboarding_title" msgid="2893070698479227616">"La conversation a été définie comme prioritaire"</string>
+ <string name="priority_onboarding_behavior" msgid="5342816047020432929">"Les conversations prioritaires :"</string>
<string name="priority_onboarding_show_at_top_text" msgid="1678400241025513541">"Afficher dans le haut de la section des conversations"</string>
<string name="priority_onboarding_show_avatar_text" msgid="5756291381124091508">"Afficher la photo de profil sur l\'écran verrouillé"</string>
<string name="priority_onboarding_appear_as_bubble_text" msgid="4227039772250263122">"Sous forme de bulle flottante, par-dessus les applis"</string>
<string name="priority_onboarding_ignores_dnd_text" msgid="2918952762719600529">"Interrompre le mode Ne pas déranger"</string>
<string name="priority_onboarding_done_button_title" msgid="4569550984286506007">"OK"</string>
+ <string name="priority_onboarding_settings_button_title" msgid="6663601574303585927">"Paramètres"</string>
<string name="magnification_overlay_title" msgid="6584179429612427958">"Fenêtre d\'agrandissement superposée"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"Fenêtre d\'agrandissement"</string>
<string name="magnification_controls_title" msgid="8421106606708891519">"Commandes pour la fenêtre d\'agrandissement"</string>
- <string name="quick_controls_title" msgid="6839108006171302273">"Commandes de contrôle des appareils"</string>
+ <string name="quick_controls_title" msgid="6839108006171302273">"Commandes des appareils"</string>
<string name="quick_controls_subtitle" msgid="1667408093326318053">"Ajoutez des commandes pour vos appareils connectés"</string>
- <string name="quick_controls_setup_title" msgid="8901436655997849822">"Configurer les commandes de contrôle des appareils"</string>
+ <string name="quick_controls_setup_title" msgid="8901436655997849822">"Configurer les commandes des appareils"</string>
<string name="quick_controls_setup_subtitle" msgid="1681506617879773824">"Maintenez l\'interrupteur enfoncé pour accéder à vos commandes"</string>
<string name="controls_providers_title" msgid="6879775889857085056">"Sélectionnez l\'application pour laquelle ajouter des commandes"</string>
<plurals name="controls_number_of_favorites" formatted="false" msgid="1057347832073807380">
@@ -1055,7 +1048,7 @@
<string name="controls_favorite_toast_no_changes" msgid="7094494210840877931">"Modifications non enregistrées"</string>
<string name="controls_favorite_load_error" msgid="2533215155804455348">"Impossible de charger la liste des commandes."</string>
<string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Autre"</string>
- <string name="controls_dialog_title" msgid="2343565267424406202">"Ajouter aux commandes de contrôle des appareils"</string>
+ <string name="controls_dialog_title" msgid="2343565267424406202">"Ajouter aux commandes des appareils"</string>
<string name="controls_dialog_ok" msgid="2770230012857881822">"Ajouter"</string>
<string name="controls_dialog_message" msgid="342066938390663844">"Suggestion de <xliff:g id="APP">%s</xliff:g>"</string>
<string name="controls_dialog_confirmation" msgid="586517302736263447">"Commandes mises à jour"</string>
@@ -1070,9 +1063,13 @@
<string name="controls_structure_tooltip" msgid="4355922222944447867">"Balayez l\'écran pour en afficher davantage"</string>
<string name="controls_seeding_in_progress" msgid="3033855341410264148">"Chargement des recommandations…"</string>
<string name="controls_media_close_session" msgid="9023534788828414585">"Fermer cette session multimédia"</string>
+ <string name="controls_media_resume" msgid="1933520684481586053">"Reprendre"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"Délai expiré, vérifiez l\'appli"</string>
<string name="controls_error_retryable" msgid="864025882878378470">"Erreur, nouvelle tentative…"</string>
- <string name="controls_error_removed" msgid="6299213591234723805">"Appareil supprimé"</string>
+ <string name="controls_error_removed" msgid="6675638069846014366">"Introuvable"</string>
+ <string name="controls_error_removed_title" msgid="1207794911208047818">"La commande n\'est pas accessible"</string>
+ <string name="controls_error_removed_message" msgid="2885911717034750542">"Impossible d\'accéder à <xliff:g id="DEVICE">%1$s</xliff:g>. Vérifiez l\'application <xliff:g id="APPLICATION">%2$s</xliff:g> pour vous assurer que la commande est toujours offerte et que les paramètres de l\'application n\'ont pas changé."</string>
+ <string name="controls_open_app" msgid="483650971094300141">"Ouvrir"</string>
<string name="controls_error_generic" msgid="352500456918362905">"Impossible de charger l\'état"</string>
<string name="controls_error_failed" msgid="960228639198558525">"Erreur. Veuillez réessayer."</string>
<string name="controls_in_progress" msgid="4421080500238215939">"En cours"</string>
diff --git a/packages/SystemUI/res/values-fr/strings.xml b/packages/SystemUI/res/values-fr/strings.xml
index 0145ce9113e7..4c69c865d1b5 100644
--- a/packages/SystemUI/res/values-fr/strings.xml
+++ b/packages/SystemUI/res/values-fr/strings.xml
@@ -77,9 +77,6 @@
<string name="compat_mode_on" msgid="4963711187149440884">"Zoomer pour remplir l\'écran"</string>
<string name="compat_mode_off" msgid="7682459748279487945">"Étirer pour remplir l\'écran"</string>
<string name="global_action_screenshot" msgid="2760267567509131654">"Capture d\'écran"</string>
- <string name="global_action_lock_message" product="default" msgid="4466026255205186456">"Déverrouillez votre téléphone pour obtenir plus d\'options"</string>
- <string name="global_action_lock_message" product="tablet" msgid="7621167597240332986">"Déverrouillez votre tablette pour obtenir plus d\'options"</string>
- <string name="global_action_lock_message" product="device" msgid="538790401275363781">"Déverrouillez votre appareil pour obtenir plus d\'options"</string>
<string name="remote_input_image_insertion_text" msgid="4850791636452521123">"a envoyé une image"</string>
<string name="screenshot_saving_ticker" msgid="6519186952674544916">"Enregistrement capture écran…"</string>
<string name="screenshot_saving_title" msgid="2298349784913287333">"Enregistrement de la capture d\'écran…"</string>
@@ -595,29 +592,21 @@
<string name="volume_odi_captions_hint_enable" msgid="2073091194012843195">"activer"</string>
<string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"désactiver"</string>
<string name="accessibility_output_chooser" msgid="7807898688967194183">"Changer de périphérique de sortie"</string>
- <!-- no translation found for screen_pinning_title (9058007390337841305) -->
- <skip />
+ <string name="screen_pinning_title" msgid="9058007390337841305">"L\'application est épinglée"</string>
<string name="screen_pinning_description" msgid="8699395373875667743">"Cet écran est épinglé jusqu\'à l\'annulation de l\'opération. Pour annuler l\'épinglage, appuyez de manière prolongée sur les boutons Retour et Aperçu."</string>
<string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"Cet écran est épinglé jusqu\'à l\'annulation de l\'opération. Pour annuler l\'épinglage, appuyez de manière prolongée sur les boutons \"Retour\" et \"Accueil\"."</string>
<string name="screen_pinning_description_gestural" msgid="7246323931831232068">"Cet écran est épinglé jusqu\'à l\'annulation de l\'opération. Pour annuler l\'épinglage, balayez l\'écran vers le haut et gardez le doigt dessus."</string>
<string name="screen_pinning_description_accessible" msgid="7386449191953535332">"Cet écran est épinglé jusqu\'à l\'annulation de l\'opération. Pour annuler l\'épinglage, appuyez de manière prolongée sur le bouton Aperçu."</string>
<string name="screen_pinning_description_recents_invisible_accessible" msgid="2857071808674481986">"Cet écran est épinglé jusqu\'à l\'annulation de l\'opération. Pour annuler l\'épinglage, appuyez de manière prolongée sur le bouton \"Accueil\"."</string>
- <!-- no translation found for screen_pinning_exposes_personal_data (8189852022981524789) -->
- <skip />
- <!-- no translation found for screen_pinning_can_open_other_apps (7529756813231421455) -->
- <skip />
- <!-- no translation found for screen_pinning_toast (8177286912533744328) -->
- <skip />
- <!-- no translation found for screen_pinning_toast_recents_invisible (6850978077443052594) -->
- <skip />
- <!-- no translation found for screen_pinning_toast_gesture_nav (170699893395336705) -->
- <skip />
+ <string name="screen_pinning_exposes_personal_data" msgid="8189852022981524789">"Les données à caractère personnel, comme les contacts et le contenu des e-mails, sont susceptibles d\'être accessibles."</string>
+ <string name="screen_pinning_can_open_other_apps" msgid="7529756813231421455">"D\'autres applications peuvent être ouvertes depuis une application épinglée."</string>
+ <string name="screen_pinning_toast" msgid="8177286912533744328">"Pour que cette application ne soit plus épinglée, appuyez de manière prolongée sur les boutons \"Retour\" et \"Aperçu\""</string>
+ <string name="screen_pinning_toast_recents_invisible" msgid="6850978077443052594">"Pour que cette application ne soit plus épinglée, appuyez de manière prolongée sur les boutons \"Retour\" et \"Accueil\""</string>
+ <string name="screen_pinning_toast_gesture_nav" msgid="170699893395336705">"Pour que cette application ne soit plus épinglée, balayez l\'écran vers le haut et maintenez votre doigt dessus"</string>
<string name="screen_pinning_positive" msgid="3285785989665266984">"OK"</string>
<string name="screen_pinning_negative" msgid="6882816864569211666">"Non, merci"</string>
- <!-- no translation found for screen_pinning_start (7483998671383371313) -->
- <skip />
- <!-- no translation found for screen_pinning_exit (4553787518387346893) -->
- <skip />
+ <string name="screen_pinning_start" msgid="7483998671383371313">"Application épinglée"</string>
+ <string name="screen_pinning_exit" msgid="4553787518387346893">"L\'application n\'est plus épinglée"</string>
<string name="quick_settings_reset_confirmation_title" msgid="463533331480997595">"Masquer <xliff:g id="TILE_LABEL">%1$s</xliff:g> ?"</string>
<string name="quick_settings_reset_confirmation_message" msgid="2320586180785674186">"Cet élément réapparaîtra la prochaine fois que vous l\'activerez dans les paramètres."</string>
<string name="quick_settings_reset_confirmation_button" msgid="3341477479055016776">"Masquer"</string>
@@ -730,7 +719,7 @@
<string name="notification_channel_summary_priority" msgid="7952654515769021553">"S\'affiche en haut de la section des conversations, apparaît sous forme de bulle flottante, affiche la photo de profil sur l\'écran de verrouillage"</string>
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"Paramètres"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"Prioritaire"</string>
- <string name="no_shortcut" msgid="7176375126961212514">"<xliff:g id="APP_NAME">%1$s</xliff:g> n\'est pas compatible avec les paramètres de conversation"</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>
<string name="bubble_overflow_empty_title" msgid="3120029421991510842">"Aucune bulle récente"</string>
<string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"Les bulles récentes et ignorées s\'afficheront ici"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"Impossible de modifier ces notifications."</string>
@@ -1013,7 +1002,8 @@
<string name="bubble_accessibility_action_move_top_right" msgid="6916868852433483569">"Déplacer en haut à droite"</string>
<string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"Déplacer en bas à gauche"</string>
<string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"Déplacer en bas à droite"</string>
- <string name="bubble_dismiss_text" msgid="7071770411580452911">"Ignorer"</string>
+ <!-- no translation found for bubble_dismiss_text (1314082410868930066) -->
+ <skip />
<string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"Ne pas afficher la conversations dans des bulles"</string>
<string name="bubbles_user_education_title" msgid="5547017089271445797">"Chatter en utilisant des bulles"</string>
<string name="bubbles_user_education_description" msgid="1160281719576715211">"Les nouvelles conversations s\'affichent sous forme d\'icônes flottantes ou bulles. Appuyez sur la bulle pour l\'ouvrir. Faites-la glisser pour la déplacer."</string>
@@ -1024,11 +1014,14 @@
<string name="notification_content_system_nav_changed" msgid="5077913144844684544">"Navigation système mise à jour. Pour apporter des modifications, accédez aux paramètres."</string>
<string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"Accédez aux paramètres pour mettre à jour la navigation système"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Mode Veille imminent"</string>
+ <string name="priority_onboarding_title" msgid="2893070698479227616">"Conversation définie comme prioritaire"</string>
+ <string name="priority_onboarding_behavior" msgid="5342816047020432929">"Les conversations prioritaires :"</string>
<string name="priority_onboarding_show_at_top_text" msgid="1678400241025513541">"En haut de la liste des conversations"</string>
<string name="priority_onboarding_show_avatar_text" msgid="5756291381124091508">"Photo de profil sur l\'écran de verrouillage"</string>
<string name="priority_onboarding_appear_as_bubble_text" msgid="4227039772250263122">"Sous forme d\'info-bulle au-dessus des applications"</string>
<string name="priority_onboarding_ignores_dnd_text" msgid="2918952762719600529">"Interrompre Ne pas déranger"</string>
<string name="priority_onboarding_done_button_title" msgid="4569550984286506007">"OK"</string>
+ <string name="priority_onboarding_settings_button_title" msgid="6663601574303585927">"Paramètres"</string>
<string name="magnification_overlay_title" msgid="6584179429612427958">"Fenêtre de superposition de l\'agrandissement"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"Fenêtre d\'agrandissement"</string>
<string name="magnification_controls_title" msgid="8421106606708891519">"Fenêtre des commandes d\'agrandissement"</string>
@@ -1050,7 +1043,7 @@
<string name="accessibility_control_move" msgid="8980344493796647792">"Déplacer l\'élément à la position <xliff:g id="NUMBER">%d</xliff:g>"</string>
<string name="controls_favorite_default_title" msgid="967742178688938137">"Commandes"</string>
<string name="controls_favorite_subtitle" msgid="6604402232298443956">"Sélectionnez les commandes auxquelles vous souhaitez accéder depuis le menu de démarrage"</string>
- <string name="controls_favorite_rearrange" msgid="5616952398043063519">"Appuyer et faire glisser pour réorganiser les commandes"</string>
+ <string name="controls_favorite_rearrange" msgid="5616952398043063519">"Appuyez et faites glisser pour réorganiser les commandes"</string>
<string name="controls_favorite_removed" msgid="5276978408529217272">"Toutes les commandes ont été supprimées"</string>
<string name="controls_favorite_toast_no_changes" msgid="7094494210840877931">"Les modifications n\'ont pas été enregistrées"</string>
<string name="controls_favorite_load_error" msgid="2533215155804455348">"Impossible de charger toutes les commandes."</string>
@@ -1070,9 +1063,13 @@
<string name="controls_structure_tooltip" msgid="4355922222944447867">"Balayer l\'écran pour voir plus d\'annonces"</string>
<string name="controls_seeding_in_progress" msgid="3033855341410264148">"Chargement des recommandations"</string>
<string name="controls_media_close_session" msgid="9023534788828414585">"Fermer cette session multimédia"</string>
+ <string name="controls_media_resume" msgid="1933520684481586053">"Reprendre"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"Délai expiré, vérifier l\'appli"</string>
<string name="controls_error_retryable" msgid="864025882878378470">"Erreur. Nouvelle tentative…"</string>
- <string name="controls_error_removed" msgid="6299213591234723805">"Appareil supprimé"</string>
+ <string name="controls_error_removed" msgid="6675638069846014366">"Introuvable"</string>
+ <string name="controls_error_removed_title" msgid="1207794911208047818">"Commande indisponible"</string>
+ <string name="controls_error_removed_message" msgid="2885911717034750542">"Impossible d\'accéder à \"<xliff:g id="DEVICE">%1$s</xliff:g>\". Vérifiez l\'application <xliff:g id="APPLICATION">%2$s</xliff:g> pour vous assurer que la commande est toujours disponible et que les paramètres de l\'application n\'ont pas changé."</string>
+ <string name="controls_open_app" msgid="483650971094300141">"Ouvrir l\'application"</string>
<string name="controls_error_generic" msgid="352500456918362905">"Impossible de charger l\'état"</string>
<string name="controls_error_failed" msgid="960228639198558525">"Erreur. Veuillez réessayer."</string>
<string name="controls_in_progress" msgid="4421080500238215939">"En cours"</string>
diff --git a/packages/SystemUI/res/values-gl/strings.xml b/packages/SystemUI/res/values-gl/strings.xml
index 59537e218582..d80bd95abf65 100644
--- a/packages/SystemUI/res/values-gl/strings.xml
+++ b/packages/SystemUI/res/values-gl/strings.xml
@@ -77,9 +77,6 @@
<string name="compat_mode_on" msgid="4963711187149440884">"Ampliar ata ocupar todo"</string>
<string name="compat_mode_off" msgid="7682459748279487945">"Estirar ata ocupar todo"</string>
<string name="global_action_screenshot" msgid="2760267567509131654">"Facer captura"</string>
- <string name="global_action_lock_message" product="default" msgid="4466026255205186456">"Desbloquea o teléfono para ver máis opcións"</string>
- <string name="global_action_lock_message" product="tablet" msgid="7621167597240332986">"Desbloquea a tableta para ver máis opcións"</string>
- <string name="global_action_lock_message" product="device" msgid="538790401275363781">"Desbloquea o dispositivo para ver máis opcións"</string>
<string name="remote_input_image_insertion_text" msgid="4850791636452521123">"enviou unha imaxe"</string>
<string name="screenshot_saving_ticker" msgid="6519186952674544916">"Gardando captura de pantalla…"</string>
<string name="screenshot_saving_title" msgid="2298349784913287333">"Gardando captura de pantalla…"</string>
@@ -722,7 +719,7 @@
<string name="notification_channel_summary_priority" msgid="7952654515769021553">"Móstrase na parte superior da sección de conversas en forma de burbulla flotante e aparece a imaxe do perfil na pantalla de bloqueo"</string>
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"Configuración"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"Prioridade"</string>
- <string name="no_shortcut" msgid="7176375126961212514">"<xliff:g id="APP_NAME">%1$s</xliff:g> non admite opcións de configuración específicas para conversas"</string>
+ <string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> non admite funcións de conversa"</string>
<string name="bubble_overflow_empty_title" msgid="3120029421991510842">"Non hai burbullas recentes"</string>
<string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"As burbullas recentes e ignoradas aparecerán aquí."</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"Estas notificacións non se poden modificar."</string>
@@ -1005,7 +1002,8 @@
<string name="bubble_accessibility_action_move_top_right" msgid="6916868852433483569">"Mover á parte superior dereita"</string>
<string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"Mover á parte infer. esquerda"</string>
<string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"Mover á parte inferior dereita"</string>
- <string name="bubble_dismiss_text" msgid="7071770411580452911">"Ignorar"</string>
+ <!-- no translation found for bubble_dismiss_text (1314082410868930066) -->
+ <skip />
<string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"Non mostrar a conversa como burbulla"</string>
<string name="bubbles_user_education_title" msgid="5547017089271445797">"Chatear usando burbullas"</string>
<string name="bubbles_user_education_description" msgid="1160281719576715211">"As conversas novas aparecen como iconas flotantes ou burbullas. Toca para abrir a burbulla e arrastra para movela."</string>
@@ -1016,11 +1014,14 @@
<string name="notification_content_system_nav_changed" msgid="5077913144844684544">"Actualizouse a navegación do sistema. Para facer cambios, vai a Configuración."</string>
<string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"Para actualizar a navegación do sistema, vai a Configuración"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Modo de espera"</string>
+ <string name="priority_onboarding_title" msgid="2893070698479227616">"A conversa definiuse como prioritaria"</string>
+ <string name="priority_onboarding_behavior" msgid="5342816047020432929">"As conversas prioritarias farán o seguinte:"</string>
<string name="priority_onboarding_show_at_top_text" msgid="1678400241025513541">"Mostrar na parte superior da sección de conversas"</string>
<string name="priority_onboarding_show_avatar_text" msgid="5756291381124091508">"Mostrar imaxe do perfil na pantalla de bloqueo"</string>
<string name="priority_onboarding_appear_as_bubble_text" msgid="4227039772250263122">"Mostrar como burbulla flotante sobre outras apps"</string>
<string name="priority_onboarding_ignores_dnd_text" msgid="2918952762719600529">"Interromper modo Non molestar"</string>
<string name="priority_onboarding_done_button_title" msgid="4569550984286506007">"Entendido"</string>
+ <string name="priority_onboarding_settings_button_title" msgid="6663601574303585927">"Configuración"</string>
<string name="magnification_overlay_title" msgid="6584179429612427958">"Ampliación da ventá de superposición"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"Ventá de superposición"</string>
<string name="magnification_controls_title" msgid="8421106606708891519">"Controis de ampliación da ventá"</string>
@@ -1062,9 +1063,13 @@
<string name="controls_structure_tooltip" msgid="4355922222944447867">"Pasar o dedo para ver máis"</string>
<string name="controls_seeding_in_progress" msgid="3033855341410264148">"Cargando recomendacións"</string>
<string name="controls_media_close_session" msgid="9023534788828414585">"Pechar esta sesión multimedia"</string>
+ <string name="controls_media_resume" msgid="1933520684481586053">"Retomar"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"Inactivo. Comproba a app"</string>
<string name="controls_error_retryable" msgid="864025882878378470">"Erro. Tentando de novo…"</string>
- <string name="controls_error_removed" msgid="6299213591234723805">"Quitouse o dispositivo"</string>
+ <string name="controls_error_removed" msgid="6675638069846014366">"Non se atopou"</string>
+ <string name="controls_error_removed_title" msgid="1207794911208047818">"O control non está dispoñible"</string>
+ <string name="controls_error_removed_message" msgid="2885911717034750542">"Non se puido acceder a: <xliff:g id="DEVICE">%1$s</xliff:g>. Comproba a aplicación <xliff:g id="APPLICATION">%2$s</xliff:g> para asegurarte de que o control aínda estea dispoñible e que non se modificase a configuración da aplicación."</string>
+ <string name="controls_open_app" msgid="483650971094300141">"Abrir aplicación"</string>
<string name="controls_error_generic" msgid="352500456918362905">"Non se puido cargar o estado"</string>
<string name="controls_error_failed" msgid="960228639198558525">"Erro. Téntao de novo"</string>
<string name="controls_in_progress" msgid="4421080500238215939">"En curso"</string>
diff --git a/packages/SystemUI/res/values-gu/strings.xml b/packages/SystemUI/res/values-gu/strings.xml
index 28d55b7df177..c641208055c1 100644
--- a/packages/SystemUI/res/values-gu/strings.xml
+++ b/packages/SystemUI/res/values-gu/strings.xml
@@ -77,9 +77,6 @@
<string name="compat_mode_on" msgid="4963711187149440884">"સ્ક્રીન ભરવા માટે ઝૂમ કરો"</string>
<string name="compat_mode_off" msgid="7682459748279487945">"સ્ક્રીન ભરવા માટે ખેંચો"</string>
<string name="global_action_screenshot" msgid="2760267567509131654">"સ્ક્રીનશૉટ"</string>
- <string name="global_action_lock_message" product="default" msgid="4466026255205186456">"વધુ વિકલ્પો માટે તમારા ફોનને અનલૉક કરો"</string>
- <string name="global_action_lock_message" product="tablet" msgid="7621167597240332986">"વધુ વિકલ્પો માટે તમારા ટૅબ્લેટને અનલૉક કરો"</string>
- <string name="global_action_lock_message" product="device" msgid="538790401275363781">"વધુ વિકલ્પો માટે તમારા ડિવાઇસને અનલૉક કરો"</string>
<string name="remote_input_image_insertion_text" msgid="4850791636452521123">"છબી મોકલી"</string>
<string name="screenshot_saving_ticker" msgid="6519186952674544916">"સ્ક્રીનશોટ સાચવી રહ્યું છે…"</string>
<string name="screenshot_saving_title" msgid="2298349784913287333">"સ્ક્રીનશોટ સાચવી રહ્યું છે…"</string>
@@ -595,29 +592,21 @@
<string name="volume_odi_captions_hint_enable" msgid="2073091194012843195">"ચાલુ કરો"</string>
<string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"બંધ કરો"</string>
<string name="accessibility_output_chooser" msgid="7807898688967194183">"આઉટપુટ ઉપકરણ સ્વિચ કરો"</string>
- <!-- no translation found for screen_pinning_title (9058007390337841305) -->
- <skip />
+ <string name="screen_pinning_title" msgid="9058007390337841305">"ઍપને પિન કરેલી છે"</string>
<string name="screen_pinning_description" msgid="8699395373875667743">"તમે જ્યાં સુધી અનપિન કરશો નહીં ત્યાં સુધી આ તેને દૃશ્યક્ષમ રાખે છે. અનપિન કરવા માટે પાછળ અને ઝલકને સ્પર્શ કરી રાખો."</string>
<string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"તમે જ્યાં સુધી અનપિન કરશો નહીં ત્યાં સુધી આ તેને દૃશ્યક્ષમ રાખે છે. અનપિન કરવા માટે પાછળ અને હોમને સ્પર્શ કરી રાખો."</string>
<string name="screen_pinning_description_gestural" msgid="7246323931831232068">"તમે જ્યાં સુધી અનપિન નહીં કરો ત્યાં સુધી આ તેને દૃશ્યક્ષમ રાખે છે. ઉપરની તરફ સ્વાઇપ કરો અને અનપિન કરવા માટે દબાવી રાખો."</string>
<string name="screen_pinning_description_accessible" msgid="7386449191953535332">"તમે જ્યાં સુધી અનપિન કરશો નહીં ત્યાં સુધી આ તેને દૃશ્યક્ષમ રાખે છે. અનપિન કરવા માટે ઝલકને સ્પર્શ કરી રાખો."</string>
<string name="screen_pinning_description_recents_invisible_accessible" msgid="2857071808674481986">"તમે જ્યાં સુધી અનપિન કરશો નહીં ત્યાં સુધી આ તેને દૃશ્યક્ષમ રાખે છે. અનપિન કરવા માટે હોમને સ્પર્શ કરી રાખો."</string>
- <!-- no translation found for screen_pinning_exposes_personal_data (8189852022981524789) -->
- <skip />
- <!-- no translation found for screen_pinning_can_open_other_apps (7529756813231421455) -->
- <skip />
- <!-- no translation found for screen_pinning_toast (8177286912533744328) -->
- <skip />
- <!-- no translation found for screen_pinning_toast_recents_invisible (6850978077443052594) -->
- <skip />
- <!-- no translation found for screen_pinning_toast_gesture_nav (170699893395336705) -->
- <skip />
+ <string name="screen_pinning_exposes_personal_data" msgid="8189852022981524789">"વ્યક્તિગત ડેટા ઍક્સેસ કરી શકાતો હોઈ શકે (જેમ કે સંપર્કો અને ઇમેઇલનું કન્ટેન્ટ)."</string>
+ <string name="screen_pinning_can_open_other_apps" msgid="7529756813231421455">"પિન કરેલી ઍપ અન્ય ઍપને ખોલી શકે છે."</string>
+ <string name="screen_pinning_toast" msgid="8177286912533744328">"આ ઍપને અનપિન કરવા માટે, પાછળ અને ઓવરવ્યૂ બટનને સ્પર્શ કરી રાખો"</string>
+ <string name="screen_pinning_toast_recents_invisible" msgid="6850978077443052594">"આ ઍપને અનપિન કરવા માટે, પાછળ અને હોમ બટનને સ્પર્શ કરી રાખો"</string>
+ <string name="screen_pinning_toast_gesture_nav" msgid="170699893395336705">"આ ઍપને અનપિન કરવા માટે, ઉપર સ્વાઇપ કરીને બટન દબાવી રાખો"</string>
<string name="screen_pinning_positive" msgid="3285785989665266984">"સમજાઈ ગયું"</string>
<string name="screen_pinning_negative" msgid="6882816864569211666">"ના, આભાર"</string>
- <!-- no translation found for screen_pinning_start (7483998671383371313) -->
- <skip />
- <!-- no translation found for screen_pinning_exit (4553787518387346893) -->
- <skip />
+ <string name="screen_pinning_start" msgid="7483998671383371313">"ઍપ પિન કરી"</string>
+ <string name="screen_pinning_exit" msgid="4553787518387346893">"ઍપ અનપિન કરી"</string>
<string name="quick_settings_reset_confirmation_title" msgid="463533331480997595">"<xliff:g id="TILE_LABEL">%1$s</xliff:g> ને છુપાવીએ?"</string>
<string name="quick_settings_reset_confirmation_message" msgid="2320586180785674186">"તે સેટિંગ્સમાં તમે તેને ચાલુ કરશો ત્યારે આગલી વખતે ફરીથી દેખાશે."</string>
<string name="quick_settings_reset_confirmation_button" msgid="3341477479055016776">"છુપાવો"</string>
@@ -730,7 +719,7 @@
<string name="notification_channel_summary_priority" msgid="7952654515769021553">"એને વાતચીત વિભાગની ટોચ પર બતાવે છે, તરતા બબલ તરીકે દેખાય છે, લૉક સ્ક્રીન પર પ્રોફાઇલ ફોટા તરીકે બતાવે છે"</string>
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"સેટિંગ"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"પ્રાધાન્યતા"</string>
- <string name="no_shortcut" msgid="7176375126961212514">"<xliff:g id="APP_NAME">%1$s</xliff:g> વાતચીત માટેના ચોક્કસ સેટિંગને સપોર્ટ કરતી નથી"</string>
+ <string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> વાતચીતની સુવિધાઓને સપોર્ટ આપતી નથી"</string>
<string name="bubble_overflow_empty_title" msgid="3120029421991510842">"તાજેતરના કોઈ બબલ નથી"</string>
<string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"એકદમ નવા બબલ અને છોડી દીધેલા બબલ અહીં દેખાશે"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"આ નોટિફિકેશનમાં કોઈ ફેરફાર થઈ શકશે નહીં."</string>
@@ -1013,7 +1002,8 @@
<string name="bubble_accessibility_action_move_top_right" msgid="6916868852433483569">"ઉપર જમણે ખસેડો"</string>
<string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"નીચે ડાબે ખસેડો"</string>
<string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"નીચે જમણે ખસેડો"</string>
- <string name="bubble_dismiss_text" msgid="7071770411580452911">"છોડી દો"</string>
+ <!-- no translation found for bubble_dismiss_text (1314082410868930066) -->
+ <skip />
<string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"વાતચીતને બબલ કરશો નહીં"</string>
<string name="bubbles_user_education_title" msgid="5547017089271445797">"બબલનો ઉપયોગ કરીને ચેટ કરો"</string>
<string name="bubbles_user_education_description" msgid="1160281719576715211">"નવી વાતચીત ફ્લોટિંગ આઇકન અથવા બબલ જેવી દેખાશે. બબલને ખોલવા માટે ટૅપ કરો. તેને ખસેડવા માટે ખેંચો."</string>
@@ -1024,11 +1014,14 @@
<string name="notification_content_system_nav_changed" msgid="5077913144844684544">"સિસ્ટમ નૅવિગેશન અપડેટ કર્યું. ફેરફારો કરવા માટે, સેટિંગ પર જાઓ."</string>
<string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"સિસ્ટમ નૅવિગેશનને અપડેટ કરવા માટે સેટિંગ પર જાઓ"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"સ્ટૅન્ડબાય"</string>
+ <string name="priority_onboarding_title" msgid="2893070698479227616">"વાતચીતને પ્રાધાન્યતા ધરાવતી તરીકે સેટ કરી"</string>
+ <string name="priority_onboarding_behavior" msgid="5342816047020432929">"પ્રાધાન્યતા ધરાવતી વાતચીતો:"</string>
<string name="priority_onboarding_show_at_top_text" msgid="1678400241025513541">"વાતચીત વિભાગની ટોચ પર બતાવો"</string>
<string name="priority_onboarding_show_avatar_text" msgid="5756291381124091508">"લૉક સ્ક્રીન પર પ્રોફાઇલ ફોટો બતાવો"</string>
<string name="priority_onboarding_appear_as_bubble_text" msgid="4227039772250263122">"ઍપની ટોચ પર તરતા બબલ તરીકે દેખાય છે"</string>
<string name="priority_onboarding_ignores_dnd_text" msgid="2918952762719600529">"ખલેલ પાડશો નહીં સેટિંગમાં હસ્તક્ષેપ કરી શકે છે"</string>
<string name="priority_onboarding_done_button_title" msgid="4569550984286506007">"સમજાઈ ગયું"</string>
+ <string name="priority_onboarding_settings_button_title" msgid="6663601574303585927">"સેટિંગ"</string>
<string name="magnification_overlay_title" msgid="6584179429612427958">"વિસ્તૃતીકરણ ઓવરલે વિંડો"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"વિસ્તૃતીકરણ વિંડો"</string>
<string name="magnification_controls_title" msgid="8421106606708891519">"વિસ્તૃતીકરણ વિંડોના નિયંત્રણો"</string>
@@ -1070,9 +1063,13 @@
<string name="controls_structure_tooltip" msgid="4355922222944447867">"વધુ જોવા માટે સ્વાઇપ કરો"</string>
<string name="controls_seeding_in_progress" msgid="3033855341410264148">"સુઝાવ લોડ કરી રહ્યાં છીએ"</string>
<string name="controls_media_close_session" msgid="9023534788828414585">"આ મીડિયા સત્રને બંધ કરો"</string>
+ <string name="controls_media_resume" msgid="1933520684481586053">"ફરી શરૂ કરો"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"નિષ્ક્રિય, ઍપને ચેક કરો"</string>
<string name="controls_error_retryable" msgid="864025882878378470">"ભૂલ, ફરી પ્રયાસ કરી રહ્યા છીએ…"</string>
- <string name="controls_error_removed" msgid="6299213591234723805">"ડિવાઇસ કાઢી નાખ્યું"</string>
+ <string name="controls_error_removed" msgid="6675638069846014366">"મળ્યું નથી"</string>
+ <string name="controls_error_removed_title" msgid="1207794911208047818">"નિયંત્રણ ઉપલબ્ધ નથી"</string>
+ <string name="controls_error_removed_message" msgid="2885911717034750542">"<xliff:g id="DEVICE">%1$s</xliff:g>ને ઍક્સેસ કરી શક્યાં નહીં. નિયંત્રણ હજી પણ ઉપલબ્ધ છે અને તે કે ઍપના સેટિંગ બદલાયા નથી તેની ખાતરી કરવા માટે <xliff:g id="APPLICATION">%2$s</xliff:g> ઍપ ચેક કરો."</string>
+ <string name="controls_open_app" msgid="483650971094300141">"ઍપ ખોલો"</string>
<string name="controls_error_generic" msgid="352500456918362905">"સ્ટેટસ લોડ કરી શકાતું નથી"</string>
<string name="controls_error_failed" msgid="960228639198558525">"ભૂલ, ફરીથી પ્રયાસ કરો"</string>
<string name="controls_in_progress" msgid="4421080500238215939">"પ્રક્રિયા ચાલુ છે"</string>
diff --git a/packages/SystemUI/res/values-hi/strings.xml b/packages/SystemUI/res/values-hi/strings.xml
index ba84d090287f..428840742b45 100644
--- a/packages/SystemUI/res/values-hi/strings.xml
+++ b/packages/SystemUI/res/values-hi/strings.xml
@@ -77,9 +77,6 @@
<string name="compat_mode_on" msgid="4963711187149440884">"स्‍क्रीन भरने के लिए ज़ूम करें"</string>
<string name="compat_mode_off" msgid="7682459748279487945">"स्‍क्रीन भरने के लिए खींचें"</string>
<string name="global_action_screenshot" msgid="2760267567509131654">"स्क्रीनशॉट"</string>
- <string name="global_action_lock_message" product="default" msgid="4466026255205186456">"ज़्यादा विकल्प देखने के लिए, अपना फ़ोन अनलॉक करें"</string>
- <string name="global_action_lock_message" product="tablet" msgid="7621167597240332986">"ज़्यादा विकल्प देखने के लिए, अपना टैबलेट अनलॉक करें"</string>
- <string name="global_action_lock_message" product="device" msgid="538790401275363781">"ज़्यादा विकल्प देखने के लिए, अपना डिवाइस अनलॉक करें"</string>
<string name="remote_input_image_insertion_text" msgid="4850791636452521123">"एक इमेज भेजी गई"</string>
<string name="screenshot_saving_ticker" msgid="6519186952674544916">"स्क्रीनशॉट सहेजा जा रहा है..."</string>
<string name="screenshot_saving_title" msgid="2298349784913287333">"स्क्रीनशॉट सहेजा जा रहा है..."</string>
@@ -597,29 +594,21 @@
<string name="volume_odi_captions_hint_enable" msgid="2073091194012843195">"चालू करें"</string>
<string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"बंद करें"</string>
<string name="accessibility_output_chooser" msgid="7807898688967194183">"आउटपुट डिवाइस बदलें"</string>
- <!-- no translation found for screen_pinning_title (9058007390337841305) -->
- <skip />
+ <string name="screen_pinning_title" msgid="9058007390337841305">"ऐप्लिकेशन पिन किया गया है"</string>
<string name="screen_pinning_description" msgid="8699395373875667743">"इससे वह तब तक दिखता रहता है जब तक कि आप उसे अनपिन नहीं कर देते. अनपिन करने के लिए, \'वापस जाएं\' और \'खास जानकारी\' को दबाकर रखें."</string>
<string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"इससे वह तब तक दिखाई देती है जब तक आप उसे अनपिन नहीं कर देते. अनपिन करने के लिए, होम और वापस जाएं वाले बटन को दबाकर रखें."</string>
<string name="screen_pinning_description_gestural" msgid="7246323931831232068">"इससे ऐप्लिकेशन की स्क्रीन तब तक दिखाई देती है जब तक आप उसे अनपिन नहीं करते. अनपिन करने के लिए ऊपर स्वाइप करें और स्क्रीन दबाकर रखें."</string>
<string name="screen_pinning_description_accessible" msgid="7386449191953535332">"इससे वह तब तक दिखता रहता है जब तक कि आप उसे अनपिन नहीं कर देते. अनपिन करने के लिए, \'खास जानकारी\' को दबाकर रखें."</string>
<string name="screen_pinning_description_recents_invisible_accessible" msgid="2857071808674481986">"इससे वह तब तक दिखाई देती है जब तक आप उसे अनपिन नहीं कर देते. अनपिन करने के लिए, होम बटन को दबाकर रखें."</string>
- <!-- no translation found for screen_pinning_exposes_personal_data (8189852022981524789) -->
- <skip />
- <!-- no translation found for screen_pinning_can_open_other_apps (7529756813231421455) -->
- <skip />
- <!-- no translation found for screen_pinning_toast (8177286912533744328) -->
- <skip />
- <!-- no translation found for screen_pinning_toast_recents_invisible (6850978077443052594) -->
- <skip />
- <!-- no translation found for screen_pinning_toast_gesture_nav (170699893395336705) -->
- <skip />
+ <string name="screen_pinning_exposes_personal_data" msgid="8189852022981524789">"निजी डेटा ऐक्सेस किया जा सकता है. जैसे कि संपर्क और ईमेल का कॉन्टेंट."</string>
+ <string name="screen_pinning_can_open_other_apps" msgid="7529756813231421455">"पिन किए गए ऐप्लिकेशन से दूसरे ऐप्लिकेशन भी खोले जा सकते हैं."</string>
+ <string name="screen_pinning_toast" msgid="8177286912533744328">"इस ऐप्लिकेशन को अनपिन करने के लिए, \'वापस जाएं\' और \'खास जानकारी\' बटन को साथ-साथ दबाकर रखें"</string>
+ <string name="screen_pinning_toast_recents_invisible" msgid="6850978077443052594">"इस ऐप्लिकेशन को अनपिन करने के लिए, \'होम\' और \'वापस जाएं\' बटन को साथ-साथ दबाकर रखें"</string>
+ <string name="screen_pinning_toast_gesture_nav" msgid="170699893395336705">"इस ऐप्लिकेशन को अनपिन करने के लिए, ऊपर की ओर स्वाइप करें और स्क्रीन को दबाकर रखें"</string>
<string name="screen_pinning_positive" msgid="3285785989665266984">"ठीक है"</string>
<string name="screen_pinning_negative" msgid="6882816864569211666">"नहीं, रहने दें"</string>
- <!-- no translation found for screen_pinning_start (7483998671383371313) -->
- <skip />
- <!-- no translation found for screen_pinning_exit (4553787518387346893) -->
- <skip />
+ <string name="screen_pinning_start" msgid="7483998671383371313">"ऐप्लिकेशन पिन किया गया"</string>
+ <string name="screen_pinning_exit" msgid="4553787518387346893">"ऐप्लिकेशन अनपिन किया गया"</string>
<string name="quick_settings_reset_confirmation_title" msgid="463533331480997595">"<xliff:g id="TILE_LABEL">%1$s</xliff:g> को छिपाएं?"</string>
<string name="quick_settings_reset_confirmation_message" msgid="2320586180785674186">"जब आप उसे अगली बार सेटिंग में चालू करेंगे तो वह फिर से दिखाई देगी."</string>
<string name="quick_settings_reset_confirmation_button" msgid="3341477479055016776">"छिपाएं"</string>
@@ -732,7 +721,7 @@
<string name="notification_channel_summary_priority" msgid="7952654515769021553">"इससे बातचीत की सुविधा, सेक्शन में सबसे ऊपर और फ़्लोटिंग बबल के तौर पर दिखती है. साथ ही, लॉक स्क्रीन पर प्रोफ़ाइल फ़ोटो दिखती है"</string>
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"सेटिंग"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"प्राथमिकता"</string>
- <string name="no_shortcut" msgid="7176375126961212514">"<xliff:g id="APP_NAME">%1$s</xliff:g> में हर बातचीत के लिए अलग सेटिंग तय नहीं की जा सकती"</string>
+ <string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> पर बातचीत की सुविधाएं काम नहीं करतीं"</string>
<string name="bubble_overflow_empty_title" msgid="3120029421991510842">"हाल ही के बबल्स मौजूद नहीं हैं"</string>
<string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"हाल ही के बबल्स और हटाए गए बबल्स यहां दिखेंगे"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"ये सूचनाएं नहीं बदली जा सकती हैं."</string>
@@ -1015,7 +1004,8 @@
<string name="bubble_accessibility_action_move_top_right" msgid="6916868852433483569">"सबसे ऊपर दाईं ओर ले जाएं"</string>
<string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"बाईं ओर सबसे नीचे ले जाएं"</string>
<string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"सबसे नीचे दाईं ओर ले जाएं"</string>
- <string name="bubble_dismiss_text" msgid="7071770411580452911">"खारिज करें"</string>
+ <!-- no translation found for bubble_dismiss_text (1314082410868930066) -->
+ <skip />
<string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"बातचीत को बबल न करें"</string>
<string name="bubbles_user_education_title" msgid="5547017089271445797">"बबल्स का इस्तेमाल करके चैट करें"</string>
<string name="bubbles_user_education_description" msgid="1160281719576715211">"नई बातचीत फ़्लोटिंग आइकॉन या बबल्स की तरह दिखेंगी. बबल को खोलने के लिए टैप करें. इसे एक जगह से दूसरी जगह ले जाने के लिए खींचें और छोड़ें."</string>
@@ -1026,11 +1016,14 @@
<string name="notification_content_system_nav_changed" msgid="5077913144844684544">"सिस्टम नेविगेशन अपडेट हो गया. बदलाव करने के लिए \'सेटिंग\' पर जाएं."</string>
<string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"सिस्टम नेविगेशन अपडेट करने के लिए \'सेटिंग\' में जाएं"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"स्टैंडबाई"</string>
+ <string name="priority_onboarding_title" msgid="2893070698479227616">"बातचीत को अहम बातचीत के तौर पर सेट किया गया है"</string>
+ <string name="priority_onboarding_behavior" msgid="5342816047020432929">"अहम बातचीत:"</string>
<string name="priority_onboarding_show_at_top_text" msgid="1678400241025513541">"बातचीत सेक्शन में सबसे ऊपर दिखाएं"</string>
<string name="priority_onboarding_show_avatar_text" msgid="5756291381124091508">"लॉक स्क्रीन पर प्रोफ़ाइल फ़ोटो दिखाएं"</string>
<string name="priority_onboarding_appear_as_bubble_text" msgid="4227039772250263122">"खास बातचीत फ़्लोटिंग बबल की तरह ऐप्लिकेशन के ऊपर दिखेंगी"</string>
<string name="priority_onboarding_ignores_dnd_text" msgid="2918952762719600529">"\'परेशान न करें\' मोड में रुकावट"</string>
<string name="priority_onboarding_done_button_title" msgid="4569550984286506007">"ठीक है"</string>
+ <string name="priority_onboarding_settings_button_title" msgid="6663601574303585927">"सेटिंग"</string>
<string name="magnification_overlay_title" msgid="6584179429612427958">"Magnification Overlay Window"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"स्क्रीन को बड़ा करके दिखाने वाली विंडो"</string>
<string name="magnification_controls_title" msgid="8421106606708891519">"स्क्रीन को बड़ा करके दिखाने वाली विंडो के नियंत्रण"</string>
@@ -1072,9 +1065,13 @@
<string name="controls_structure_tooltip" msgid="4355922222944447867">"ज़्यादा देखने के लिए स्वाइप करें"</string>
<string name="controls_seeding_in_progress" msgid="3033855341410264148">"सुझाव लोड हो रहे हैं"</string>
<string name="controls_media_close_session" msgid="9023534788828414585">"इस मीडिया सेशन को बंद करें"</string>
+ <string name="controls_media_resume" msgid="1933520684481586053">"फिर से शुरू करें"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"काम नहीं कर रहा, ऐप जांचें"</string>
<string name="controls_error_retryable" msgid="864025882878378470">"कोई गड़बड़ी हुई, फिर से कोशिश की जा रही है…"</string>
- <string name="controls_error_removed" msgid="6299213591234723805">"डिवाइस हटाया गया"</string>
+ <string name="controls_error_removed" msgid="6675638069846014366">"कंट्रोल नहीं मिला"</string>
+ <string name="controls_error_removed_title" msgid="1207794911208047818">"कंट्रोल मौजूद नहीं है"</string>
+ <string name="controls_error_removed_message" msgid="2885911717034750542">"<xliff:g id="DEVICE">%1$s</xliff:g> ऐक्सेस नहीं किया जा सका. <xliff:g id="APPLICATION">%2$s</xliff:g> ऐप्लिकेशन देखें, ताकि यह पक्का किया जा सके कि कंट्रोल अब भी मौजूद है और सेटिंग में कोई बदलाव नहीं हुआ है."</string>
+ <string name="controls_open_app" msgid="483650971094300141">"ऐप्लिकेशन खोलें"</string>
<string name="controls_error_generic" msgid="352500456918362905">"स्थिति लोड नहीं की जा सकती"</string>
<string name="controls_error_failed" msgid="960228639198558525">"गड़बड़ी हुई, फिर से कोशिश करें"</string>
<string name="controls_in_progress" msgid="4421080500238215939">"जारी है"</string>
diff --git a/packages/SystemUI/res/values-hr/strings.xml b/packages/SystemUI/res/values-hr/strings.xml
index 003f05c2ad84..b8b784c36735 100644
--- a/packages/SystemUI/res/values-hr/strings.xml
+++ b/packages/SystemUI/res/values-hr/strings.xml
@@ -77,9 +77,6 @@
<string name="compat_mode_on" msgid="4963711187149440884">"Zumiraj i ispuni zaslon"</string>
<string name="compat_mode_off" msgid="7682459748279487945">"Rastegni i ispuni zaslon"</string>
<string name="global_action_screenshot" msgid="2760267567509131654">"Snimka zaslona"</string>
- <string name="global_action_lock_message" product="default" msgid="4466026255205186456">"Za više opcija otključajte telefon"</string>
- <string name="global_action_lock_message" product="tablet" msgid="7621167597240332986">"Za više opcija otključajte tablet"</string>
- <string name="global_action_lock_message" product="device" msgid="538790401275363781">"Za više opcija otključajte uređaj"</string>
<string name="remote_input_image_insertion_text" msgid="4850791636452521123">"šalje sliku"</string>
<string name="screenshot_saving_ticker" msgid="6519186952674544916">"Spremanje snimke zaslona..."</string>
<string name="screenshot_saving_title" msgid="2298349784913287333">"Spremanje snimke zaslona..."</string>
@@ -725,7 +722,7 @@
<string name="notification_channel_summary_priority" msgid="7952654515769021553">"Prikazuje se pri vrhu odjeljka razgovora kao pomični oblačić i prikazuje profilnu sliku na zaključanom zaslonu"</string>
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"Postavke"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"Prioritet"</string>
- <string name="no_shortcut" msgid="7176375126961212514">"<xliff:g id="APP_NAME">%1$s</xliff:g> ne podržava postavke koje se odnose na razgovor"</string>
+ <string name="no_shortcut" msgid="8257177117568230126">"Aplikacija <xliff:g id="APP_NAME">%1$s</xliff:g> ne podržava značajke razgovora"</string>
<string name="bubble_overflow_empty_title" msgid="3120029421991510842">"Nema nedavnih oblačića"</string>
<string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"Ovdje će se prikazivati nedavni i odbačeni oblačići"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"Te se obavijesti ne mogu izmijeniti."</string>
@@ -1010,7 +1007,8 @@
<string name="bubble_accessibility_action_move_top_right" msgid="6916868852433483569">"Premjesti u gornji desni kut"</string>
<string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"Premjesti u donji lijevi kut"</string>
<string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"Premjestite u donji desni kut"</string>
- <string name="bubble_dismiss_text" msgid="7071770411580452911">"Odbaci"</string>
+ <!-- no translation found for bubble_dismiss_text (1314082410868930066) -->
+ <skip />
<string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"Zaustavi razgovor u oblačićima"</string>
<string name="bubbles_user_education_title" msgid="5547017089271445797">"Chatanje pomoću oblačića"</string>
<string name="bubbles_user_education_description" msgid="1160281719576715211">"Novi razgovori pojavljuju se kao pomične ikone ili oblačići. Dodirnite za otvaranje oblačića. Povucite da biste ga premjestili."</string>
@@ -1021,11 +1019,14 @@
<string name="notification_content_system_nav_changed" msgid="5077913144844684544">"Ažurirana je navigacija sustavom. Možete je promijeniti u Postavkama."</string>
<string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"Navigaciju sustavom možete ažurirati u Postavkama"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Stanje mirovanja"</string>
+ <string name="priority_onboarding_title" msgid="2893070698479227616">"Razgovor postavljen na prioritetan"</string>
+ <string name="priority_onboarding_behavior" msgid="5342816047020432929">"Prioritetni razgovori će sljedeće:"</string>
<string name="priority_onboarding_show_at_top_text" msgid="1678400241025513541">"Prikazuje se pri vrhu odjeljka razgovora"</string>
<string name="priority_onboarding_show_avatar_text" msgid="5756291381124091508">"Prikazuje profilnu sliku na zaključanom zaslonu"</string>
<string name="priority_onboarding_appear_as_bubble_text" msgid="4227039772250263122">"Prikazuje se kao lebdeći oblačić iznad aplikacija"</string>
<string name="priority_onboarding_ignores_dnd_text" msgid="2918952762719600529">"Prekida Ne uznemiravaj"</string>
<string name="priority_onboarding_done_button_title" msgid="4569550984286506007">"Shvaćam"</string>
+ <string name="priority_onboarding_settings_button_title" msgid="6663601574303585927">"Postavke"</string>
<string name="magnification_overlay_title" msgid="6584179429612427958">"Prozor preklapanja povećavanja"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"Prozor za povećavanje"</string>
<string name="magnification_controls_title" msgid="8421106606708891519">"Kontrole prozora za povećavanje"</string>
@@ -1068,9 +1069,13 @@
<string name="controls_structure_tooltip" msgid="4355922222944447867">"Prijeđite prstom da vidite više"</string>
<string name="controls_seeding_in_progress" msgid="3033855341410264148">"Učitavanje preporuka"</string>
<string name="controls_media_close_session" msgid="9023534788828414585">"Zatvorite ovu medijsku sesiju"</string>
+ <string name="controls_media_resume" msgid="1933520684481586053">"Nastavi"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"Neaktivno, provjerite aplik."</string>
<string name="controls_error_retryable" msgid="864025882878378470">"Pogreška, pokušavamo ponovo…"</string>
- <string name="controls_error_removed" msgid="6299213591234723805">"Uređaj je uklonjen"</string>
+ <string name="controls_error_removed" msgid="6675638069846014366">"Nije pronađeno"</string>
+ <string name="controls_error_removed_title" msgid="1207794911208047818">"Kontrola nije dostupna"</string>
+ <string name="controls_error_removed_message" msgid="2885911717034750542">"Nije moguće pristupiti uređaju: <xliff:g id="DEVICE">%1$s</xliff:g>. U aplikaciji <xliff:g id="APPLICATION">%2$s</xliff:g> provjerite je li kontrola i dalje dostupna te potvrdite da se postavke aplikacije nisu promijenile."</string>
+ <string name="controls_open_app" msgid="483650971094300141">"Otvori apl."</string>
<string name="controls_error_generic" msgid="352500456918362905">"Status se ne može učitati"</string>
<string name="controls_error_failed" msgid="960228639198558525">"Pogreška, pokušajte ponovo"</string>
<string name="controls_in_progress" msgid="4421080500238215939">"U tijeku"</string>
diff --git a/packages/SystemUI/res/values-hu/strings.xml b/packages/SystemUI/res/values-hu/strings.xml
index 8e3a833289a3..551fcd8b2975 100644
--- a/packages/SystemUI/res/values-hu/strings.xml
+++ b/packages/SystemUI/res/values-hu/strings.xml
@@ -77,9 +77,6 @@
<string name="compat_mode_on" msgid="4963711187149440884">"Nagyítás a kitöltéshez"</string>
<string name="compat_mode_off" msgid="7682459748279487945">"Nyújtás kitöltéshez"</string>
<string name="global_action_screenshot" msgid="2760267567509131654">"Képernyőkép"</string>
- <string name="global_action_lock_message" product="default" msgid="4466026255205186456">"További lehetőségekért oldja fel a telefont"</string>
- <string name="global_action_lock_message" product="tablet" msgid="7621167597240332986">"További lehetőségekért oldja fel a táblagépet"</string>
- <string name="global_action_lock_message" product="device" msgid="538790401275363781">"További lehetőségekért oldja fel az eszközt"</string>
<string name="remote_input_image_insertion_text" msgid="4850791636452521123">"képet küldött"</string>
<string name="screenshot_saving_ticker" msgid="6519186952674544916">"Képernyőkép mentése..."</string>
<string name="screenshot_saving_title" msgid="2298349784913287333">"Képernyőkép mentése..."</string>
@@ -722,7 +719,7 @@
<string name="notification_channel_summary_priority" msgid="7952654515769021553">"A beszélgetések szakaszának tetején, lebegő buborékként látható, megjeleníti a profilképet a lezárási képernyőn"</string>
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"Beállítások"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"Prioritás"</string>
- <string name="no_shortcut" msgid="7176375126961212514">"A(z) <xliff:g id="APP_NAME">%1$s</xliff:g> alkalmazás nem támogatja a beszélgetésspecifikus beállításokat"</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>
<string name="bubble_overflow_empty_title" msgid="3120029421991510842">"Nincsenek buborékok a közelmúltból"</string>
<string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"A legutóbbi és az elvetett buborékok itt jelennek majd meg"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"Ezeket az értesítéseket nem lehet módosítani."</string>
@@ -1005,7 +1002,8 @@
<string name="bubble_accessibility_action_move_top_right" msgid="6916868852433483569">"Áthelyezés fel és jobbra"</string>
<string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"Áthelyezés le és balra"</string>
<string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"Áthelyezés le és jobbra"</string>
- <string name="bubble_dismiss_text" msgid="7071770411580452911">"Elvetés"</string>
+ <!-- no translation found for bubble_dismiss_text (1314082410868930066) -->
+ <skip />
<string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"Ne jelenjen meg a beszélgetés buborékban"</string>
<string name="bubbles_user_education_title" msgid="5547017089271445797">"Buborékokat használó csevegés"</string>
<string name="bubbles_user_education_description" msgid="1160281719576715211">"Az új beszélgetések lebegő ikonként, vagyis buborékként jelennek meg. A buborék megnyitásához koppintson rá. Áthelyezéshez húzza a kívánt helyre."</string>
@@ -1016,11 +1014,14 @@
<string name="notification_content_system_nav_changed" msgid="5077913144844684544">"A rendszer-navigáció módja megváltozott. Módosításához nyissa meg a Beállításokat."</string>
<string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"A rendszer-navigációs lehetőségeket a Beállításokban módosíthatja"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Készenléti mód"</string>
+ <string name="priority_onboarding_title" msgid="2893070698479227616">"Fontosnak beállított beszélgetés"</string>
+ <string name="priority_onboarding_behavior" msgid="5342816047020432929">"A fontos beszélgetések:"</string>
<string name="priority_onboarding_show_at_top_text" msgid="1678400241025513541">"A beszélgetések szakaszának tetején jelennek meg"</string>
<string name="priority_onboarding_show_avatar_text" msgid="5756291381124091508">"Megjelenítik a profilképet a lezárási képernyőn"</string>
<string name="priority_onboarding_appear_as_bubble_text" msgid="4227039772250263122">"Buborékként jelennek meg az alkalmazások felett"</string>
<string name="priority_onboarding_ignores_dnd_text" msgid="2918952762719600529">"Megszakítják a Ne zavarjanak módot"</string>
<string name="priority_onboarding_done_button_title" msgid="4569550984286506007">"Értem"</string>
+ <string name="priority_onboarding_settings_button_title" msgid="6663601574303585927">"Beállítások"</string>
<string name="magnification_overlay_title" msgid="6584179429612427958">"Nagyítási fedvény ablaka"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"Nagyítás ablaka"</string>
<string name="magnification_controls_title" msgid="8421106606708891519">"Nagyítási vezérlők ablaka"</string>
@@ -1056,15 +1057,19 @@
<string name="controls_pin_wrong" msgid="6162694056042164211">"Helytelen PIN-kód"</string>
<string name="controls_pin_verifying" msgid="3755045989392131746">"Ellenőrzés…"</string>
<string name="controls_pin_instructions" msgid="6363309783822475238">"PIN-kód megadása"</string>
- <string name="controls_pin_instructions_retry" msgid="1566667581012131046">"Próbálkozzon másik PIN-kóddal"</string>
+ <string name="controls_pin_instructions_retry" msgid="1566667581012131046">"Próbálkozzon másik kóddal"</string>
<string name="controls_confirmation_confirming" msgid="2596071302617310665">"Megerősítés…"</string>
<string name="controls_confirmation_message" msgid="7744104992609594859">"A(z) <xliff:g id="DEVICE">%s</xliff:g> módosításának megerősítése"</string>
<string name="controls_structure_tooltip" msgid="4355922222944447867">"Továbbiak megtekintéséhez csúsztasson"</string>
<string name="controls_seeding_in_progress" msgid="3033855341410264148">"Javaslatok betöltése…"</string>
<string name="controls_media_close_session" msgid="9023534788828414585">"Médiamunkamenet bezárása"</string>
+ <string name="controls_media_resume" msgid="1933520684481586053">"Folytatás"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"Inaktív, ellenőrizze az appot"</string>
<string name="controls_error_retryable" msgid="864025882878378470">"Hiba, újrapróbálkozás…"</string>
- <string name="controls_error_removed" msgid="6299213591234723805">"Eszköz eltávolítva"</string>
+ <string name="controls_error_removed" msgid="6675638069846014366">"Nem található"</string>
+ <string name="controls_error_removed_title" msgid="1207794911208047818">"Nem hozzáférhető vezérlő"</string>
+ <string name="controls_error_removed_message" msgid="2885911717034750542">"Nem lehet hozzáférni a következőhöz: <xliff:g id="DEVICE">%1$s</xliff:g>. Ellenőrizze a(z) <xliff:g id="APPLICATION">%2$s</xliff:g> alkalmazást, és győződjön meg arról, hogy a vezérlő továbbra is rendelkezésre áll, illetve nem változtak az alkalmazás beállításai."</string>
+ <string name="controls_open_app" msgid="483650971094300141">"App megnyitása"</string>
<string name="controls_error_generic" msgid="352500456918362905">"Állapot betöltése sikertelen"</string>
<string name="controls_error_failed" msgid="960228639198558525">"Hiba történt. Próbálja újra."</string>
<string name="controls_in_progress" msgid="4421080500238215939">"Folyamatban"</string>
diff --git a/packages/SystemUI/res/values-hy/strings.xml b/packages/SystemUI/res/values-hy/strings.xml
index dc84c41e7246..730f1155502b 100644
--- a/packages/SystemUI/res/values-hy/strings.xml
+++ b/packages/SystemUI/res/values-hy/strings.xml
@@ -77,9 +77,6 @@
<string name="compat_mode_on" msgid="4963711187149440884">"Խոշորացնել` էկրանը լցնելու համար"</string>
<string name="compat_mode_off" msgid="7682459748279487945">"Ձգել` էկրանը լցնելու համար"</string>
<string name="global_action_screenshot" msgid="2760267567509131654">"Սքրինշոթ"</string>
- <string name="global_action_lock_message" product="default" msgid="4466026255205186456">"Ապակողպեք ձեր հեռախոսը՝ լրացուցիչ կարգավորումները տեսնելու համար"</string>
- <string name="global_action_lock_message" product="tablet" msgid="7621167597240332986">"Ապակողպեք ձեր պլանշետը՝ լրացուցիչ կարգավորումները տեսնելու համար"</string>
- <string name="global_action_lock_message" product="device" msgid="538790401275363781">"Ապակողպեք ձեր սարքը՝ լրացուցիչ կարգավորումները տեսնելու համար"</string>
<string name="remote_input_image_insertion_text" msgid="4850791636452521123">"պատկեր է ուղարկվել"</string>
<string name="screenshot_saving_ticker" msgid="6519186952674544916">"Սքրինշոթը պահվում է…"</string>
<string name="screenshot_saving_title" msgid="2298349784913287333">"Սքրինշոթը պահվում է..."</string>
@@ -595,29 +592,21 @@
<string name="volume_odi_captions_hint_enable" msgid="2073091194012843195">"միացնել"</string>
<string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"անջատել"</string>
<string name="accessibility_output_chooser" msgid="7807898688967194183">"Փոխել արտածման սարքը"</string>
- <!-- no translation found for screen_pinning_title (9058007390337841305) -->
- <skip />
+ <string name="screen_pinning_title" msgid="9058007390337841305">"Հավելվածն ամրացված է"</string>
<string name="screen_pinning_description" msgid="8699395373875667743">"Էկրանը կմնա տեսադաշտում, մինչև այն ապամրացնեք: Ապամրացնելու համար հպեք և պահեք Հետ և Համատեսք կոճակները:"</string>
<string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"Էկրանը կցուցադրվի այնքան ժամանակ, մինչև չապամրացնեք այն: Ապամրացնելու համար հպեք և պահեք «Հետ» և «Գլխավոր էկրան» կոճակները"</string>
<string name="screen_pinning_description_gestural" msgid="7246323931831232068">"Էկրանը կցուցադրվի այնքան ժամանակ, մինչև որ չապամրացնեք այն: Ապամրացնելու համար մատը սահեցրեք վեր և պահեք։"</string>
<string name="screen_pinning_description_accessible" msgid="7386449191953535332">"Էկրանը կմնա տեսադաշտում, մինչև այն ապամրացնեք: Ապամրացնելու համար հպեք և պահեք Համատեսք կոճակը:"</string>
<string name="screen_pinning_description_recents_invisible_accessible" msgid="2857071808674481986">"Էկրանը կցուցադրվի այնքան ժամանակ, մինչև որ չապամրացնեք այն: Ապամրացնելու համար հպեք և պահեք գլխավոր էկրանի կոճակը:"</string>
- <!-- no translation found for screen_pinning_exposes_personal_data (8189852022981524789) -->
- <skip />
- <!-- no translation found for screen_pinning_can_open_other_apps (7529756813231421455) -->
- <skip />
- <!-- no translation found for screen_pinning_toast (8177286912533744328) -->
- <skip />
- <!-- no translation found for screen_pinning_toast_recents_invisible (6850978077443052594) -->
- <skip />
- <!-- no translation found for screen_pinning_toast_gesture_nav (170699893395336705) -->
- <skip />
+ <string name="screen_pinning_exposes_personal_data" msgid="8189852022981524789">"Ձեր անձնական տվյալները (օր․՝ կոնտակտները և նամակների բովանդակությունը) կարող են հասանելի դառնալ։"</string>
+ <string name="screen_pinning_can_open_other_apps" msgid="7529756813231421455">"Ամրացված հավելվածը կարող է այլ հավելվածներ գործարկել։"</string>
+ <string name="screen_pinning_toast" msgid="8177286912533744328">"Հավելվածն ապամրացնելու համար հպեք և պահեք «Հետ» և «Համատեսք» կոճակները"</string>
+ <string name="screen_pinning_toast_recents_invisible" msgid="6850978077443052594">"Հավելվածն ապամրացնելու համար հպեք և պահեք «Հետ» և «Գլխավոր էկրան» կոճակները"</string>
+ <string name="screen_pinning_toast_gesture_nav" msgid="170699893395336705">"Հավելվածն ապամրացնելու համար մատը սահեցրեք վերև և պահեք"</string>
<string name="screen_pinning_positive" msgid="3285785989665266984">"Եղավ"</string>
<string name="screen_pinning_negative" msgid="6882816864569211666">"Ոչ"</string>
- <!-- no translation found for screen_pinning_start (7483998671383371313) -->
- <skip />
- <!-- no translation found for screen_pinning_exit (4553787518387346893) -->
- <skip />
+ <string name="screen_pinning_start" msgid="7483998671383371313">"Հավելվածն ամրացվեց"</string>
+ <string name="screen_pinning_exit" msgid="4553787518387346893">"Հավելվածն ապամրացվեց"</string>
<string name="quick_settings_reset_confirmation_title" msgid="463533331480997595">"Թաքցնե՞լ <xliff:g id="TILE_LABEL">%1$s</xliff:g>-ը:"</string>
<string name="quick_settings_reset_confirmation_message" msgid="2320586180785674186">"Այն դարձյալ կհայտնվի, երբ նորից միացնեք կարգավորումներում:"</string>
<string name="quick_settings_reset_confirmation_button" msgid="3341477479055016776">"Թաքցնել"</string>
@@ -730,7 +719,7 @@
<string name="notification_channel_summary_priority" msgid="7952654515769021553">"Ցուցադրվում է զրույցների ցանկի վերևում, հայտնվում է լողացող ամպիկի տեսքով, ցուցադրում է պրոֆիլի նկարը կողպէկրանին"</string>
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"Կարգավորումներ"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"Կարևոր"</string>
- <string name="no_shortcut" msgid="7176375126961212514">"<xliff:g id="APP_NAME">%1$s</xliff:g> հավելվածը չի աջակցում զրույցի կարգավորումները"</string>
+ <string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> հավելվածը զրույցի գործառույթներ չի աջակցում"</string>
<string name="bubble_overflow_empty_title" msgid="3120029421991510842">"Վերջին ամպիկներ չկան"</string>
<string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"Այստեղ կցուցադրվեն վերջերս օգտագործված և փակված ամպիկները, որոնք կկարողանաք հեշտությամբ վերաբացել"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"Այս ծանուցումները չեն կարող փոփոխվել:"</string>
@@ -756,7 +745,7 @@
<string name="inline_undo" msgid="9026953267645116526">"Հետարկել"</string>
<string name="demote" msgid="6225813324237153980">"Նշել այս ծանուցումը որպես ոչ զրույց"</string>
<string name="notification_conversation_favorite" msgid="1905240206975921907">"Կարևոր զրույց"</string>
- <string name="notification_conversation_unfavorite" msgid="181383708304763807">"Ոչ կարևոր զրույց"</string>
+ <string name="notification_conversation_unfavorite" msgid="181383708304763807">"Կարևոր զրույց չէ"</string>
<string name="notification_conversation_mute" msgid="268951550222925548">"Լռեցված"</string>
<string name="notification_conversation_unmute" msgid="2692255619510896710">"Միացնել ծանուցումների ձայնը"</string>
<string name="notification_conversation_bubble" msgid="2242180995373949022">"Ցուցադրել ամպիկը"</string>
@@ -1013,7 +1002,8 @@
<string name="bubble_accessibility_action_move_top_right" msgid="6916868852433483569">"Տեղափոխել վերև՝ աջ"</string>
<string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"Տեղափոխել ներքև՝ ձախ"</string>
<string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"Տեղափոխել ներքև՝ աջ"</string>
- <string name="bubble_dismiss_text" msgid="7071770411580452911">"Փակել"</string>
+ <!-- no translation found for bubble_dismiss_text (1314082410868930066) -->
+ <skip />
<string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"Զրույցը չցուցադրել ամպիկի տեսքով"</string>
<string name="bubbles_user_education_title" msgid="5547017089271445797">"Զրուցել ամպիկների միջոցով"</string>
<string name="bubbles_user_education_description" msgid="1160281719576715211">"Նոր խոսակցությունները կհայտնվեն լողացող պատկերակների կամ ամպիկների տեսքով։ Հպեք՝ ամպիկը բացելու համար։ Քաշեք՝ այն տեղափոխելու համար։"</string>
@@ -1024,11 +1014,14 @@
<string name="notification_content_system_nav_changed" msgid="5077913144844684544">"Համակարգի նավիգացիան թարմացվեց: Փոփոխություններ անելու համար անցեք կարգավորումներ:"</string>
<string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"Թարմացրեք համակարգի նավիգացիան կարգավորումներում"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Սպասման ռեժիմ"</string>
+ <string name="priority_onboarding_title" msgid="2893070698479227616">"Զրույցը նշված է որպես կարևոր"</string>
+ <string name="priority_onboarding_behavior" msgid="5342816047020432929">"Կարևոր զրույցները՝"</string>
<string name="priority_onboarding_show_at_top_text" msgid="1678400241025513541">"Ցուցադրել զրույցների ցանկի վերևում"</string>
<string name="priority_onboarding_show_avatar_text" msgid="5756291381124091508">"Ցուցադրել պրոֆիլի նկարը կողպէկրանին"</string>
<string name="priority_onboarding_appear_as_bubble_text" msgid="4227039772250263122">"Հայտնվում են որպես լողացող ամպիկ հավելվածների վրայից"</string>
<string name="priority_onboarding_ignores_dnd_text" msgid="2918952762719600529">"Ընդհատել «Չանհանգստացնել» ռեժիմը"</string>
<string name="priority_onboarding_done_button_title" msgid="4569550984286506007">"Եղավ"</string>
+ <string name="priority_onboarding_settings_button_title" msgid="6663601574303585927">"Կարգավորումներ"</string>
<string name="magnification_overlay_title" msgid="6584179429612427958">"Խոշորացման պատուհանի վրադրում"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"Խոշորացման պատուհան"</string>
<string name="magnification_controls_title" msgid="8421106606708891519">"Խոշորացման պատուհանի կառավարման տարրեր"</string>
@@ -1070,9 +1063,13 @@
<string name="controls_structure_tooltip" msgid="4355922222944447867">"Սահեցրեք մատը՝ ավելին իմանալու համար"</string>
<string name="controls_seeding_in_progress" msgid="3033855341410264148">"Բեռնման խորհուրդներ"</string>
<string name="controls_media_close_session" msgid="9023534788828414585">"Փակել աշխատաշրջանը"</string>
+ <string name="controls_media_resume" msgid="1933520684481586053">"Շարունակել"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"Ակտիվ չէ, ստուգեք հավելվածը"</string>
<string name="controls_error_retryable" msgid="864025882878378470">"Սխալ. նորից ենք փորձում…"</string>
- <string name="controls_error_removed" msgid="6299213591234723805">"Սարքը հեռացված է"</string>
+ <string name="controls_error_removed" msgid="6675638069846014366">"Չի գտնվել"</string>
+ <string name="controls_error_removed_title" msgid="1207794911208047818">"Կառավարման տարրը հասանելի չէ"</string>
+ <string name="controls_error_removed_message" msgid="2885911717034750542">"<xliff:g id="DEVICE">%1$s</xliff:g> սարքն անհասանելի է։ Ստուգեք <xliff:g id="APPLICATION">%2$s</xliff:g> հավելվածը՝ համոզվելու, որ կառավարման տարրը դեռ հասանելի է և հավելվածի կարգավորումները չեն փոխվել։"</string>
+ <string name="controls_open_app" msgid="483650971094300141">"Բացել հավելվածը"</string>
<string name="controls_error_generic" msgid="352500456918362905">"Չհաջողվեց բեռնել կարգավիճակը"</string>
<string name="controls_error_failed" msgid="960228639198558525">"Սխալ առաջացավ։ Նորից փորձեք։"</string>
<string name="controls_in_progress" msgid="4421080500238215939">"Ընթացքի մեջ է"</string>
diff --git a/packages/SystemUI/res/values-in/strings.xml b/packages/SystemUI/res/values-in/strings.xml
index afb96b3b520b..3614cb4d88c0 100644
--- a/packages/SystemUI/res/values-in/strings.xml
+++ b/packages/SystemUI/res/values-in/strings.xml
@@ -77,9 +77,6 @@
<string name="compat_mode_on" msgid="4963711187149440884">"Perbesar utk mengisi layar"</string>
<string name="compat_mode_off" msgid="7682459748279487945">"Rentangkn utk mngisi layar"</string>
<string name="global_action_screenshot" msgid="2760267567509131654">"Screenshot"</string>
- <string name="global_action_lock_message" product="default" msgid="4466026255205186456">"Buka kunci ponsel untuk melihat opsi lainnya"</string>
- <string name="global_action_lock_message" product="tablet" msgid="7621167597240332986">"Buka kunci tablet untuk opsi lainnya"</string>
- <string name="global_action_lock_message" product="device" msgid="538790401275363781">"Buka kunci perangkat untuk melihat opsi lainnya"</string>
<string name="remote_input_image_insertion_text" msgid="4850791636452521123">"mengirim gambar"</string>
<string name="screenshot_saving_ticker" msgid="6519186952674544916">"Menyimpan screenshot..."</string>
<string name="screenshot_saving_title" msgid="2298349784913287333">"Menyimpan screenshot..."</string>
@@ -197,7 +194,7 @@
<string name="accessibility_data_three_bars" msgid="3036562180893930325">"Data tiga batang."</string>
<string name="accessibility_data_signal_full" msgid="283507058258113551">"Sinyal data penuh."</string>
<string name="accessibility_wifi_name" msgid="4863440268606851734">"Terhubung ke <xliff:g id="WIFI">%s</xliff:g>."</string>
- <string name="accessibility_bluetooth_name" msgid="7300973230214067678">"Tersambung ke <xliff:g id="BLUETOOTH">%s</xliff:g>."</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>
<string name="accessibility_no_wimax" msgid="2014864207473859228">"Tidak ada WiMAX."</string>
<string name="accessibility_wimax_one_bar" msgid="2996915709342221412">"WiMAX satu batang."</string>
@@ -604,7 +601,7 @@
<string name="screen_pinning_exposes_personal_data" msgid="8189852022981524789">"Data pribadi dapat diakses (seperti kontak dan konten email)."</string>
<string name="screen_pinning_can_open_other_apps" msgid="7529756813231421455">"Aplikasi yang dipasangi pin dapat membuka aplikasi lain."</string>
<string name="screen_pinning_toast" msgid="8177286912533744328">"Untuk melepas pin aplikasi ini, sentuh &amp; lama tombol Kembali dan Ringkasan"</string>
- <string name="screen_pinning_toast_recents_invisible" msgid="6850978077443052594">"Untuk melepas pin layar ini, sentuh &amp; lama tombol Kembali dan Layar utama"</string>
+ <string name="screen_pinning_toast_recents_invisible" msgid="6850978077443052594">"Untuk melepas pin aplikasi ini, sentuh &amp; lama tombol Kembali dan Layar utama"</string>
<string name="screen_pinning_toast_gesture_nav" msgid="170699893395336705">"Untuk melepas pin aplikasi ini, geser ke atas &amp; tahan"</string>
<string name="screen_pinning_positive" msgid="3285785989665266984">"Mengerti"</string>
<string name="screen_pinning_negative" msgid="6882816864569211666">"Lain kali"</string>
@@ -722,7 +719,7 @@
<string name="notification_channel_summary_priority" msgid="7952654515769021553">"Muncul di atas bagian percakapan, ditampilkan sebagai balon yang mengambang, menampilkan gambar profil di layar kunci"</string>
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"Setelan"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"Prioritas"</string>
- <string name="no_shortcut" msgid="7176375126961212514">"<xliff:g id="APP_NAME">%1$s</xliff:g> tidak mendukung setelan khusus percakapan"</string>
+ <string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> tidak mendukung fitur percakapan"</string>
<string name="bubble_overflow_empty_title" msgid="3120029421991510842">"Tidak ada balon baru-baru ini"</string>
<string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"Balon yang baru dipakai dan balon yang telah ditutup akan muncul di sini"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"Notifikasi ini tidak dapat diubah."</string>
@@ -1005,7 +1002,8 @@
<string name="bubble_accessibility_action_move_top_right" msgid="6916868852433483569">"Pindahkan ke kanan atas"</string>
<string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"Pindahkan ke kiri bawah"</string>
<string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"Pindahkan ke kanan bawah"</string>
- <string name="bubble_dismiss_text" msgid="7071770411580452911">"Tutup"</string>
+ <!-- no translation found for bubble_dismiss_text (1314082410868930066) -->
+ <skip />
<string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"Jangan gunakan percakapan balon"</string>
<string name="bubbles_user_education_title" msgid="5547017089271445797">"Chat dalam tampilan balon"</string>
<string name="bubbles_user_education_description" msgid="1160281719576715211">"Percakapan baru muncul sebagai ikon mengambang, atau balon. Ketuk untuk membuka balon. Tarik untuk memindahkannya."</string>
@@ -1016,11 +1014,14 @@
<string name="notification_content_system_nav_changed" msgid="5077913144844684544">"Navigasi sistem diupdate. Untuk melakukan perubahan, buka Setelan."</string>
<string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"Buka Setelan untuk mengupdate navigasi sistem"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Siaga"</string>
+ <string name="priority_onboarding_title" msgid="2893070698479227616">"Percakapan disetel ke prioritas"</string>
+ <string name="priority_onboarding_behavior" msgid="5342816047020432929">"Percakapan prioritas akan:"</string>
<string name="priority_onboarding_show_at_top_text" msgid="1678400241025513541">"Muncul di atas bagian percakapan"</string>
<string name="priority_onboarding_show_avatar_text" msgid="5756291381124091508">"Menampilkan gambar profil di layar kunci"</string>
<string name="priority_onboarding_appear_as_bubble_text" msgid="4227039772250263122">"Muncul sebagai balon mengambang di atas aplikasi"</string>
<string name="priority_onboarding_ignores_dnd_text" msgid="2918952762719600529">"Mengganggu fitur Jangan Ganggu"</string>
<string name="priority_onboarding_done_button_title" msgid="4569550984286506007">"Oke"</string>
+ <string name="priority_onboarding_settings_button_title" msgid="6663601574303585927">"Setelan"</string>
<string name="magnification_overlay_title" msgid="6584179429612427958">"Jendela Overlay Pembesaran"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"Jendela Pembesaran"</string>
<string name="magnification_controls_title" msgid="8421106606708891519">"Kontrol Jendela Pembesaran"</string>
@@ -1062,9 +1063,13 @@
<string name="controls_structure_tooltip" msgid="4355922222944447867">"Geser untuk melihat selengkapnya"</string>
<string name="controls_seeding_in_progress" msgid="3033855341410264148">"Memuat rekomendasi"</string>
<string name="controls_media_close_session" msgid="9023534788828414585">"Tutup sesi media ini"</string>
+ <string name="controls_media_resume" msgid="1933520684481586053">"Lanjutkan"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"Nonaktif, periksa aplikasi"</string>
<string name="controls_error_retryable" msgid="864025882878378470">"Error, mencoba lagi..."</string>
- <string name="controls_error_removed" msgid="6299213591234723805">"Perangkat dihapus"</string>
+ <string name="controls_error_removed" msgid="6675638069846014366">"Tidak ditemukan"</string>
+ <string name="controls_error_removed_title" msgid="1207794911208047818">"Kontrol tidak tersedia"</string>
+ <string name="controls_error_removed_message" msgid="2885911717034750542">"Tidak dapat mengakses <xliff:g id="DEVICE">%1$s</xliff:g>. Periksa aplikasi <xliff:g id="APPLICATION">%2$s</xliff:g> untuk memastikan kontrol masih tersedia dan bahwa setelan aplikasi tidak berubah."</string>
+ <string name="controls_open_app" msgid="483650971094300141">"Buka aplikasi"</string>
<string name="controls_error_generic" msgid="352500456918362905">"Tidak dapat memuat status"</string>
<string name="controls_error_failed" msgid="960228639198558525">"Error, coba lagi"</string>
<string name="controls_in_progress" msgid="4421080500238215939">"Dalam proses"</string>
diff --git a/packages/SystemUI/res/values-is/strings.xml b/packages/SystemUI/res/values-is/strings.xml
index 66db202feed5..224164c012e5 100644
--- a/packages/SystemUI/res/values-is/strings.xml
+++ b/packages/SystemUI/res/values-is/strings.xml
@@ -77,9 +77,6 @@
<string name="compat_mode_on" msgid="4963711187149440884">"Fylla skjá með aðdrætti"</string>
<string name="compat_mode_off" msgid="7682459748279487945">"Teygja yfir allan skjáinn"</string>
<string name="global_action_screenshot" msgid="2760267567509131654">"Skjámynd"</string>
- <string name="global_action_lock_message" product="default" msgid="4466026255205186456">"Taktu símann úr lás til að fá fleiri valkosti"</string>
- <string name="global_action_lock_message" product="tablet" msgid="7621167597240332986">"Taktu spjaldtölvuna úr lás til að fá fleiri valkosti"</string>
- <string name="global_action_lock_message" product="device" msgid="538790401275363781">"Taktu tækið úr lás til að fá fleiri valkosti"</string>
<string name="remote_input_image_insertion_text" msgid="4850791636452521123">"sendi mynd"</string>
<string name="screenshot_saving_ticker" msgid="6519186952674544916">"Vistar skjámynd…"</string>
<string name="screenshot_saving_title" msgid="2298349784913287333">"Vistar skjámynd…"</string>
@@ -722,7 +719,7 @@
<string name="notification_channel_summary_priority" msgid="7952654515769021553">"Birtist efst í samtalshluta, birtist sem fljótandi blaðra, birtir prófílmynd á lásskjánum"</string>
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"Áfram"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"Forgangur"</string>
- <string name="no_shortcut" msgid="7176375126961212514">"<xliff:g id="APP_NAME">%1$s</xliff:g> styður ekki stillingar fyrir einstök samtöl"</string>
+ <string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> styður ekki samtalseiginleika"</string>
<string name="bubble_overflow_empty_title" msgid="3120029421991510842">"Engar nýlegar blöðrur"</string>
<string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"Nýlegar blöðrur og blöðrur sem þú hefur lokað birtast hér"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"Ekki er hægt að breyta þessum tilkynningum."</string>
@@ -1005,7 +1002,8 @@
<string name="bubble_accessibility_action_move_top_right" msgid="6916868852433483569">"Færa efst til hægri"</string>
<string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"Færa neðst til vinstri"</string>
<string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"Færðu neðst til hægri"</string>
- <string name="bubble_dismiss_text" msgid="7071770411580452911">"Hunsa"</string>
+ <!-- no translation found for bubble_dismiss_text (1314082410868930066) -->
+ <skip />
<string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"Ekki setja samtal í blöðru"</string>
<string name="bubbles_user_education_title" msgid="5547017089271445797">"Spjalla með blöðrum"</string>
<string name="bubbles_user_education_description" msgid="1160281719576715211">"Ný samtöl birtast sem fljótandi tákn eða blöðrur. Ýttu til að opna blöðru. Dragðu hana til að færa."</string>
@@ -1016,11 +1014,14 @@
<string name="notification_content_system_nav_changed" msgid="5077913144844684544">"Kerfisstjórnun uppfærð. Þú getur breytt þessu í stillingunum."</string>
<string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"Farðu í stillingar til að uppfæra kerfisstjórnun"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Biðstaða"</string>
+ <string name="priority_onboarding_title" msgid="2893070698479227616">"Samtal sett í forgang"</string>
+ <string name="priority_onboarding_behavior" msgid="5342816047020432929">"Forgangssamtöl munu:"</string>
<string name="priority_onboarding_show_at_top_text" msgid="1678400241025513541">"Sýna yfir samtalshluta"</string>
<string name="priority_onboarding_show_avatar_text" msgid="5756291381124091508">"Sýna prófílmynd á lásskjá"</string>
<string name="priority_onboarding_appear_as_bubble_text" msgid="4227039772250263122">"Birta sem fljótandi blöðru yfir forritum"</string>
<string name="priority_onboarding_ignores_dnd_text" msgid="2918952762719600529">"Stöðva „Ónáðið ekki“"</string>
<string name="priority_onboarding_done_button_title" msgid="4569550984286506007">"Ég skil"</string>
+ <string name="priority_onboarding_settings_button_title" msgid="6663601574303585927">"Stillingar"</string>
<string name="magnification_overlay_title" msgid="6584179429612427958">"Stækkun yfirglugga"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"Stækkunargluggi"</string>
<string name="magnification_controls_title" msgid="8421106606708891519">"Stækkunarstillingar glugga"</string>
@@ -1062,9 +1063,13 @@
<string name="controls_structure_tooltip" msgid="4355922222944447867">"Strjúktu til að sjá meira"</string>
<string name="controls_seeding_in_progress" msgid="3033855341410264148">"Hleður tillögum"</string>
<string name="controls_media_close_session" msgid="9023534788828414585">"Loka þessari efnislotu"</string>
+ <string name="controls_media_resume" msgid="1933520684481586053">"Halda áfram"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"Óvirkt, athugaðu forrit"</string>
<string name="controls_error_retryable" msgid="864025882878378470">"Villa, reynir aftur…"</string>
- <string name="controls_error_removed" msgid="6299213591234723805">"Tæki fjarlægt"</string>
+ <string name="controls_error_removed" msgid="6675638069846014366">"Fannst ekki"</string>
+ <string name="controls_error_removed_title" msgid="1207794911208047818">"Stýring er ekki tiltæk"</string>
+ <string name="controls_error_removed_message" msgid="2885911717034750542">"Ekki tókst að tengjast <xliff:g id="DEVICE">%1$s</xliff:g>. Athugaðu <xliff:g id="APPLICATION">%2$s</xliff:g> forritið til að ganga úr skugga um að stýringin sé enn í boði og að stillingum forritsins hafi ekki verið breytt."</string>
+ <string name="controls_open_app" msgid="483650971094300141">"Opna forrit"</string>
<string name="controls_error_generic" msgid="352500456918362905">"Ekki er hægt að hlaða stöðu"</string>
<string name="controls_error_failed" msgid="960228639198558525">"Villa, reyndu aftur"</string>
<string name="controls_in_progress" msgid="4421080500238215939">"Í gangi"</string>
diff --git a/packages/SystemUI/res/values-it/strings.xml b/packages/SystemUI/res/values-it/strings.xml
index 629b850b799e..f9fcda4b3eca 100644
--- a/packages/SystemUI/res/values-it/strings.xml
+++ b/packages/SystemUI/res/values-it/strings.xml
@@ -77,9 +77,6 @@
<string name="compat_mode_on" msgid="4963711187149440884">"Zoom per riempire schermo"</string>
<string name="compat_mode_off" msgid="7682459748279487945">"Estendi per riemp. schermo"</string>
<string name="global_action_screenshot" msgid="2760267567509131654">"Screenshot"</string>
- <string name="global_action_lock_message" product="default" msgid="4466026255205186456">"Sblocca il telefono per visualizzare altre opzioni"</string>
- <string name="global_action_lock_message" product="tablet" msgid="7621167597240332986">"Sblocca il tablet per visualizzare altre opzioni"</string>
- <string name="global_action_lock_message" product="device" msgid="538790401275363781">"Sblocca il dispositivo per visualizzare altre opzioni"</string>
<string name="remote_input_image_insertion_text" msgid="4850791636452521123">"è stata inviata un\'immagine"</string>
<string name="screenshot_saving_ticker" msgid="6519186952674544916">"Salvataggio screenshot..."</string>
<string name="screenshot_saving_title" msgid="2298349784913287333">"Salvataggio screenshot..."</string>
@@ -704,7 +701,7 @@
<string name="inline_deliver_silently_button" msgid="2714314213321223286">"Invia in modalità silenziosa"</string>
<string name="inline_block_button" msgid="479892866568378793">"Blocca"</string>
<string name="inline_keep_button" msgid="299631874103662170">"Continua a mostrare"</string>
- <string name="inline_minimize_button" msgid="1474436209299333445">"Riduci a icona"</string>
+ <string name="inline_minimize_button" msgid="1474436209299333445">"Riduci"</string>
<string name="inline_silent_button_silent" msgid="525243786649275816">"Modalità silenziosa"</string>
<string name="inline_silent_button_stay_silent" msgid="2129254868305468743">"Continua con notifiche silenziose"</string>
<string name="inline_silent_button_alert" msgid="5705343216858250354">"Avvisi"</string>
@@ -712,19 +709,19 @@
<string name="inline_turn_off_notifications" msgid="8543989584403106071">"Disattiva notifiche"</string>
<string name="inline_keep_showing_app" msgid="4393429060390649757">"Continuare a ricevere notifiche da questa app?"</string>
<string name="notification_silence_title" msgid="8608090968400832335">"Modalità silenziosa"</string>
- <string name="notification_alert_title" msgid="3656229781017543655">"Livello predefinito"</string>
+ <string name="notification_alert_title" msgid="3656229781017543655">"Modalità predefinita"</string>
<string name="notification_bubble_title" msgid="8330481035191903164">"Fumetto"</string>
<string name="notification_channel_summary_low" msgid="4860617986908931158">"Nessun suono o vibrazione"</string>
<string name="notification_conversation_summary_low" msgid="1734433426085468009">"Nessun suono o vibrazione e appare più in basso nella sezione delle conversazioni"</string>
- <string name="notification_channel_summary_default" msgid="3282930979307248890">"Potrebbero essere attivati lo squillo o la vibrazione in base alle impostazioni del telefono"</string>
- <string name="notification_channel_summary_default_with_bubbles" msgid="1782419896613644568">"Potrebbero essere attivati lo squillo o la vibrazione in base alle impostazioni del telefono. Conversazioni dalla bolla <xliff:g id="APP_NAME">%1$s</xliff:g> per impostazione predefinita."</string>
+ <string name="notification_channel_summary_default" msgid="3282930979307248890">"Può suonare o vibrare in base alle impostazioni del telefono"</string>
+ <string name="notification_channel_summary_default_with_bubbles" msgid="1782419896613644568">"Può suonare o vibrare in base alle impostazioni del telefono. Conversazioni dalla bolla <xliff:g id="APP_NAME">%1$s</xliff:g> per impostazione predefinita."</string>
<string name="notification_channel_summary_bubble" msgid="7235935211580860537">"Mantiene la tua attenzione con una scorciatoia mobile a questi contenuti."</string>
<string name="notification_channel_summary_priority" msgid="7952654515769021553">"Viene mostrata in cima alla sezione delle conversazioni, appare sotto forma di bolla mobile, mostra l\'immagine del profilo nella schermata di blocco"</string>
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"Impostazioni"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"Priorità"</string>
- <string name="no_shortcut" msgid="7176375126961212514">"<xliff:g id="APP_NAME">%1$s</xliff:g> non supporta impostazioni specifiche per le conversazioni"</string>
+ <string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> non supporta le funzionalità delle conversazioni"</string>
<string name="bubble_overflow_empty_title" msgid="3120029421991510842">"Nessuna bolla recente"</string>
- <string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"Le bolle recenti e ignorate verranno visualizzate qui"</string>
+ <string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"Le bolle recenti e ignorate appariranno qui"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"Impossibile modificare queste notifiche."</string>
<string name="notification_multichannel_desc" msgid="7414593090056236179">"Qui non è possibile configurare questo gruppo di notifiche"</string>
<string name="notification_delegate_header" msgid="1264510071031479920">"Notifica inviata al proxy"</string>
@@ -1005,7 +1002,8 @@
<string name="bubble_accessibility_action_move_top_right" msgid="6916868852433483569">"Sposta in alto a destra"</string>
<string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"Sposta in basso a sinistra"</string>
<string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"Sposta in basso a destra"</string>
- <string name="bubble_dismiss_text" msgid="7071770411580452911">"Ignora"</string>
+ <!-- no translation found for bubble_dismiss_text (1314082410868930066) -->
+ <skip />
<string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"Non utilizzare bolle per la conversazione"</string>
<string name="bubbles_user_education_title" msgid="5547017089271445797">"Chatta utilizzando le bolle"</string>
<string name="bubbles_user_education_description" msgid="1160281719576715211">"Le nuove conversazioni vengono visualizzate come icone mobili o bolle. Tocca per aprire la bolla. Trascinala per spostarla."</string>
@@ -1016,11 +1014,14 @@
<string name="notification_content_system_nav_changed" msgid="5077913144844684544">"Navigazione del sistema aggiornata. Per apportare modifiche, usa le Impostazioni."</string>
<string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"Usa le Impostazioni per aggiornare la navigazione del sistema"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Standby"</string>
+ <string name="priority_onboarding_title" msgid="2893070698479227616">"Conversazione impostata come prioritaria"</string>
+ <string name="priority_onboarding_behavior" msgid="5342816047020432929">"Le conversazioni prioritarie:"</string>
<string name="priority_onboarding_show_at_top_text" msgid="1678400241025513541">"Appaiono in cima alla sezione delle conversazioni"</string>
<string name="priority_onboarding_show_avatar_text" msgid="5756291381124091508">"Mostrano immagine profilo in schermata di blocco"</string>
<string name="priority_onboarding_appear_as_bubble_text" msgid="4227039772250263122">"Vengono mostrate come bolle mobili sopra le app"</string>
<string name="priority_onboarding_ignores_dnd_text" msgid="2918952762719600529">"Interrompono la modalità Non disturbare"</string>
<string name="priority_onboarding_done_button_title" msgid="4569550984286506007">"OK"</string>
+ <string name="priority_onboarding_settings_button_title" msgid="6663601574303585927">"Impostazioni"</string>
<string name="magnification_overlay_title" msgid="6584179429612427958">"Finestra overlay ingrandimento"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"Finestra ingrandimento"</string>
<string name="magnification_controls_title" msgid="8421106606708891519">"Finestra controlli di ingrandimento"</string>
@@ -1062,9 +1063,13 @@
<string name="controls_structure_tooltip" msgid="4355922222944447867">"Scorri per vedere altro"</string>
<string name="controls_seeding_in_progress" msgid="3033855341410264148">"Caricamento dei consigli"</string>
<string name="controls_media_close_session" msgid="9023534788828414585">"Chiudi questa sessione multimediale"</string>
+ <string name="controls_media_resume" msgid="1933520684481586053">"Riprendi"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"Inattivo, controlla l\'app"</string>
<string name="controls_error_retryable" msgid="864025882878378470">"Errore. Nuovo tentativo…"</string>
- <string name="controls_error_removed" msgid="6299213591234723805">"Dispositivo rimosso"</string>
+ <string name="controls_error_removed" msgid="6675638069846014366">"Controllo non trovato"</string>
+ <string name="controls_error_removed_title" msgid="1207794911208047818">"Il controllo non è disponibile"</string>
+ <string name="controls_error_removed_message" msgid="2885911717034750542">"Impossibile accedere a: <xliff:g id="DEVICE">%1$s</xliff:g>. Verifica nell\'app <xliff:g id="APPLICATION">%2$s</xliff:g> che il controllo sia ancora disponibile e che le impostazioni dell\'app non siano cambiate."</string>
+ <string name="controls_open_app" msgid="483650971094300141">"Apri app"</string>
<string name="controls_error_generic" msgid="352500456918362905">"Impossibile caricare lo stato"</string>
<string name="controls_error_failed" msgid="960228639198558525">"Errore. Riprova"</string>
<string name="controls_in_progress" msgid="4421080500238215939">"In corso"</string>
diff --git a/packages/SystemUI/res/values-iw/strings.xml b/packages/SystemUI/res/values-iw/strings.xml
index 566baf143760..172919c497e3 100644
--- a/packages/SystemUI/res/values-iw/strings.xml
+++ b/packages/SystemUI/res/values-iw/strings.xml
@@ -77,9 +77,6 @@
<string name="compat_mode_on" msgid="4963711187149440884">"הגדל תצוגה כדי למלא את המסך"</string>
<string name="compat_mode_off" msgid="7682459748279487945">"מתח כדי למלא את המסך"</string>
<string name="global_action_screenshot" msgid="2760267567509131654">"צילום מסך"</string>
- <string name="global_action_lock_message" product="default" msgid="4466026255205186456">"לאפשרויות נוספות, יש לבטל את נעילת הטלפון"</string>
- <string name="global_action_lock_message" product="tablet" msgid="7621167597240332986">"לאפשרויות נוספות, יש לבטל את נעילת הטאבלט"</string>
- <string name="global_action_lock_message" product="device" msgid="538790401275363781">"לאפשרויות נוספות, יש לבטל את נעילת המכשיר"</string>
<string name="remote_input_image_insertion_text" msgid="4850791636452521123">"נשלחה תמונה"</string>
<string name="screenshot_saving_ticker" msgid="6519186952674544916">"שומר צילום מסך..."</string>
<string name="screenshot_saving_title" msgid="2298349784913287333">"שומר צילום מסך..."</string>
@@ -601,29 +598,21 @@
<string name="volume_odi_captions_hint_enable" msgid="2073091194012843195">"הפעלה"</string>
<string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"השבתה"</string>
<string name="accessibility_output_chooser" msgid="7807898688967194183">"החלפת מכשיר פלט"</string>
- <!-- no translation found for screen_pinning_title (9058007390337841305) -->
- <skip />
+ <string name="screen_pinning_title" msgid="9058007390337841305">"האפליקציה מוצמדת"</string>
<string name="screen_pinning_description" msgid="8699395373875667743">"נשאר בתצוגה עד לביטול ההצמדה. יש ללחוץ לחיצה ארוכה על הלחצנים \'הקודם\' ו\'סקירה\' כדי לבטל את ההצמדה."</string>
<string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"נשאר בתצוגה עד לביטול ההצמדה. יש ללחוץ לחיצה ארוכה על הלחצנים \'הקודם\' ו\'דף הבית\' כדי לבטל את ההצמדה."</string>
<string name="screen_pinning_description_gestural" msgid="7246323931831232068">"נשאר בתצוגה עד לביטול ההצמדה. יש להחליק למעלה ולהחזיק כדי לבטל הצמדה."</string>
<string name="screen_pinning_description_accessible" msgid="7386449191953535332">"נשאר בתצוגה עד לביטול ההצמדה. יש ללחוץ לחיצה ארוכה על הלחצן \'סקירה\' כדי לבטל את ההצמדה."</string>
<string name="screen_pinning_description_recents_invisible_accessible" msgid="2857071808674481986">"נשאר בתצוגה עד לביטול ההצמדה. יש ללחוץ לחיצה ארוכה על הלחצן \'דף הבית\' כדי לבטל את ההצמדה."</string>
- <!-- no translation found for screen_pinning_exposes_personal_data (8189852022981524789) -->
- <skip />
- <!-- no translation found for screen_pinning_can_open_other_apps (7529756813231421455) -->
- <skip />
- <!-- no translation found for screen_pinning_toast (8177286912533744328) -->
- <skip />
- <!-- no translation found for screen_pinning_toast_recents_invisible (6850978077443052594) -->
- <skip />
- <!-- no translation found for screen_pinning_toast_gesture_nav (170699893395336705) -->
- <skip />
+ <string name="screen_pinning_exposes_personal_data" msgid="8189852022981524789">"ייתכן שתתאפשר גישה למידע אישי (כמו אנשי קשר ותוכן מהאימייל)."</string>
+ <string name="screen_pinning_can_open_other_apps" msgid="7529756813231421455">"האפליקציה שהוצמדה עשויה לפתוח אפליקציות אחרות."</string>
+ <string name="screen_pinning_toast" msgid="8177286912533744328">"כדי לבטל את ההצמדה של האפליקציה הזו, יש ללחוץ לחיצה ארוכה על הלחצנים \'הקודם\' ו\'סקירה\'"</string>
+ <string name="screen_pinning_toast_recents_invisible" msgid="6850978077443052594">"כדי לבטל את ההצמדה של האפליקציה הזו, יש ללחוץ לחיצה ארוכה על הלחצן \'הקודם\' והלחצן הראשי"</string>
+ <string name="screen_pinning_toast_gesture_nav" msgid="170699893395336705">"לביטול ההצמדה של האפליקציה הזו, יש להחליק למעלה ולהחזיק"</string>
<string name="screen_pinning_positive" msgid="3285785989665266984">"הבנתי"</string>
<string name="screen_pinning_negative" msgid="6882816864569211666">"לא, תודה"</string>
- <!-- no translation found for screen_pinning_start (7483998671383371313) -->
- <skip />
- <!-- no translation found for screen_pinning_exit (4553787518387346893) -->
- <skip />
+ <string name="screen_pinning_start" msgid="7483998671383371313">"האפליקציה הוצמדה"</string>
+ <string name="screen_pinning_exit" msgid="4553787518387346893">"הצמדת האפליקציה בוטלה"</string>
<string name="quick_settings_reset_confirmation_title" msgid="463533331480997595">"להסתיר<xliff:g id="TILE_LABEL">%1$s</xliff:g>?"</string>
<string name="quick_settings_reset_confirmation_message" msgid="2320586180785674186">"יופיע מחדש בפעם הבאה שתפעיל את האפשרות בהגדרות."</string>
<string name="quick_settings_reset_confirmation_button" msgid="3341477479055016776">"הסתר"</string>
@@ -736,7 +725,7 @@
<string name="notification_channel_summary_priority" msgid="7952654515769021553">"מוצגת בחלק העליון של קטע התראות השיחה, מופיעה בבועה צפה, תוצג תמונת פרופיל במסך הנעילה"</string>
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"הגדרות"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"עדיפות"</string>
- <string name="no_shortcut" msgid="7176375126961212514">"האפליקציה <xliff:g id="APP_NAME">%1$s</xliff:g> לא תומכת בהגדרות ספציפיות לשיחות"</string>
+ <string name="no_shortcut" msgid="8257177117568230126">"האפליקציה <xliff:g id="APP_NAME">%1$s</xliff:g> לא תומכת בתכונות השיחה"</string>
<string name="bubble_overflow_empty_title" msgid="3120029421991510842">"אין בועות מהזמן האחרון"</string>
<string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"בועות אחרונות ובועות שנסגרו יופיעו כאן"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"לא ניתן לשנות את ההתראות האלה."</string>
@@ -1023,7 +1012,8 @@
<string name="bubble_accessibility_action_move_top_right" msgid="6916868852433483569">"העברה לפינה הימנית העליונה"</string>
<string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"העברה לפינה השמאלית התחתונה"</string>
<string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"העברה לפינה הימנית התחתונה"</string>
- <string name="bubble_dismiss_text" msgid="7071770411580452911">"סגירה"</string>
+ <!-- no translation found for bubble_dismiss_text (1314082410868930066) -->
+ <skip />
<string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"אין להציג בועות לשיחה"</string>
<string name="bubbles_user_education_title" msgid="5547017089271445797">"לדבר בצ\'אט באמצעות בועות"</string>
<string name="bubbles_user_education_description" msgid="1160281719576715211">"שיחות חדשות מופיעות כסמלים צפים, או בועות. יש להקיש כדי לפתוח בועה. יש לגרור כדי להזיז אותה."</string>
@@ -1034,11 +1024,14 @@
<string name="notification_content_system_nav_changed" msgid="5077913144844684544">"הניווט במערכת עודכן. אפשר לערוך שינויים דרך ההגדרות."</string>
<string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"יש לעבור להגדרות כדי לעדכן את הניווט במערכת"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"המתנה"</string>
+ <string name="priority_onboarding_title" msgid="2893070698479227616">"השיחה הוגדרה כבעלת עדיפות גבוהה"</string>
+ <string name="priority_onboarding_behavior" msgid="5342816047020432929">"שיחות בעדיפות גבוהה:"</string>
<string name="priority_onboarding_show_at_top_text" msgid="1678400241025513541">"מופיעות בחלק העליון של קטע השיחות"</string>
<string name="priority_onboarding_show_avatar_text" msgid="5756291381124091508">"מציגות תמונת פרופיל במסך הנעילה"</string>
<string name="priority_onboarding_appear_as_bubble_text" msgid="4227039772250263122">"מופיעות כבועה צפה מעל האפליקציות שלך"</string>
<string name="priority_onboarding_ignores_dnd_text" msgid="2918952762719600529">"גוברות על ההגדרה \'נא לא להפריע\'"</string>
<string name="priority_onboarding_done_button_title" msgid="4569550984286506007">"הבנתי"</string>
+ <string name="priority_onboarding_settings_button_title" msgid="6663601574303585927">"הגדרות"</string>
<string name="magnification_overlay_title" msgid="6584179429612427958">"חלון ליצירת שכבת-על להגדלה"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"חלון הגדלה"</string>
<string name="magnification_controls_title" msgid="8421106606708891519">"בקרות של חלון ההגדלה"</string>
@@ -1082,9 +1075,13 @@
<string name="controls_structure_tooltip" msgid="4355922222944447867">"יש להחליק כדי להציג עוד פריטים"</string>
<string name="controls_seeding_in_progress" msgid="3033855341410264148">"בטעינת המלצות"</string>
<string name="controls_media_close_session" msgid="9023534788828414585">"סגירת הסשן הזה של המדיה"</string>
+ <string name="controls_media_resume" msgid="1933520684481586053">"המשך"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"לא פעיל, יש לבדוק את האפליקציה"</string>
<string name="controls_error_retryable" msgid="864025882878378470">"שגיאה, מתבצע ניסיון חוזר…"</string>
- <string name="controls_error_removed" msgid="6299213591234723805">"המכשיר הוסר"</string>
+ <string name="controls_error_removed" msgid="6675638069846014366">"לא נמצא"</string>
+ <string name="controls_error_removed_title" msgid="1207794911208047818">"הפקד לא זמין"</string>
+ <string name="controls_error_removed_message" msgid="2885911717034750542">"לא ניתן להתחבר אל <xliff:g id="DEVICE">%1$s</xliff:g>. יש לבדוק את האפליקציה <xliff:g id="APPLICATION">%2$s</xliff:g> כדי לוודא שהפקד עדיין זמין ושהגדרות האפליקציה לא השתנו."</string>
+ <string name="controls_open_app" msgid="483650971094300141">"לפתיחת האפליקציה"</string>
<string name="controls_error_generic" msgid="352500456918362905">"לא ניתן לטעון את הסטטוס"</string>
<string name="controls_error_failed" msgid="960228639198558525">"שגיאה, יש לנסות שוב"</string>
<string name="controls_in_progress" msgid="4421080500238215939">"בתהליך"</string>
diff --git a/packages/SystemUI/res/values-ja/strings.xml b/packages/SystemUI/res/values-ja/strings.xml
index 7567a224e863..a2bb39cd9e6b 100644
--- a/packages/SystemUI/res/values-ja/strings.xml
+++ b/packages/SystemUI/res/values-ja/strings.xml
@@ -77,9 +77,6 @@
<string name="compat_mode_on" msgid="4963711187149440884">"画面サイズに合わせて拡大"</string>
<string name="compat_mode_off" msgid="7682459748279487945">"画面サイズに合わせて拡大"</string>
<string name="global_action_screenshot" msgid="2760267567509131654">"スクリーンショット"</string>
- <string name="global_action_lock_message" product="default" msgid="4466026255205186456">"スマートフォンのロックを解除してその他のオプションを表示する"</string>
- <string name="global_action_lock_message" product="tablet" msgid="7621167597240332986">"タブレットのロックを解除してその他のオプションを表示する"</string>
- <string name="global_action_lock_message" product="device" msgid="538790401275363781">"デバイスのロックを解除してその他のオプションを表示する"</string>
<string name="remote_input_image_insertion_text" msgid="4850791636452521123">"画像を送信しました"</string>
<string name="screenshot_saving_ticker" msgid="6519186952674544916">"スクリーンショットを保存中..."</string>
<string name="screenshot_saving_title" msgid="2298349784913287333">"スクリーンショットを保存しています..."</string>
@@ -595,29 +592,21 @@
<string name="volume_odi_captions_hint_enable" msgid="2073091194012843195">"有効にする"</string>
<string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"無効にする"</string>
<string name="accessibility_output_chooser" msgid="7807898688967194183">"出力デバイスを選択"</string>
- <!-- no translation found for screen_pinning_title (9058007390337841305) -->
- <skip />
+ <string name="screen_pinning_title" msgid="9058007390337841305">"アプリは固定されています"</string>
<string name="screen_pinning_description" msgid="8699395373875667743">"固定を解除するまで画面が常に表示されるようになります。[戻る] と [最近] を同時に押し続けると固定が解除されます。"</string>
<string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"固定を解除するまで画面が常に表示されるようになります。[戻る] と [ホーム] を同時に押し続けると固定が解除されます。"</string>
<string name="screen_pinning_description_gestural" msgid="7246323931831232068">"固定を解除するまで常に表示されます。上にスワイプして長押しすると固定が解除されます。"</string>
<string name="screen_pinning_description_accessible" msgid="7386449191953535332">"固定を解除するまで画面が常に表示されるようになります。[最近] を押し続けると固定が解除されます。"</string>
<string name="screen_pinning_description_recents_invisible_accessible" msgid="2857071808674481986">"固定を解除するまで画面が常に表示されるようになります。[ホーム] を押し続けると固定が解除されます。"</string>
- <!-- no translation found for screen_pinning_exposes_personal_data (8189852022981524789) -->
- <skip />
- <!-- no translation found for screen_pinning_can_open_other_apps (7529756813231421455) -->
- <skip />
- <!-- no translation found for screen_pinning_toast (8177286912533744328) -->
- <skip />
- <!-- no translation found for screen_pinning_toast_recents_invisible (6850978077443052594) -->
- <skip />
- <!-- no translation found for screen_pinning_toast_gesture_nav (170699893395336705) -->
- <skip />
+ <string name="screen_pinning_exposes_personal_data" msgid="8189852022981524789">"個人データ(連絡先やメールの内容など)にアクセスできる可能性があります。"</string>
+ <string name="screen_pinning_can_open_other_apps" msgid="7529756813231421455">"固定したアプリが他のアプリを開く可能性があります。"</string>
+ <string name="screen_pinning_toast" msgid="8177286912533744328">"このアプリの固定を解除するには [戻る] ボタンと [最近] ボタンを長押しします"</string>
+ <string name="screen_pinning_toast_recents_invisible" msgid="6850978077443052594">"このアプリの固定を解除するには [戻る] ボタンと [ホーム] ボタンを長押しします"</string>
+ <string name="screen_pinning_toast_gesture_nav" msgid="170699893395336705">"このアプリの固定を解除するには、上にスワイプして長押しします"</string>
<string name="screen_pinning_positive" msgid="3285785989665266984">"はい"</string>
<string name="screen_pinning_negative" msgid="6882816864569211666">"いいえ"</string>
- <!-- no translation found for screen_pinning_start (7483998671383371313) -->
- <skip />
- <!-- no translation found for screen_pinning_exit (4553787518387346893) -->
- <skip />
+ <string name="screen_pinning_start" msgid="7483998671383371313">"固定したアプリ"</string>
+ <string name="screen_pinning_exit" msgid="4553787518387346893">"固定を解除したアプリ"</string>
<string name="quick_settings_reset_confirmation_title" msgid="463533331480997595">"<xliff:g id="TILE_LABEL">%1$s</xliff:g>を非表示にしますか?"</string>
<string name="quick_settings_reset_confirmation_message" msgid="2320586180785674186">"次回、設定でONにすると再表示されます。"</string>
<string name="quick_settings_reset_confirmation_button" msgid="3341477479055016776">"非表示"</string>
@@ -730,7 +719,7 @@
<string name="notification_channel_summary_priority" msgid="7952654515769021553">"会話セクションの一番上にふきだしとして表示され、プロフィール写真がロック画面に表示されます"</string>
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"設定"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"優先度"</string>
- <string name="no_shortcut" msgid="7176375126961212514">"<xliff:g id="APP_NAME">%1$s</xliff:g> は会話専用の設定をサポートしていません"</string>
+ <string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> は会話機能に対応していません"</string>
<string name="bubble_overflow_empty_title" msgid="3120029421991510842">"最近閉じたバブルはありません"</string>
<string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"最近表示されたバブルや閉じたバブルが、ここに表示されます"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"これらの通知は変更できません。"</string>
@@ -759,7 +748,7 @@
<string name="notification_conversation_unfavorite" msgid="181383708304763807">"重要でない会話"</string>
<string name="notification_conversation_mute" msgid="268951550222925548">"マナーモード"</string>
<string name="notification_conversation_unmute" msgid="2692255619510896710">"アラートを受け取る"</string>
- <string name="notification_conversation_bubble" msgid="2242180995373949022">"バブルを表示"</string>
+ <string name="notification_conversation_bubble" msgid="2242180995373949022">"バブルで表示"</string>
<string name="notification_conversation_unbubble" msgid="6908427185031099868">"バブルを削除"</string>
<string name="notification_conversation_home_screen" msgid="8347136037958438935">"ホーム画面に追加"</string>
<string name="notification_menu_accessibility" msgid="8984166825879886773">"<xliff:g id="APP_NAME">%1$s</xliff:g> <xliff:g id="MENU_DESCRIPTION">%2$s</xliff:g>"</string>
@@ -1013,9 +1002,10 @@
<string name="bubble_accessibility_action_move_top_right" msgid="6916868852433483569">"右上に移動"</string>
<string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"左下に移動"</string>
<string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"右下に移動"</string>
- <string name="bubble_dismiss_text" msgid="7071770411580452911">"閉じる"</string>
- <string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"会話をバブルにしない"</string>
- <string name="bubbles_user_education_title" msgid="5547017089271445797">"チャットでのバブルの使用"</string>
+ <!-- no translation found for bubble_dismiss_text (1314082410868930066) -->
+ <skip />
+ <string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"会話をバブルで表示しない"</string>
+ <string name="bubbles_user_education_title" msgid="5547017089271445797">"チャットでバブルを使う"</string>
<string name="bubbles_user_education_description" msgid="1160281719576715211">"新しい会話はフローティング アイコン(バブル)として表示されます。タップするとバブルが開きます。ドラッグしてバブルを移動できます。"</string>
<string name="bubbles_user_education_manage_title" msgid="2848511858160342320">"いつでもバブルを管理"</string>
<string name="bubbles_user_education_manage" msgid="1391639189507036423">"このアプリからのバブルをオフにするには、[管理] をタップしてください"</string>
@@ -1024,11 +1014,14 @@
<string name="notification_content_system_nav_changed" msgid="5077913144844684544">"システム ナビゲーションを更新しました。変更するには [設定] に移動してください。"</string>
<string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"システム ナビゲーションを更新するには [設定] に移動してください"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"スタンバイ"</string>
- <string name="priority_onboarding_show_at_top_text" msgid="1678400241025513541">"会話セクションの一番上にバブル表示"</string>
+ <string name="priority_onboarding_title" msgid="2893070698479227616">"優先度を高く設定された会話"</string>
+ <string name="priority_onboarding_behavior" msgid="5342816047020432929">"優先度の高い会話では、次のようになります。"</string>
+ <string name="priority_onboarding_show_at_top_text" msgid="1678400241025513541">"会話セクションの一番上にバブルで表示"</string>
<string name="priority_onboarding_show_avatar_text" msgid="5756291381124091508">"ロック画面にプロフィール写真を表示"</string>
<string name="priority_onboarding_appear_as_bubble_text" msgid="4227039772250263122">"他のアプリに重ねてフローティング バブルとして表示"</string>
<string name="priority_onboarding_ignores_dnd_text" msgid="2918952762719600529">"サイレント モードに割り込み"</string>
<string name="priority_onboarding_done_button_title" msgid="4569550984286506007">"OK"</string>
+ <string name="priority_onboarding_settings_button_title" msgid="6663601574303585927">"設定"</string>
<string name="magnification_overlay_title" msgid="6584179429612427958">"拡大オーバーレイ ウィンドウ"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"拡大ウィンドウ"</string>
<string name="magnification_controls_title" msgid="8421106606708891519">"拡大ウィンドウ コントロール"</string>
@@ -1070,9 +1063,13 @@
<string name="controls_structure_tooltip" msgid="4355922222944447867">"スワイプすると他の構造が表示されます"</string>
<string name="controls_seeding_in_progress" msgid="3033855341410264148">"候補を読み込んでいます"</string>
<string name="controls_media_close_session" msgid="9023534788828414585">"このメディア セッションを閉じる"</string>
+ <string name="controls_media_resume" msgid="1933520684481586053">"再開"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"無効: アプリをご確認ください"</string>
<string name="controls_error_retryable" msgid="864025882878378470">"エラー。再試行しています…"</string>
- <string name="controls_error_removed" msgid="6299213591234723805">"デバイスを削除しました"</string>
+ <string name="controls_error_removed" msgid="6675638069846014366">"見つかりませんでした"</string>
+ <string name="controls_error_removed_title" msgid="1207794911208047818">"コントロールを使用できません"</string>
+ <string name="controls_error_removed_message" msgid="2885911717034750542">"「<xliff:g id="DEVICE">%1$s</xliff:g>」にアクセスできませんでした<xliff:g id="APPLICATION">%2$s</xliff:g> アプリで、コントロールが使用可能な状態でアプリの設定が変更されていないことをご確認ください。"</string>
+ <string name="controls_open_app" msgid="483650971094300141">"アプリを開く"</string>
<string name="controls_error_generic" msgid="352500456918362905">"ステータスを読み込めません"</string>
<string name="controls_error_failed" msgid="960228639198558525">"エラー: もう一度お試しください"</string>
<string name="controls_in_progress" msgid="4421080500238215939">"処理中"</string>
diff --git a/packages/SystemUI/res/values-ka/strings.xml b/packages/SystemUI/res/values-ka/strings.xml
index 4def42554e11..37b5ec98797e 100644
--- a/packages/SystemUI/res/values-ka/strings.xml
+++ b/packages/SystemUI/res/values-ka/strings.xml
@@ -77,9 +77,6 @@
<string name="compat_mode_on" msgid="4963711187149440884">"მასშტაბი შეცვალეთ ეკრანის შესავსებად."</string>
<string name="compat_mode_off" msgid="7682459748279487945">"გაწიეთ ეკრანის შესავსებად."</string>
<string name="global_action_screenshot" msgid="2760267567509131654">"ეკრანის ანაბეჭდი"</string>
- <string name="global_action_lock_message" product="default" msgid="4466026255205186456">"მეტი ვარიანტის სანახავად განბლოკეთ თქვენი ტელეფონი"</string>
- <string name="global_action_lock_message" product="tablet" msgid="7621167597240332986">"მეტი ვარიანტის სანახავად განბლოკეთ თქვენი ტაბლეტი"</string>
- <string name="global_action_lock_message" product="device" msgid="538790401275363781">"მეტი ვარიანტის სანახავად განბლოკეთ თქვენი მოწყობილობა"</string>
<string name="remote_input_image_insertion_text" msgid="4850791636452521123">"გაიგზავნა სურათი"</string>
<string name="screenshot_saving_ticker" msgid="6519186952674544916">"სკრინშოტის შენახვა…"</string>
<string name="screenshot_saving_title" msgid="2298349784913287333">"ეკრანის სურათის შენახვა…"</string>
@@ -595,29 +592,21 @@
<string name="volume_odi_captions_hint_enable" msgid="2073091194012843195">"ჩართვა"</string>
<string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"გამორთვა"</string>
<string name="accessibility_output_chooser" msgid="7807898688967194183">"გამოტანის მოწყობილობის გადართვა"</string>
- <!-- no translation found for screen_pinning_title (9058007390337841305) -->
- <skip />
+ <string name="screen_pinning_title" msgid="9058007390337841305">"აპი ჩამაგრებულია"</string>
<string name="screen_pinning_description" msgid="8699395373875667743">"ამით ის დარჩება ხედში ჩამაგრების მოხსნამდე. ჩამაგრების მოსახსნელად, ხანგრძლივად შეეხეთ „უკან და მიმოხილვა“-ს."</string>
<string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"ამით ის დარჩება ხედში ჩამაგრების მოხსნამდე. ჩამაგრების მოსახსნელად, ხანგრძლივად შეეხეთ „უკან მთავარ გვერდზე“-ს."</string>
<string name="screen_pinning_description_gestural" msgid="7246323931831232068">"ამით ის დარჩება ხედში ჩამაგრების მოხსნამდე. აუსვით ზემოთ და დააყოვნეთ ჩამაგრების მოსახსნელად."</string>
<string name="screen_pinning_description_accessible" msgid="7386449191953535332">"ამით ის დარჩება ხედში ჩამაგრების მოხსნამდე. ჩამაგრების მოსახსნელად, ხანგრძლივად შეეხეთ „მიმოხილვა“-ს."</string>
<string name="screen_pinning_description_recents_invisible_accessible" msgid="2857071808674481986">"ამით ის დარჩება ხედში ჩამაგრების მოხსნამდე. ჩამაგრების მოსახსნელად, ხანგრძლივად შეეხეთ „მთავარ გვერდს“."</string>
- <!-- no translation found for screen_pinning_exposes_personal_data (8189852022981524789) -->
- <skip />
- <!-- no translation found for screen_pinning_can_open_other_apps (7529756813231421455) -->
- <skip />
- <!-- no translation found for screen_pinning_toast (8177286912533744328) -->
- <skip />
- <!-- no translation found for screen_pinning_toast_recents_invisible (6850978077443052594) -->
- <skip />
- <!-- no translation found for screen_pinning_toast_gesture_nav (170699893395336705) -->
- <skip />
+ <string name="screen_pinning_exposes_personal_data" msgid="8189852022981524789">"შეიძლება მისაწვდომი გახდეს პერსონალური მონაცემები (მაგალითად, კონტაქტები და ელფოსტის კონტენტი)."</string>
+ <string name="screen_pinning_can_open_other_apps" msgid="7529756813231421455">"ჩამაგრებულმა აპმა შეიძლება სხვა აპები გახსნას."</string>
+ <string name="screen_pinning_toast" msgid="8177286912533744328">"ამ აპის ჩამაგრების მოსახსნელად, ხანგრძლივად შეეხეთ ღილაკებს „უკან“ და „მიმოხილვა“"</string>
+ <string name="screen_pinning_toast_recents_invisible" msgid="6850978077443052594">"ამ აპის ჩამაგრების მოსახსნელად, ხანგრძლივად შეეხეთ ღილაკებს „უკან“ და „მთავარი გვერდი“"</string>
+ <string name="screen_pinning_toast_gesture_nav" msgid="170699893395336705">"ამ აპის ჩამაგრების მოსახსნელად გადაფურცლეთ ზემოთ და არ აუშვათ"</string>
<string name="screen_pinning_positive" msgid="3285785989665266984">"გასაგებია"</string>
<string name="screen_pinning_negative" msgid="6882816864569211666">"არა, გმადლობთ"</string>
- <!-- no translation found for screen_pinning_start (7483998671383371313) -->
- <skip />
- <!-- no translation found for screen_pinning_exit (4553787518387346893) -->
- <skip />
+ <string name="screen_pinning_start" msgid="7483998671383371313">"აპი ჩამაგრდა"</string>
+ <string name="screen_pinning_exit" msgid="4553787518387346893">"აპის ჩამაგრება გაუქმდა"</string>
<string name="quick_settings_reset_confirmation_title" msgid="463533331480997595">"დაიმალოს <xliff:g id="TILE_LABEL">%1$s</xliff:g>?"</string>
<string name="quick_settings_reset_confirmation_message" msgid="2320586180785674186">"ის კვლავ გამოჩნდება, როდესაც პარამეტრებში ჩართავთ"</string>
<string name="quick_settings_reset_confirmation_button" msgid="3341477479055016776">"დამალვა"</string>
@@ -730,7 +719,7 @@
<string name="notification_channel_summary_priority" msgid="7952654515769021553">"გამოჩნდება მიმოწერების სექციის ზედა ნაწილში მოლივლივე ბუშტის სახით, აჩვენებს პროფილის სურათს ჩაკეტილ ეკრანზე"</string>
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"პარამეტრები"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"პრიორიტეტი"</string>
- <string name="no_shortcut" msgid="7176375126961212514">"<xliff:g id="APP_NAME">%1$s</xliff:g>-ს არ აქვს სპეციალურად მიმოწერისთვის განკუთვნილი პარამეტრების მხარდაჭერა"</string>
+ <string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g>-ს არ აქვს მიმოწერის ფუნქციების მხარდაჭერა"</string>
<string name="bubble_overflow_empty_title" msgid="3120029421991510842">"ბოლო დროს გამოყენებული ბუშტები არ არის"</string>
<string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"აქ გამოჩნდება ბოლოდროინდელი ბუშტები და უარყოფილი ბუშტები"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"ამ შეტყობინებების შეცვლა შეუძლებელია."</string>
@@ -1013,7 +1002,8 @@
<string name="bubble_accessibility_action_move_top_right" msgid="6916868852433483569">"გადაანაცვლეთ ზევით და მარჯვნივ"</string>
<string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"ქვევით და მარცხნივ გადატანა"</string>
<string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"გადაანაცვ. ქვემოთ და მარჯვნივ"</string>
- <string name="bubble_dismiss_text" msgid="7071770411580452911">"დახურვა"</string>
+ <!-- no translation found for bubble_dismiss_text (1314082410868930066) -->
+ <skip />
<string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"აიკრძალოს საუბრის ბუშტები"</string>
<string name="bubbles_user_education_title" msgid="5547017089271445797">"ჩეთი ბუშტების გამოყენებით"</string>
<string name="bubbles_user_education_description" msgid="1160281719576715211">"ახალი საუბრები გამოჩნდება როგორც მოტივტივე ხატულები ან ბუშტები. შეეხეთ ბუშტის გასახსნელად. გადაიტანეთ ჩავლებით."</string>
@@ -1024,11 +1014,14 @@
<string name="notification_content_system_nav_changed" msgid="5077913144844684544">"სისტემური ნავიგაცია განახლდა. ცვლილებების შესატანად გადადით პარამეტრებზე."</string>
<string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"სისტემური ნავიგაციის გასაახლებლად გადადით პარამეტრებზე"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"მოლოდინის რეჟიმი"</string>
+ <string name="priority_onboarding_title" msgid="2893070698479227616">"მიმოწერა დაყენებულია პრიორიტეტად"</string>
+ <string name="priority_onboarding_behavior" msgid="5342816047020432929">"პრიორიტეტული მიმოწერები:"</string>
<string name="priority_onboarding_show_at_top_text" msgid="1678400241025513541">"მიმოწერის სექციის ზემოთ ჩვენება"</string>
<string name="priority_onboarding_show_avatar_text" msgid="5756291381124091508">"ჩაკეტილ ეკრანზე პროფილის სურათის ჩვენება"</string>
<string name="priority_onboarding_appear_as_bubble_text" msgid="4227039772250263122">"გამოჩნდება მოლივლივე ბუშტის სახით აპების ზემოდან"</string>
<string name="priority_onboarding_ignores_dnd_text" msgid="2918952762719600529">"„არ შემაწუხოთ“ რეჟიმის შეწყვეტა"</string>
<string name="priority_onboarding_done_button_title" msgid="4569550984286506007">"გასაგებია"</string>
+ <string name="priority_onboarding_settings_button_title" msgid="6663601574303585927">"პარამეტრები"</string>
<string name="magnification_overlay_title" msgid="6584179429612427958">"გადიდების გადაფარვის ფანჯარა"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"გადიდების ფანჯარა"</string>
<string name="magnification_controls_title" msgid="8421106606708891519">"გადიდების კონტროლის ფანჯარა"</string>
@@ -1070,9 +1063,13 @@
<string name="controls_structure_tooltip" msgid="4355922222944447867">"გადაფურცლეთ მეტის სანახავად"</string>
<string name="controls_seeding_in_progress" msgid="3033855341410264148">"მიმდინარეობს რეკომენდაციების ჩატვირთვა"</string>
<string name="controls_media_close_session" msgid="9023534788828414585">"ამ მედია სესიის დახურვა"</string>
+ <string name="controls_media_resume" msgid="1933520684481586053">"გაგრძელება"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"არააქტიურია, გადაამოწმეთ აპი"</string>
<string name="controls_error_retryable" msgid="864025882878378470">"შეცდომა, ხელახალი მცდელობა…"</string>
- <string name="controls_error_removed" msgid="6299213591234723805">"მოწყობილობა ამოიშალა"</string>
+ <string name="controls_error_removed" msgid="6675638069846014366">"ვერ მოიძებნა"</string>
+ <string name="controls_error_removed_title" msgid="1207794911208047818">"კონტროლი მიუწვდომელია"</string>
+ <string name="controls_error_removed_message" msgid="2885911717034750542">"<xliff:g id="DEVICE">%1$s</xliff:g>-ზე წვდომა ვერ მოხერხდა. შეამოწმეთ <xliff:g id="APPLICATION">%2$s</xliff:g> აპი, რათა დარწმუნდეთ, რომ კონტროლი კვლავაც ხელმისაწვდომია და რომ აპის პარამეტრები არ შეცვლილა."</string>
+ <string name="controls_open_app" msgid="483650971094300141">"აპის გახსნა"</string>
<string name="controls_error_generic" msgid="352500456918362905">"სტატუსი ვერ იტვირთება"</string>
<string name="controls_error_failed" msgid="960228639198558525">"შეცდომა, ისევ ცადეთ"</string>
<string name="controls_in_progress" msgid="4421080500238215939">"მუშავდება"</string>
diff --git a/packages/SystemUI/res/values-kk/strings.xml b/packages/SystemUI/res/values-kk/strings.xml
index b7b1ac49b467..73f0e6c7af7d 100644
--- a/packages/SystemUI/res/values-kk/strings.xml
+++ b/packages/SystemUI/res/values-kk/strings.xml
@@ -77,9 +77,6 @@
<string name="compat_mode_on" msgid="4963711187149440884">"Экранды толтыру үшін ұлғайту"</string>
<string name="compat_mode_off" msgid="7682459748279487945">"Экранды толтыру үшін созу"</string>
<string name="global_action_screenshot" msgid="2760267567509131654">"Скриншот"</string>
- <string name="global_action_lock_message" product="default" msgid="4466026255205186456">"Басқа опцияларды көру үшін телефон құлпын ашыңыз."</string>
- <string name="global_action_lock_message" product="tablet" msgid="7621167597240332986">"Басқа опцияларды көру үшін планшет құлпын ашыңыз."</string>
- <string name="global_action_lock_message" product="device" msgid="538790401275363781">"Басқа опцияларды көру үшін құрылғы құлпын ашыңыз."</string>
<string name="remote_input_image_insertion_text" msgid="4850791636452521123">"сурет жіберілді"</string>
<string name="screenshot_saving_ticker" msgid="6519186952674544916">"Скриншотты сақтауда…"</string>
<string name="screenshot_saving_title" msgid="2298349784913287333">"Скриншотты сақтауда…"</string>
@@ -277,7 +274,7 @@
<string name="accessibility_quick_settings_airplane_changed_off" msgid="8880183481476943754">"Ұшақ режимі өшірілді."</string>
<string name="accessibility_quick_settings_airplane_changed_on" msgid="6327378061894076288">"Ұшақ режимі қосылды."</string>
<string name="accessibility_quick_settings_dnd_none_on" msgid="3235552940146035383">"үнсіз"</string>
- <string name="accessibility_quick_settings_dnd_alarms_on" msgid="3375848309132140014">"тек дабылдар"</string>
+ <string name="accessibility_quick_settings_dnd_alarms_on" msgid="3375848309132140014">"оятқыштар ғана"</string>
<string name="accessibility_quick_settings_dnd" msgid="2415967452264206047">"Мазаламау."</string>
<string name="accessibility_quick_settings_dnd_changed_off" msgid="1457150026842505799">"\"Мазаламау\" режимі өшірілді."</string>
<string name="accessibility_quick_settings_dnd_changed_on" msgid="186315911607486129">"\"Мазаламау\" режимі қосылды."</string>
@@ -347,7 +344,7 @@
<string name="quick_settings_header_onboarding_text" msgid="1918085351115504765">"Басқа опцияларды көру үшін белгішелерді түртіп ұстап тұрыңыз"</string>
<string name="quick_settings_dnd_label" msgid="7728690179108024338">"Мазаламау"</string>
<string name="quick_settings_dnd_priority_label" msgid="6251076422352664571">"Маңыздылары ғана"</string>
- <string name="quick_settings_dnd_alarms_label" msgid="1241780970469630835">"Тек дабылдар"</string>
+ <string name="quick_settings_dnd_alarms_label" msgid="1241780970469630835">"Оятқыштар ғана"</string>
<string name="quick_settings_dnd_none_label" msgid="8420869988472836354">"Толық тыныштық"</string>
<string name="quick_settings_bluetooth_label" msgid="7018763367142041481">"Bluetooth"</string>
<string name="quick_settings_bluetooth_multiple_devices_label" msgid="6595808498429809855">"Bluetooth (<xliff:g id="NUMBER">%d</xliff:g> құрылғылары)"</string>
@@ -465,7 +462,7 @@
<string name="interruption_level_none_with_warning" msgid="8394434073508145437">"Толық тыныштық. Экранды оқу құралдары да өшеді."</string>
<string name="interruption_level_none" msgid="219484038314193379">"Толық тыныштық"</string>
<string name="interruption_level_priority" msgid="661294280016622209">"Маңыздылары ғана"</string>
- <string name="interruption_level_alarms" msgid="2457850481335846959">"Тек дабылдар"</string>
+ <string name="interruption_level_alarms" msgid="2457850481335846959">"Оятқыштар ғана"</string>
<string name="interruption_level_none_twoline" msgid="8579382742855486372">"Толық\nтыныштық"</string>
<string name="interruption_level_priority_twoline" msgid="8523482736582498083">"Тек\nбасымдық"</string>
<string name="interruption_level_alarms_twoline" msgid="2045067991335708767">"Тек\nдабылдар"</string>
@@ -595,29 +592,21 @@
<string name="volume_odi_captions_hint_enable" msgid="2073091194012843195">"қосу"</string>
<string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"өшіру"</string>
<string name="accessibility_output_chooser" msgid="7807898688967194183">"Шығыс құрылғыны ауыстыру"</string>
- <!-- no translation found for screen_pinning_title (9058007390337841305) -->
- <skip />
+ <string name="screen_pinning_title" msgid="9058007390337841305">"Қолданба бекітілді"</string>
<string name="screen_pinning_description" msgid="8699395373875667743">"Экран босатылғанға дейін көрсетіліп тұрады. Оны босату үшін \"Артқа\" және \"Шолу\" түймелерін басып тұрыңыз."</string>
<string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"Экран босатылғанға дейін көрсетіліп тұрады. Оны босату үшін \"Артқа\" және \"Негізгі бет\" түймелерін түртіп, ұстап тұрыңыз"</string>
<string name="screen_pinning_description_gestural" msgid="7246323931831232068">"Экран босатылғанға дейін көрсетіліп тұрады. Экранды босату үшін жоғары сырғытып, ұстап тұрыңыз."</string>
<string name="screen_pinning_description_accessible" msgid="7386449191953535332">"Экран босатылғанға дейін көрсетіліп тұрады. Оны босату үшін \"Кері\" түймесін басып тұрыңыз."</string>
<string name="screen_pinning_description_recents_invisible_accessible" msgid="2857071808674481986">"Экран босатылғанға дейін көрсетіліп тұрады. Оны босату үшін \"Негізгі бет\" түймесін түртіп, ұстап тұрыңыз."</string>
- <!-- no translation found for screen_pinning_exposes_personal_data (8189852022981524789) -->
- <skip />
- <!-- no translation found for screen_pinning_can_open_other_apps (7529756813231421455) -->
- <skip />
- <!-- no translation found for screen_pinning_toast (8177286912533744328) -->
- <skip />
- <!-- no translation found for screen_pinning_toast_recents_invisible (6850978077443052594) -->
- <skip />
- <!-- no translation found for screen_pinning_toast_gesture_nav (170699893395336705) -->
- <skip />
+ <string name="screen_pinning_exposes_personal_data" msgid="8189852022981524789">"Жеке деректер (мысалы, байланыс ақпараты және электрондық пошта мазмұны) ашық болуы мүмкін."</string>
+ <string name="screen_pinning_can_open_other_apps" msgid="7529756813231421455">"Бекітілген қолданба басқа қолданбаларды ашуы мүмкін."</string>
+ <string name="screen_pinning_toast" msgid="8177286912533744328">"Бұл қолданбаны босату үшін \"Артқа\" және \"Шолу\" түймелерін түртіп, ұстап тұрыңыз."</string>
+ <string name="screen_pinning_toast_recents_invisible" msgid="6850978077443052594">"Бұл қолданбаны босату үшін \"Артқа\" және \"Негізгі бет\" түймелерін түртіп, ұстап тұрыңыз."</string>
+ <string name="screen_pinning_toast_gesture_nav" msgid="170699893395336705">"Бұл қолданбаны босату үшін жоғары сырғытып, ұстап тұрыңыз."</string>
<string name="screen_pinning_positive" msgid="3285785989665266984">"Түсінікті"</string>
<string name="screen_pinning_negative" msgid="6882816864569211666">"Жоқ, рақмет"</string>
- <!-- no translation found for screen_pinning_start (7483998671383371313) -->
- <skip />
- <!-- no translation found for screen_pinning_exit (4553787518387346893) -->
- <skip />
+ <string name="screen_pinning_start" msgid="7483998671383371313">"Қолданба бекітілді."</string>
+ <string name="screen_pinning_exit" msgid="4553787518387346893">"Қолданба босатылды."</string>
<string name="quick_settings_reset_confirmation_title" msgid="463533331480997595">"<xliff:g id="TILE_LABEL">%1$s</xliff:g> жасыру керек пе?"</string>
<string name="quick_settings_reset_confirmation_message" msgid="2320586180785674186">"Ол сіз оны параметрлерде келесі қосқанда қайта пайда болады."</string>
<string name="quick_settings_reset_confirmation_button" msgid="3341477479055016776">"Жасыру"</string>
@@ -730,9 +719,9 @@
<string name="notification_channel_summary_priority" msgid="7952654515769021553">"Әңгімелер бөлімінің жоғарғы жағында тұрады, қалқыма хабар түрінде шығады, құлыптаулы экранда профиль суретін көрсетеді"</string>
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"Параметрлер"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"Маңыздылығы"</string>
- <string name="no_shortcut" msgid="7176375126961212514">"<xliff:g id="APP_NAME">%1$s</xliff:g> қолданбасында чаттың арнайы параметрлеріне қолдау көрсетілмейді."</string>
+ <string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> әңгімелесу функцияларын қолдамайды."</string>
<string name="bubble_overflow_empty_title" msgid="3120029421991510842">"Жақындағы қалқыма хабарлар жоқ"</string>
- <string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"Жақында ашылған және жабылған қалқыма хабарлар осы жерде көрсетіледі."</string>
+ <string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"Соңғы және жабылған қалқыма хабарлар осы жерде көрсетіледі."</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"Бұл хабарландыруларды өзгерту мүмкін емес."</string>
<string name="notification_multichannel_desc" msgid="7414593090056236179">"Мұндай хабарландырулар бұл жерде конфигурацияланбайды."</string>
<string name="notification_delegate_header" msgid="1264510071031479920">"Прокси-сервер арқылы жіберілген хабарландыру"</string>
@@ -1013,9 +1002,10 @@
<string name="bubble_accessibility_action_move_top_right" msgid="6916868852433483569">"Жоғары оң жаққа жылжыту"</string>
<string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"Төменгі сол жаққа жылжыту"</string>
<string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"Төменгі оң жаққа жылжыту"</string>
- <string name="bubble_dismiss_text" msgid="7071770411580452911">"Жабу"</string>
+ <!-- no translation found for bubble_dismiss_text (1314082410868930066) -->
+ <skip />
<string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"Әңгіменің қалқыма хабары көрсетілмесін"</string>
- <string name="bubbles_user_education_title" msgid="5547017089271445797">"Сөйлесуге арналған қалқыма хабарлар"</string>
+ <string name="bubbles_user_education_title" msgid="5547017089271445797">"Қалқыма хабарлар арқылы сөйлесу"</string>
<string name="bubbles_user_education_description" msgid="1160281719576715211">"Жаңа әңгімелер қалқыма белгішелер немесе хабарлар түрінде көрсетіледі. Қалқыма хабарды ашу үшін түртіңіз. Жылжыту үшін сүйреңіз."</string>
<string name="bubbles_user_education_manage_title" msgid="2848511858160342320">"Қалқыма хабарларды реттеу"</string>
<string name="bubbles_user_education_manage" msgid="1391639189507036423">"Бұл қолданбадан қалқыма хабарларды өшіру үшін \"Басқару\" түймесін түртіңіз."</string>
@@ -1024,11 +1014,14 @@
<string name="notification_content_system_nav_changed" msgid="5077913144844684544">"Жүйе навигациясы жаңартылды. Өзгерту енгізу үшін \"Параметрлер\" бөліміне өтіңіз."</string>
<string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"Жүйе навигациясын жаңарту үшін \"Параметрлер\" бөліміне өтіңіз."</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Күту режимі"</string>
+ <string name="priority_onboarding_title" msgid="2893070698479227616">"Әңгіме маңызды деп белгіленді"</string>
+ <string name="priority_onboarding_behavior" msgid="5342816047020432929">"Маңызды әңгімелердің әрекеті:"</string>
<string name="priority_onboarding_show_at_top_text" msgid="1678400241025513541">"Сөйлесу бөлімінің жоғарғы жағында көрсетіледі."</string>
<string name="priority_onboarding_show_avatar_text" msgid="5756291381124091508">"Профиль суреті құлыптаулы экранда көрсетіледі."</string>
<string name="priority_onboarding_appear_as_bubble_text" msgid="4227039772250263122">"Қолданбалар терезесінің бергі жағынан қалқыма хабарлар түрінде көрсетіледі."</string>
<string name="priority_onboarding_ignores_dnd_text" msgid="2918952762719600529">"\"Мазаламау\" режимінде көрсетіледі."</string>
<string name="priority_onboarding_done_button_title" msgid="4569550984286506007">"Түсінікті"</string>
+ <string name="priority_onboarding_settings_button_title" msgid="6663601574303585927">"Параметрлер"</string>
<string name="magnification_overlay_title" msgid="6584179429612427958">"Ұлғайту терезесін қабаттастыру"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"Ұлғайту терезесі"</string>
<string name="magnification_controls_title" msgid="8421106606708891519">"Ұлғайту терезесінің басқару элементтері"</string>
@@ -1070,9 +1063,13 @@
<string name="controls_structure_tooltip" msgid="4355922222944447867">"Толығырақ ақпарат алу үшін сырғытыңыз."</string>
<string name="controls_seeding_in_progress" msgid="3033855341410264148">"Жүктеуге қатысты ұсыныстар"</string>
<string name="controls_media_close_session" msgid="9023534788828414585">"Мультимедиа сеансын жабу"</string>
+ <string name="controls_media_resume" msgid="1933520684481586053">"Жалғастыру"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"Өшірулі. Қолданба тексеріңіз."</string>
<string name="controls_error_retryable" msgid="864025882878378470">"Қате, әрекет қайталануда…"</string>
- <string name="controls_error_removed" msgid="6299213591234723805">"Құрылғы өшірілді."</string>
+ <string name="controls_error_removed" msgid="6675638069846014366">"Табылмады"</string>
+ <string name="controls_error_removed_title" msgid="1207794911208047818">"Басқару элементтері қолжетімді емес"</string>
+ <string name="controls_error_removed_message" msgid="2885911717034750542">"<xliff:g id="DEVICE">%1$s</xliff:g> ашылмады. Басқару элементтерінің әлі қолжетімді екенін және қолданба параметрлерінің өзгермегенін тексеру үшін <xliff:g id="APPLICATION">%2$s</xliff:g> қолданбасын қараңыз."</string>
+ <string name="controls_open_app" msgid="483650971094300141">"Қолданбаны ашу"</string>
<string name="controls_error_generic" msgid="352500456918362905">"Күйді жүктеу мүмкін емес."</string>
<string name="controls_error_failed" msgid="960228639198558525">"Қате шықты. Қайталап көріңіз."</string>
<string name="controls_in_progress" msgid="4421080500238215939">"Орындалуда"</string>
diff --git a/packages/SystemUI/res/values-km/strings.xml b/packages/SystemUI/res/values-km/strings.xml
index 15a022b4103b..47fd544912ea 100644
--- a/packages/SystemUI/res/values-km/strings.xml
+++ b/packages/SystemUI/res/values-km/strings.xml
@@ -77,9 +77,6 @@
<string name="compat_mode_on" msgid="4963711187149440884">"ពង្រីក​​ដើម្បី​ឲ្យ​ពេញ​អេក្រង់"</string>
<string name="compat_mode_off" msgid="7682459748279487945">"ទាញ​ដើម្បី​ឲ្យ​ពេញ​អេក្រង់"</string>
<string name="global_action_screenshot" msgid="2760267567509131654">"រូបថតអេក្រង់"</string>
- <string name="global_action_lock_message" product="default" msgid="4466026255205186456">"ដោះសោ​ទូរសព្ទរបស់អ្នក​សម្រាប់​ជម្រើសច្រើនទៀត"</string>
- <string name="global_action_lock_message" product="tablet" msgid="7621167597240332986">"ដោះសោ​ថេប្លេតរបស់អ្នក​សម្រាប់​ជម្រើសច្រើនទៀត"</string>
- <string name="global_action_lock_message" product="device" msgid="538790401275363781">"ដោះសោ​ឧបករណ៍របស់អ្នក​សម្រាប់​ជម្រើសច្រើនទៀត"</string>
<string name="remote_input_image_insertion_text" msgid="4850791636452521123">"បាន​ផ្ញើរូបភាព"</string>
<string name="screenshot_saving_ticker" msgid="6519186952674544916">"កំពុង​រក្សាទុក​រូបថត​អេក្រង់…"</string>
<string name="screenshot_saving_title" msgid="2298349784913287333">"កំពុង​រក្សាទុក​រូបថត​អេក្រង់..."</string>
@@ -595,29 +592,21 @@
<string name="volume_odi_captions_hint_enable" msgid="2073091194012843195">"បើក"</string>
<string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"បិទ"</string>
<string name="accessibility_output_chooser" msgid="7807898688967194183">"ប្ដូរ​ឧបករណ៍​បញ្ចេញ​សំឡេង"</string>
- <!-- no translation found for screen_pinning_title (9058007390337841305) -->
- <skip />
+ <string name="screen_pinning_title" msgid="9058007390337841305">"កម្មវិធី​ត្រូវបានខ្ទាស់"</string>
<string name="screen_pinning_description" msgid="8699395373875667743">"វា​នឹង​នៅតែ​បង្ហាញ រហូត​ទាល់​តែ​អ្នក​ដក​ការដៅ។ សូម​សង្កត់​ប៊ូតុង​ថយ​ក្រោយ និង​ប៊ូតុង​ទិដ្ឋភាពរួម​ឲ្យ​ជាប់ ដើម្បី​ដក​ការ​ដៅ។"</string>
<string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"វា​នឹង​នៅតែ​បង្ហាញ រហូត​ទាល់​តែ​អ្នក​ដក​ការដៅ។ សូម​ចុចប៊ូតុង​ថយក្រោយ និងប៊ូតុង​ទំព័រដើម​ឱ្យ​ជាប់ ដើម្បី​ដក​ការ​ដៅ។"</string>
<string name="screen_pinning_description_gestural" msgid="7246323931831232068">"វា​នឹង​នៅតែ​បង្ហាញ រហូតទាល់​តែអ្នក​ដកការដៅ។ អូសឡើងលើ​ឱ្យជាប់ ដើម្បី​ដក​ការដៅ។"</string>
<string name="screen_pinning_description_accessible" msgid="7386449191953535332">"វា​នឹង​នៅតែ​បង្ហាញ រហូត​ទាល់​តែ​អ្នក​ដក​ការ​ដៅ។ សូម​សង្កត់​ប៊ូតុង​ទិដ្ឋភាពរួម​​ឲ្យ​ជាប់ ដើម្បី​ដក​ការ​ដៅ។"</string>
<string name="screen_pinning_description_recents_invisible_accessible" msgid="2857071808674481986">"វា​នឹង​នៅតែ​បង្ហាញ រហូត​ទាល់​តែ​អ្នក​ដក​ការដៅ។ សូម​ចុច​ប៊ូតុង​ទំព័រដើម​ឱ្យ​ជាប់ ដើម្បី​ដក​ការ​ដៅ។"</string>
- <!-- no translation found for screen_pinning_exposes_personal_data (8189852022981524789) -->
- <skip />
- <!-- no translation found for screen_pinning_can_open_other_apps (7529756813231421455) -->
- <skip />
- <!-- no translation found for screen_pinning_toast (8177286912533744328) -->
- <skip />
- <!-- no translation found for screen_pinning_toast_recents_invisible (6850978077443052594) -->
- <skip />
- <!-- no translation found for screen_pinning_toast_gesture_nav (170699893395336705) -->
- <skip />
+ <string name="screen_pinning_exposes_personal_data" msgid="8189852022981524789">"អាចចូលប្រើ​ទិន្នន័យផ្ទាល់ខ្លួន​បាន (ដូចជា ទំនាក់ទំនង និងខ្លឹមសារ​អ៊ីមែលជាដើម)។"</string>
+ <string name="screen_pinning_can_open_other_apps" msgid="7529756813231421455">"កម្មវិធីដែលបានខ្ទាស់​អាចបើកកម្មវិធី​ផ្សេងទៀតបាន។"</string>
+ <string name="screen_pinning_toast" msgid="8177286912533744328">"ដើម្បីដកខ្ទាស់​កម្មវិធីនេះ សូមចុច​ប៊ូតុង​ថយក្រោយ និងប៊ូតុង​ទិដ្ឋភាពរួម​ឱ្យជាប់"</string>
+ <string name="screen_pinning_toast_recents_invisible" msgid="6850978077443052594">"ដើម្បី​ដកខ្ទាស់​កម្មវិធីនេះ សូម​ចុចប៊ូតុង​ថយក្រោយ និង​ប៊ូតុងទំព័រដើម​ឱ្យជាប់"</string>
+ <string name="screen_pinning_toast_gesture_nav" msgid="170699893395336705">"ដើម្បីដកខ្ទាស់កម្មវិធី​នេះ សូមអូសឡើងលើ​ឱ្យជាប់"</string>
<string name="screen_pinning_positive" msgid="3285785989665266984">"យល់​ហើយ"</string>
<string name="screen_pinning_negative" msgid="6882816864569211666">"ទេ អរគុណ"</string>
- <!-- no translation found for screen_pinning_start (7483998671383371313) -->
- <skip />
- <!-- no translation found for screen_pinning_exit (4553787518387346893) -->
- <skip />
+ <string name="screen_pinning_start" msgid="7483998671383371313">"បានខ្ទាស់​កម្មវិធី"</string>
+ <string name="screen_pinning_exit" msgid="4553787518387346893">"បានដកខ្ទាស់​កម្មវិធី"</string>
<string name="quick_settings_reset_confirmation_title" msgid="463533331480997595">"លាក់ <xliff:g id="TILE_LABEL">%1$s</xliff:g>?"</string>
<string name="quick_settings_reset_confirmation_message" msgid="2320586180785674186">"វា​នឹង​បង្ហាញ​ពេល​ក្រោយ​ ពេល​ដែល​អ្នក​បើក​ក្នុង​ការ​កំណត់។"</string>
<string name="quick_settings_reset_confirmation_button" msgid="3341477479055016776">"លាក់"</string>
@@ -730,7 +719,7 @@
<string name="notification_channel_summary_priority" msgid="7952654515769021553">"បង្ហាញនៅខាងលើ​ផ្នែកសន្ទនា បង្ហាញជា​ពពុះអណ្ដែត បង្ហាញ​រូបភាព​កម្រងព័ត៌មាន​នៅលើ​អេក្រង់ចាក់សោ"</string>
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"ការកំណត់"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"អាទិភាព"</string>
- <string name="no_shortcut" msgid="7176375126961212514">"<xliff:g id="APP_NAME">%1$s</xliff:g> មិនអាចប្រើ​ការកំណត់​ជាក់លាក់ចំពោះការសន្ទនា​បានទេ"</string>
+ <string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> មិនអាចប្រើ​មុខងារ​សន្ទនា​បានទេ"</string>
<string name="bubble_overflow_empty_title" msgid="3120029421991510842">"មិនមាន​ពពុះ​ថ្មីៗ​ទេ"</string>
<string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"ពពុះថ្មីៗ​ និង​ពពុះដែលបានបិទ​​នឹង​បង្ហាញ​នៅទីនេះ"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"មិនអាច​កែប្រែ​ការជូនដំណឹង​ទាំងនេះ​បានទេ។"</string>
@@ -1013,7 +1002,8 @@
<string name="bubble_accessibility_action_move_top_right" msgid="6916868852433483569">"ផ្លាស់ទីទៅផ្នែកខាងលើខាងស្ដាំ"</string>
<string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"ផ្លាស់ទីទៅផ្នែកខាងក្រោមខាងឆ្វេង​"</string>
<string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"ផ្លាស់ទីទៅផ្នែកខាងក្រោម​ខាងស្ដាំ"</string>
- <string name="bubble_dismiss_text" msgid="7071770411580452911">"ច្រានចោល"</string>
+ <!-- no translation found for bubble_dismiss_text (1314082410868930066) -->
+ <skip />
<string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"កុំបង្ហាញ​ការសន្ទនា​ជាពពុះ"</string>
<string name="bubbles_user_education_title" msgid="5547017089271445797">"ជជែក​ដោយប្រើ​ពពុះ"</string>
<string name="bubbles_user_education_description" msgid="1160281719576715211">"ការសន្ទនាថ្មីៗ​បង្ហាញជា​​ពពុះ ឬរូបអណ្ដែត។ ចុច ដើម្បីបើក​ពពុះ។ អូស ដើម្បី​ផ្លាស់ទី​ពពុះនេះ។"</string>
@@ -1024,19 +1014,22 @@
<string name="notification_content_system_nav_changed" msgid="5077913144844684544">"បានធ្វើ​បច្ចុប្បន្នភាព​ការរុករកក្នុង​ប្រព័ន្ធ។ ដើម្បីធ្វើការផ្លាស់ប្ដូរ សូមចូលទៅ​កាន់ការកំណត់។"</string>
<string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"ចូល​ទៅកាន់​ការកំណត់ ដើម្បី​ធ្វើបច្ចុប្បន្នភាព​ការរុករក​ក្នុង​ប្រព័ន្ធ"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"ផ្អាក​ដំណើរការ"</string>
+ <string name="priority_onboarding_title" msgid="2893070698479227616">"បានកំណត់​ការសន្ទនា​ជាអាទិភាព"</string>
+ <string name="priority_onboarding_behavior" msgid="5342816047020432929">"ការសន្ទនា​ជា​អាទិភាព​នឹង៖"</string>
<string name="priority_onboarding_show_at_top_text" msgid="1678400241025513541">"បង្ហាញនៅ​ខាងលើ​ផ្នែកសន្ទនា"</string>
<string name="priority_onboarding_show_avatar_text" msgid="5756291381124091508">"បង្ហាញរូបភាព​កម្រងព័ត៌មាន​នៅលើអេក្រង់​ចាក់សោ"</string>
<string name="priority_onboarding_appear_as_bubble_text" msgid="4227039772250263122">"បង្ហាញជា​ពពុះអណ្ដែត​នៅផ្នែក​ខាងលើនៃ​កម្មវិធី"</string>
<string name="priority_onboarding_ignores_dnd_text" msgid="2918952762719600529">"ផ្អាក​មុខងារកុំរំខាន"</string>
<string name="priority_onboarding_done_button_title" msgid="4569550984286506007">"យល់ហើយ"</string>
+ <string name="priority_onboarding_settings_button_title" msgid="6663601574303585927">"ការកំណត់"</string>
<string name="magnification_overlay_title" msgid="6584179429612427958">"វិនដូ​ត្រួតគ្នា​លើ​ការពង្រីក"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"វិនដូ​ការពង្រីក"</string>
<string name="magnification_controls_title" msgid="8421106606708891519">"វិនដូគ្រប់គ្រង​​ការពង្រីក"</string>
<string name="quick_controls_title" msgid="6839108006171302273">"ផ្ទាំងគ្រប់គ្រងឧបករណ៍"</string>
- <string name="quick_controls_subtitle" msgid="1667408093326318053">"បញ្ចូល​ការគ្រប់គ្រង​សម្រាប់​ឧបករណ៍​ដែលបានភ្ជាប់​របស់អ្នក"</string>
+ <string name="quick_controls_subtitle" msgid="1667408093326318053">"បញ្ចូល​ផ្ទាំងគ្រប់គ្រង​សម្រាប់​ឧបករណ៍​ដែលអ្នកបានភ្ជាប់"</string>
<string name="quick_controls_setup_title" msgid="8901436655997849822">"រៀបចំ​ផ្ទាំងគ្រប់គ្រងឧបករណ៍"</string>
<string name="quick_controls_setup_subtitle" msgid="1681506617879773824">"សង្កត់ប៊ូតុង​ថាមពលឱ្យជាប់ ដើម្បី​ចូលប្រើ​ការគ្រប់គ្រងរបស់អ្នក"</string>
- <string name="controls_providers_title" msgid="6879775889857085056">"ជ្រើសរើស​កម្មវិធី ដើម្បី​បញ្ចូល​ការគ្រប់គ្រង"</string>
+ <string name="controls_providers_title" msgid="6879775889857085056">"ជ្រើសរើស​កម្មវិធីដែលត្រូវបញ្ចូល​ផ្ទាំងគ្រប់គ្រង"</string>
<plurals name="controls_number_of_favorites" formatted="false" msgid="1057347832073807380">
<item quantity="other">បានបញ្ចូល​ការគ្រប់គ្រង <xliff:g id="NUMBER_1">%s</xliff:g>។</item>
<item quantity="one">បានបញ្ចូល​ការគ្រប់គ្រង <xliff:g id="NUMBER_0">%s</xliff:g>។</item>
@@ -1049,9 +1042,9 @@
<string name="accessibility_control_change_unfavorite" msgid="6997408061750740327">"ដកចេញ​ពី​សំណព្វ"</string>
<string name="accessibility_control_move" msgid="8980344493796647792">"ផ្លាស់ទី​ទៅតាំងទី <xliff:g id="NUMBER">%d</xliff:g>"</string>
<string name="controls_favorite_default_title" msgid="967742178688938137">"ការគ្រប់គ្រង"</string>
- <string name="controls_favorite_subtitle" msgid="6604402232298443956">"ជ្រើសរើស​ការគ្រប់គ្រង ដើម្បី​ចូលប្រើ​ពីម៉ឺនុយ​ថាមពល"</string>
- <string name="controls_favorite_rearrange" msgid="5616952398043063519">"ចុច​ឱ្យ​ជាប់ រួចអូស​ដើម្បី​រៀបចំ​ការគ្រប់គ្រង​ឡើងវិញ"</string>
- <string name="controls_favorite_removed" msgid="5276978408529217272">"បាន​លុបការគ្រប់គ្រងទាំងអស់ហើយ"</string>
+ <string name="controls_favorite_subtitle" msgid="6604402232298443956">"ជ្រើសរើស​ផ្ទាំងគ្រប់គ្រង​ដែលត្រូវចូលប្រើ​ពីម៉ឺនុយ​ថាមពល"</string>
+ <string name="controls_favorite_rearrange" msgid="5616952398043063519">"ចុច​ឱ្យ​ជាប់ រួចអូស​ដើម្បី​រៀបចំ​ផ្ទាំងគ្រប់គ្រង​ឡើងវិញ"</string>
+ <string name="controls_favorite_removed" msgid="5276978408529217272">"បាន​ដកផ្ទាំងគ្រប់គ្រងទាំងអស់ហើយ"</string>
<string name="controls_favorite_toast_no_changes" msgid="7094494210840877931">"មិនបាន​រក្សាទុក​ការផ្លាស់ប្ដូរទេ"</string>
<string name="controls_favorite_load_error" msgid="2533215155804455348">"មិនអាច​ផ្ទុក​បញ្ជី​នៃការគ្រប់គ្រង​ទាំងអស់​បានទេ។"</string>
<string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"ផ្សេងៗ"</string>
@@ -1070,13 +1063,17 @@
<string name="controls_structure_tooltip" msgid="4355922222944447867">"អូសដើម្បី​មើលច្រើនទៀត"</string>
<string name="controls_seeding_in_progress" msgid="3033855341410264148">"កំពុងផ្ទុក​ការណែនាំ"</string>
<string name="controls_media_close_session" msgid="9023534788828414585">"បិទវគ្គ​មេឌៀ​នេះ"</string>
+ <string name="controls_media_resume" msgid="1933520684481586053">"បន្ត"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"អសកម្ម ពិនិត្យមើល​កម្មវិធី"</string>
<string name="controls_error_retryable" msgid="864025882878378470">"បញ្ហា កំពុងព្យាយាម​ម្ដងទៀត…"</string>
- <string name="controls_error_removed" msgid="6299213591234723805">"បានលុប​ឧបករណ៍"</string>
+ <string name="controls_error_removed" msgid="6675638069846014366">"រកមិន​ឃើញទេ"</string>
+ <string name="controls_error_removed_title" msgid="1207794911208047818">"មិនអាច​គ្រប់គ្រង​បានទេ"</string>
+ <string name="controls_error_removed_message" msgid="2885911717034750542">"មិនអាច​ចូលប្រើ <xliff:g id="DEVICE">%1$s</xliff:g> បានទេ​។ សូមពិនិត្យមើល​កម្មវិធី <xliff:g id="APPLICATION">%2$s</xliff:g> ដើម្បីប្រាកដថា​នៅតែអាច​គ្រប់គ្រងបាន ហើយថា​ការកំណត់​កម្មវិធីនេះ​មិនបានផ្លាស់ប្ដូរឡើយ​។"</string>
+ <string name="controls_open_app" msgid="483650971094300141">"បើកកម្មវិធី"</string>
<string name="controls_error_generic" msgid="352500456918362905">"មិនអាច​ផ្ទុក​ស្ថានភាព​បានទេ"</string>
<string name="controls_error_failed" msgid="960228639198558525">"មានបញ្ហា សូម​ព្យាយាម​ម្តងទៀត"</string>
<string name="controls_in_progress" msgid="4421080500238215939">"កំពុងដំណើរការ"</string>
<string name="controls_added_tooltip" msgid="4842812921719153085">"សង្កត់​ប៊ូតុង​ថាមពល ដើម្បី​មើលឃើញ​ការគ្រប់គ្រង​ថ្មីៗ"</string>
- <string name="controls_menu_add" msgid="4447246119229920050">"បញ្ចូល​ការគ្រប់គ្រង"</string>
- <string name="controls_menu_edit" msgid="890623986951347062">"កែ​ការគ្រប់គ្រង"</string>
+ <string name="controls_menu_add" msgid="4447246119229920050">"បញ្ចូល​ផ្ទាំងគ្រប់គ្រង"</string>
+ <string name="controls_menu_edit" msgid="890623986951347062">"កែ​ផ្ទាំងគ្រប់គ្រង"</string>
</resources>
diff --git a/packages/SystemUI/res/values-kn/strings.xml b/packages/SystemUI/res/values-kn/strings.xml
index 7d77fc144680..afa60524fca6 100644
--- a/packages/SystemUI/res/values-kn/strings.xml
+++ b/packages/SystemUI/res/values-kn/strings.xml
@@ -77,9 +77,6 @@
<string name="compat_mode_on" msgid="4963711187149440884">"ಪರದೆ ತುಂಬಿಸಲು ಝೂಮ್ ಮಾಡು"</string>
<string name="compat_mode_off" msgid="7682459748279487945">"ಪರದೆ ತುಂಬಿಸಲು ವಿಸ್ತಾರಗೊಳಿಸು"</string>
<string name="global_action_screenshot" msgid="2760267567509131654">"ಸ್ಕ್ರೀನ್‌ಶಾಟ್"</string>
- <string name="global_action_lock_message" product="default" msgid="4466026255205186456">"ಹೆಚ್ಚಿನ ಆಯ್ಕೆಗಳಿಗಾಗಿ ನಿಮ್ಮ ಫೋನ್ ಅನ್ನು ಅನ್‌ಲಾಕ್ ಮಾಡಿ"</string>
- <string name="global_action_lock_message" product="tablet" msgid="7621167597240332986">"ಹೆಚ್ಚಿನ ಆಯ್ಕೆಗಳಿಗಾಗಿ ನಿಮ್ಮ ಟ್ಯಾಬ್ಲೆಟ್ ಅನ್ನು ಅನ್‌ಲಾಕ್ ಮಾಡಿ"</string>
- <string name="global_action_lock_message" product="device" msgid="538790401275363781">"ಹೆಚ್ಚಿನ ಆಯ್ಕೆಗಳಿಗಾಗಿ ನಿಮ್ಮ ಸಾಧನವನ್ನು ಅನ್‌ಲಾಕ್ ಮಾಡಿ"</string>
<string name="remote_input_image_insertion_text" msgid="4850791636452521123">"ಚಿತ್ರವನ್ನು ಕಳುಹಿಸಲಾಗಿದೆ"</string>
<string name="screenshot_saving_ticker" msgid="6519186952674544916">"ಸ್ಕ್ರೀನ್‌ಶಾಟ್ ಉಳಿಸಲಾಗುತ್ತಿದೆ…"</string>
<string name="screenshot_saving_title" msgid="2298349784913287333">"ಸ್ಕ್ರೀನ್‌ಶಾಟ್ ಉಳಿಸಲಾಗುತ್ತಿದೆ…"</string>
@@ -252,7 +249,7 @@
<string name="accessibility_gps_enabled" msgid="4061313248217660858">"GPS ಸಕ್ರಿಯವಾಗಿದೆ."</string>
<string name="accessibility_gps_acquiring" msgid="896207402196024040">"GPS ಸ್ವಾಧೀನ."</string>
<string name="accessibility_tty_enabled" msgid="1123180388823381118">"ಟೆಲಿಟೈಪ್‌ರೈಟರ್ ಸಕ್ರಿಯವಾಗಿದೆ."</string>
- <string name="accessibility_ringer_vibrate" msgid="6261841170896561364">"ರಿಂಗರ್ ಕಂಪನ."</string>
+ <string name="accessibility_ringer_vibrate" msgid="6261841170896561364">"ರಿಂಗರ್ ವೈಬ್ರೇಟ್‌."</string>
<string name="accessibility_ringer_silent" msgid="8994620163934249882">"ರಿಂಗರ್ ಶಾಂತ."</string>
<!-- no translation found for accessibility_casting (8708751252897282313) -->
<skip />
@@ -595,29 +592,21 @@
<string name="volume_odi_captions_hint_enable" msgid="2073091194012843195">"ಸಕ್ರಿಯಗೊಳಿಸಿ"</string>
<string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"ನಿಷ್ಕ್ರಿಯಗೊಳಿಸಿ"</string>
<string name="accessibility_output_chooser" msgid="7807898688967194183">"ಔಟ್‌ಪುಟ್ ಸಾಧನವನ್ನು ಬದಲಿಸಿ"</string>
- <!-- no translation found for screen_pinning_title (9058007390337841305) -->
- <skip />
+ <string name="screen_pinning_title" msgid="9058007390337841305">"ಆ್ಯಪ್ ಅನ್ನು ಪಿನ್ ಮಾಡಲಾಗಿದೆ"</string>
<string name="screen_pinning_description" msgid="8699395373875667743">"ನೀವು ಅನ್‌ಪಿನ್ ಮಾಡುವವರೆಗೆ ಅದನ್ನು ವೀಕ್ಷಣೆಯಲ್ಲಿಡುತ್ತದೆ. ಸ್ಪರ್ಶಿಸಿ ಮತ್ತು ಹಿಡಿದುಕೊಳ್ಳಿ ಹಾಗೂ ಅನ್‌ಪಿನ್ ಮಾಡಲು ಅವಲೋಕಿಸಿ."</string>
<string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"ನೀವು ಅನ್‌ಪಿನ್ ಮಾಡುವವರೆಗೆ ಅದನ್ನು ವೀಕ್ಷಣೆಯಲ್ಲಿಡುತ್ತದೆ. ಸ್ಪರ್ಶಿಸಿ ಮತ್ತು ಹಿಡಿದುಕೊಳ್ಳಿ ಹಾಗೂ ಅನ್‌ಪಿನ್ ಮಾಡಲು ಮುಖಪುಟಕ್ಕೆ ಹಿಂತಿರುಗಿ."</string>
<string name="screen_pinning_description_gestural" msgid="7246323931831232068">"ನೀವು ಅನ್‌ಪಿನ್ ಮಾಡುವವರೆಗೆ ಅದನ್ನು ವೀಕ್ಷಣೆಯಲ್ಲಿಡುತ್ತದೆ. ಮೇಲೆ ಸ್ವೈಪ್ ಮಾಡಿ ಮತ್ತು ಅನ್‌ಪಿನ್ ಮಾಡಲು ಹೋಲ್ಡ್ ಮಾಡಿ."</string>
<string name="screen_pinning_description_accessible" msgid="7386449191953535332">"ನೀವು ಅನ್‌ಪಿನ್ ಮಾಡುವವರೆಗೆ ಅದನ್ನು ವೀಕ್ಷಣೆಯಲ್ಲಿಡುತ್ತದೆ. ಅನ್‌ಪಿನ್ ಮಾಡಲು ಅವಲೋಕನವನ್ನು ಸ್ಪರ್ಶಿಸಿ ಮತ್ತು ಹೋಲ್ಡ್ ಮಾಡಿ."</string>
<string name="screen_pinning_description_recents_invisible_accessible" msgid="2857071808674481986">"ನೀವು ಅನ್‌ಪಿನ್ ಮಾಡುವವರೆಗೆ ಅದನ್ನು ವೀಕ್ಷಣೆಯಲ್ಲಿಡುತ್ತದೆ. ಅನ್‌ಪಿನ್ ಮಾಡಲು ಮುಖಪುಟವನ್ನು ಸ್ಪರ್ಶಿಸಿ ಮತ್ತು ಒತ್ತಿಹಿಡಿಯಿರಿ."</string>
- <!-- no translation found for screen_pinning_exposes_personal_data (8189852022981524789) -->
- <skip />
- <!-- no translation found for screen_pinning_can_open_other_apps (7529756813231421455) -->
- <skip />
- <!-- no translation found for screen_pinning_toast (8177286912533744328) -->
- <skip />
- <!-- no translation found for screen_pinning_toast_recents_invisible (6850978077443052594) -->
- <skip />
- <!-- no translation found for screen_pinning_toast_gesture_nav (170699893395336705) -->
- <skip />
+ <string name="screen_pinning_exposes_personal_data" msgid="8189852022981524789">"ವೈಯಕ್ತಿಕ ಡೇಟಾವನ್ನು ಪ್ರವೇಶಿಸಬಹುದು (ಉದಾ, ಸಂಪರ್ಕಗಳು ಮತ್ತು ಇಮೇಲ್ ವಿಷಯ)."</string>
+ <string name="screen_pinning_can_open_other_apps" msgid="7529756813231421455">"ಪಿನ್ ಮಾಡಲಾದ ಆ್ಯಪ್ ಇತರ ಆ್ಯಪ್‌ಗಳನ್ನು ತೆರೆಯಬಹುದು."</string>
+ <string name="screen_pinning_toast" msgid="8177286912533744328">"ಈ ಆ್ಯಪ್ ಅನ್ನು ಅನ್‌‌ಪಿನ್ ಮಾಡಲು, ಹಿಂದಕ್ಕೆ ಮತ್ತು ಸಮಗ್ರ ನೋಟ ಬಟನ್‌ಗಳನ್ನು ಸ್ಪರ್ಶಿಸಿ &amp; ಒತ್ತಿಹಿಡಿಯಿರಿ"</string>
+ <string name="screen_pinning_toast_recents_invisible" msgid="6850978077443052594">"ಈ ಆ್ಯಪ್ ಅನ್ನು ಅನ್‌ಪಿನ್ ಮಾಡಲು, ಹಿಂದಕ್ಕೆ ಮತ್ತು ಮುಖಪುಟ ಬಟನ್‌ಗಳನ್ನು ಸ್ಪರ್ಶಿಸಿ &amp; ಒತ್ತಿಹಿಡಿಯಿರಿ"</string>
+ <string name="screen_pinning_toast_gesture_nav" msgid="170699893395336705">"ಈ ಆ್ಯಪ್‌ ಅನ್ನು ಅನ್‌ಪಿನ್ ಮಾಡಲು, ಮೇಲಕ್ಕೆ ಸ್ವೈಪ್ ಮಾಡಿ &amp; ಒತ್ತಿಹಿಡಿಯಿರಿ"</string>
<string name="screen_pinning_positive" msgid="3285785989665266984">"ತಿಳಿಯಿತು"</string>
<string name="screen_pinning_negative" msgid="6882816864569211666">"ಧನ್ಯವಾದಗಳು"</string>
- <!-- no translation found for screen_pinning_start (7483998671383371313) -->
- <skip />
- <!-- no translation found for screen_pinning_exit (4553787518387346893) -->
- <skip />
+ <string name="screen_pinning_start" msgid="7483998671383371313">"ಆ್ಯಪ್ ಪಿನ್ ಮಾಡಲಾಗಿದೆ"</string>
+ <string name="screen_pinning_exit" msgid="4553787518387346893">"ಆ್ಯಪ್ ಅನ್‌ಪಿನ್ ಮಾಡಲಾಗಿದೆ"</string>
<string name="quick_settings_reset_confirmation_title" msgid="463533331480997595">"<xliff:g id="TILE_LABEL">%1$s</xliff:g> ಮರೆಮಾಡುವುದೇ?"</string>
<string name="quick_settings_reset_confirmation_message" msgid="2320586180785674186">"ನೀವು ಸೆಟ್ಟಿಂಗ್‌ಗಳಲ್ಲಿ ಅದನ್ನು ಆನ್ ಮಾಡಿದಾಗ ಅದು ಮರುಕಾಣಿಸಿಕೊಳ್ಳುತ್ತದೆ."</string>
<string name="quick_settings_reset_confirmation_button" msgid="3341477479055016776">"ಮರೆಮಾಡಿ"</string>
@@ -730,7 +719,7 @@
<string name="notification_channel_summary_priority" msgid="7952654515769021553">"ಸಂಭಾಷಣೆ ವಿಭಾಗದ ಮೇಲ್ಭಾಗದಲ್ಲಿ ತೇಲುವ ಬಬಲ್‌ ಆಗಿ ಗೋಚರಿಸುತ್ತದೆ ಮತ್ತು ಪ್ರೊಫೈಲ್ ಚಿತ್ರವನ್ನು ಲಾಕ್‌ಸ್ಕ್ರೀನ್‌ ಮೇಲೆ‌ ಗೋಚರಿಸುತ್ತದೆ"</string>
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"ಸೆಟ್ಟಿಂಗ್‌ಗಳು"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"ಆದ್ಯತೆ"</string>
- <string name="no_shortcut" msgid="7176375126961212514">"<xliff:g id="APP_NAME">%1$s</xliff:g> ಆ್ಯಪ್ ಸಂಭಾಷಣೆ ನಿರ್ದಿಷ್ಟ ಸೆಟ್ಟಿಂಗ್‌ಗಳನ್ನು ಬೆಂಬಲಿಸುವುದಿಲ್ಲ"</string>
+ <string name="no_shortcut" msgid="8257177117568230126">"ಸಂವಾದ ಫೀಚರ್‌ಗಳನ್ನು <xliff:g id="APP_NAME">%1$s</xliff:g> ಬೆಂಬಲಿಸುವುದಿಲ್ಲ"</string>
<string name="bubble_overflow_empty_title" msgid="3120029421991510842">"ಯಾವುದೇ ಇತ್ತೀಚಿನ ಬಬಲ್ಸ್ ಇಲ್ಲ"</string>
<string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"ಇತ್ತೀಚಿನ ಬಬಲ್ಸ್ ಮತ್ತು ವಜಾಗೊಳಿಸಿದ ಬಬಲ್ಸ್ ಇಲ್ಲಿ ಗೋಚರಿಸುತ್ತವೆ"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"ಈ ಅಧಿಸೂಚನೆಗಳನ್ನು ಮಾರ್ಪಡಿಸಲು ಸಾಧ್ಯವಿಲ್ಲ."</string>
@@ -1013,7 +1002,8 @@
<string name="bubble_accessibility_action_move_top_right" msgid="6916868852433483569">"ಬಲ ಮೇಲ್ಭಾಗಕ್ಕೆ ಸರಿಸಿ"</string>
<string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"ಸ್ಕ್ರೀನ್‌ನ ಎಡ ಕೆಳಭಾಗಕ್ಕೆ ಸರಿಸಿ"</string>
<string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"ಕೆಳಗಿನ ಬಲಭಾಗಕ್ಕೆ ಸರಿಸಿ"</string>
- <string name="bubble_dismiss_text" msgid="7071770411580452911">"ವಜಾಗೊಳಿಸಿ"</string>
+ <!-- no translation found for bubble_dismiss_text (1314082410868930066) -->
+ <skip />
<string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"ಸಂಭಾಷಣೆಯನ್ನು ಬಬಲ್ ಮಾಡಬೇಡಿ"</string>
<string name="bubbles_user_education_title" msgid="5547017089271445797">"ಬಬಲ್ಸ್ ಬಳಸಿ ಚಾಟ್ ಮಾಡಿ"</string>
<string name="bubbles_user_education_description" msgid="1160281719576715211">"ಹೊಸ ಸಂಭಾಷಣೆಗಳು ತೇಲುವ ಐಕಾನ್‌ಗಳು ಅಥವಾ ಬಬಲ್ಸ್ ಆಗಿ ಗೋಚರಿಸುತ್ತವೆ. ಬಬಲ್ ತೆರೆಯಲು ಟ್ಯಾಪ್ ಮಾಡಿ. ಅದನ್ನು ಡ್ರ್ಯಾಗ್ ಮಾಡಲು ಎಳೆಯಿರಿ."</string>
@@ -1024,11 +1014,14 @@
<string name="notification_content_system_nav_changed" msgid="5077913144844684544">"ಸಿಸ್ಟಂ ನ್ಯಾವಿಗೇಷನ ಅಪ್‌ಡೇಟ್ ಮಾಡಲಾಗಿದೆ ಬದಲಾವಣೆಗಳನ್ನು ಮಾಡಲು, ಸೆಟ್ಟಿಂಗ್‌ಗಳಿಗೆ ಹೋಗಿ."</string>
<string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"ಸಿಸ್ಟಂ ನ್ಯಾವಿಗೇಷನ್ ಅಪ್‌ಡೇಟ್ ಮಾಡಲು ಸೆಟ್ಟಿಂಗ್‌ಗಳಿಗೆ ಹೋಗಿ"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"ಸ್ಟ್ಯಾಂಡ್‌ಬೈ"</string>
+ <string name="priority_onboarding_title" msgid="2893070698479227616">"ಸಂವಾದವನ್ನು ಆದ್ಯತೆಯಾಗಿ ಹೊಂದಿಸಲಾಗಿದೆ"</string>
+ <string name="priority_onboarding_behavior" msgid="5342816047020432929">"ಆದ್ಯತೆಯ ಸಂವಾದಗಳು:"</string>
<string name="priority_onboarding_show_at_top_text" msgid="1678400241025513541">"ಸಂಭಾಷಣೆ ವಿಭಾಗದ ಮೇಲ್ಭಾಗದಲ್ಲಿ ತೋರಿಸಿ"</string>
<string name="priority_onboarding_show_avatar_text" msgid="5756291381124091508">"ಲಾಕ್ ಸ್ಕ್ರೀನ್‌ ಮೇಲೆ ಪ್ರೊಫೈಲ್ ಚಿತ್ರವನ್ನು ತೋರಿಸಿ"</string>
<string name="priority_onboarding_appear_as_bubble_text" msgid="4227039772250263122">"ಆ್ಯಪ್‌ಗಳ ಮೇಲ್ಭಾಗದಲ್ಲಿ ತೇಲುವ ಬಬಲ್‌ನಂತೆ ಗೋಚರಿಸಲಿ"</string>
<string name="priority_onboarding_ignores_dnd_text" msgid="2918952762719600529">"ಅಡಚಣೆ ಮಾಡಬೇಡ ಅನ್ನು ಅಡ್ಡಿಪಡಿಸಿ"</string>
<string name="priority_onboarding_done_button_title" msgid="4569550984286506007">"ಅರ್ಥವಾಯಿತು"</string>
+ <string name="priority_onboarding_settings_button_title" msgid="6663601574303585927">"ಸೆಟ್ಟಿಂಗ್‌ಗಳು"</string>
<string name="magnification_overlay_title" msgid="6584179429612427958">"ವರ್ಧನೆಯ ಓವರ್‌ಲೇ ವಿಂಡೋ"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"ವರ್ಧನೆಯ ವಿಂಡೋ"</string>
<string name="magnification_controls_title" msgid="8421106606708891519">"ವರ್ಧನೆಯ ವಿಂಡೋ ನಿಯಂತ್ರಣಗಳು"</string>
@@ -1070,9 +1063,13 @@
<string name="controls_structure_tooltip" msgid="4355922222944447867">"ಇನ್ನಷ್ಟು ನೋಡಲು ಸ್ವೈಪ್ ಮಾಡಿ"</string>
<string name="controls_seeding_in_progress" msgid="3033855341410264148">"ಶಿಫಾರಸುಗಳು ಲೋಡ್ ಆಗುತ್ತಿವೆ"</string>
<string name="controls_media_close_session" msgid="9023534788828414585">"ಈ ಮಾಧ್ಯಮ ಸೆಶನ್ ಅನ್ನು ಮುಚ್ಚಿರಿ"</string>
+ <string name="controls_media_resume" msgid="1933520684481586053">"ಪುನರಾರಂಭಿಸಿ"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"ನಿಷ್ಕ್ರಿಯ, ಆ್ಯಪ್ ಪರಿಶೀಲಿಸಿ"</string>
<string name="controls_error_retryable" msgid="864025882878378470">"ದೋಷ, ಮರುಪ್ರಯತ್ನಿಸಲಾಗುತ್ತಿದೆ…"</string>
- <string name="controls_error_removed" msgid="6299213591234723805">"ಸಾಧನವನ್ನು ತೆಗೆದುಹಾಕಲಾಗಿದೆ"</string>
+ <string name="controls_error_removed" msgid="6675638069846014366">"ಕಂಡುಬಂದಿಲ್ಲ"</string>
+ <string name="controls_error_removed_title" msgid="1207794911208047818">"ನಿಯಂತ್ರಣ ಲಭ್ಯವಿಲ್ಲ"</string>
+ <string name="controls_error_removed_message" msgid="2885911717034750542">"<xliff:g id="DEVICE">%1$s</xliff:g> ಪ್ರವೇಶಿಸಲು ಸಾಧ್ಯವಿಲ್ಲ. ನಿಯಂತ್ರಣ ಈಗಲೂ ಲಭ್ಯವಿದೆಯೇ ಮತ್ತು <xliff:g id="APPLICATION">%2$s</xliff:g> ಆ್ಯಪ್ ಸೆಟ್ಟಿಂಗ್‌ಗಳನ್ನು ಬದಲಾಯಿಸಲಾಗಿಲ್ಲ ಎಂಬುದನ್ನು ಖಚಿತಪಡಿಸಿಕೊಳ್ಳಲು ಆ್ಯಪ್ ಅನ್ನು ಪರಿಶೀಲಿಸಿ."</string>
+ <string name="controls_open_app" msgid="483650971094300141">"ಆ್ಯಪ್ ತೆರೆಯಿರಿ"</string>
<string name="controls_error_generic" msgid="352500456918362905">"ಸ್ಥಿತಿ ಲೋಡ್ ಮಾಡಲು ಸಾಧ್ಯವಿಲ್ಲ"</string>
<string name="controls_error_failed" msgid="960228639198558525">"ದೋಷ, ಮತ್ತೆ ಪ್ರಯತ್ನಿಸಿ"</string>
<string name="controls_in_progress" msgid="4421080500238215939">"ಪ್ರಗತಿಯಲ್ಲಿದೆ"</string>
diff --git a/packages/SystemUI/res/values-ko/strings.xml b/packages/SystemUI/res/values-ko/strings.xml
index a015afee2faa..a75c230cd681 100644
--- a/packages/SystemUI/res/values-ko/strings.xml
+++ b/packages/SystemUI/res/values-ko/strings.xml
@@ -77,9 +77,6 @@
<string name="compat_mode_on" msgid="4963711187149440884">"전체화면 모드로 확대"</string>
<string name="compat_mode_off" msgid="7682459748279487945">"전체화면 모드로 확대"</string>
<string name="global_action_screenshot" msgid="2760267567509131654">"스크린샷"</string>
- <string name="global_action_lock_message" product="default" msgid="4466026255205186456">"더 많은 옵션을 확인하려면 휴대전화를 잠금 해제하세요."</string>
- <string name="global_action_lock_message" product="tablet" msgid="7621167597240332986">"더 많은 옵션을 확인하려면 태블릿을 잠금 해제하세요."</string>
- <string name="global_action_lock_message" product="device" msgid="538790401275363781">"더 많은 옵션을 확인하려면 기기를 잠금 해제하세요."</string>
<string name="remote_input_image_insertion_text" msgid="4850791636452521123">"이미지 보냄"</string>
<string name="screenshot_saving_ticker" msgid="6519186952674544916">"캡쳐화면 저장 중..."</string>
<string name="screenshot_saving_title" msgid="2298349784913287333">"캡쳐화면 저장 중..."</string>
@@ -595,29 +592,21 @@
<string name="volume_odi_captions_hint_enable" msgid="2073091194012843195">"사용"</string>
<string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"사용 중지"</string>
<string name="accessibility_output_chooser" msgid="7807898688967194183">"출력 기기 전환"</string>
- <!-- no translation found for screen_pinning_title (9058007390337841305) -->
- <skip />
+ <string name="screen_pinning_title" msgid="9058007390337841305">"앱 고정됨"</string>
<string name="screen_pinning_description" msgid="8699395373875667743">"고정 해제할 때까지 계속 표시됩니다. 고정 해제하려면 뒤로 및 최근 사용을 길게 터치하세요."</string>
<string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"고정 해제할 때까지 계속 표시됩니다. 고정 해제하려면 뒤로 및 홈을 길게 터치하세요."</string>
<string name="screen_pinning_description_gestural" msgid="7246323931831232068">"고정 해제할 때까지 계속 표시됩니다. 고정 해제하려면 위로 스와이프한 다음 탭한 상태를 유지하세요."</string>
<string name="screen_pinning_description_accessible" msgid="7386449191953535332">"고정 해제할 때까지 계속 표시됩니다. 고정 해제하려면 최근 사용을 길게 터치하세요."</string>
<string name="screen_pinning_description_recents_invisible_accessible" msgid="2857071808674481986">"고정 해제할 때까지 계속 표시됩니다. 고정 해제하려면 홈을 길게 터치하세요."</string>
- <!-- no translation found for screen_pinning_exposes_personal_data (8189852022981524789) -->
- <skip />
- <!-- no translation found for screen_pinning_can_open_other_apps (7529756813231421455) -->
- <skip />
- <!-- no translation found for screen_pinning_toast (8177286912533744328) -->
- <skip />
- <!-- no translation found for screen_pinning_toast_recents_invisible (6850978077443052594) -->
- <skip />
- <!-- no translation found for screen_pinning_toast_gesture_nav (170699893395336705) -->
- <skip />
+ <string name="screen_pinning_exposes_personal_data" msgid="8189852022981524789">"개인 정보가 표시될 수 있습니다(연락처, 이메일 내용 등)."</string>
+ <string name="screen_pinning_can_open_other_apps" msgid="7529756813231421455">"고정된 앱을 통해 다른 앱이 열릴 수 있습니다."</string>
+ <string name="screen_pinning_toast" msgid="8177286912533744328">"이 앱을 고정 해제하려면 뒤로 및 최근 사용 버튼을 길게 터치하세요."</string>
+ <string name="screen_pinning_toast_recents_invisible" msgid="6850978077443052594">"이 앱을 고정 해제하려면 뒤로 및 홈 버튼을 길게 터치하세요."</string>
+ <string name="screen_pinning_toast_gesture_nav" msgid="170699893395336705">"이 앱을 고정 해제하려면 위로 스와이프하고 유지하세요."</string>
<string name="screen_pinning_positive" msgid="3285785989665266984">"확인"</string>
<string name="screen_pinning_negative" msgid="6882816864569211666">"거부"</string>
- <!-- no translation found for screen_pinning_start (7483998671383371313) -->
- <skip />
- <!-- no translation found for screen_pinning_exit (4553787518387346893) -->
- <skip />
+ <string name="screen_pinning_start" msgid="7483998671383371313">"앱 고정됨"</string>
+ <string name="screen_pinning_exit" msgid="4553787518387346893">"앱 고정 해제됨"</string>
<string name="quick_settings_reset_confirmation_title" msgid="463533331480997595">"<xliff:g id="TILE_LABEL">%1$s</xliff:g>을(를) 숨기시겠습니까?"</string>
<string name="quick_settings_reset_confirmation_message" msgid="2320586180785674186">"다음번에 설정에서 사용 설정하면 다시 표시됩니다."</string>
<string name="quick_settings_reset_confirmation_button" msgid="3341477479055016776">"숨기기"</string>
@@ -730,8 +719,8 @@
<string name="notification_channel_summary_priority" msgid="7952654515769021553">"대화 섹션 상단의 플로팅 대화창 또는 잠금 화면의 프로필 사진으로 표시됩니다."</string>
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"설정"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"우선순위"</string>
- <string name="no_shortcut" msgid="7176375126961212514">"<xliff:g id="APP_NAME">%1$s</xliff:g>에서는 대화 관련 설정을 지원하지 않습니다."</string>
- <string name="bubble_overflow_empty_title" msgid="3120029421991510842">"최근에 닫은 대화창 없음"</string>
+ <string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> 앱은 대화 기능을 지원하지 않습니다."</string>
+ <string name="bubble_overflow_empty_title" msgid="3120029421991510842">"최근 대화창 없음"</string>
<string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"최근 대화창과 내가 닫은 대화창이 여기에 표시됩니다."</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"이 알림은 수정할 수 없습니다."</string>
<string name="notification_multichannel_desc" msgid="7414593090056236179">"이 알림 그룹은 여기에서 설정할 수 없습니다."</string>
@@ -1013,9 +1002,10 @@
<string name="bubble_accessibility_action_move_top_right" msgid="6916868852433483569">"오른쪽 상단으로 이동"</string>
<string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"왼쪽 하단으로 이동"</string>
<string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"오른쪽 하단으로 이동"</string>
- <string name="bubble_dismiss_text" msgid="7071770411580452911">"닫기"</string>
+ <!-- no translation found for bubble_dismiss_text (1314082410868930066) -->
+ <skip />
<string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"대화를 대화창으로 표시하지 않음"</string>
- <string name="bubbles_user_education_title" msgid="5547017089271445797">"대화창을 사용하여 채팅하세요"</string>
+ <string name="bubbles_user_education_title" msgid="5547017089271445797">"대화창으로 채팅하기"</string>
<string name="bubbles_user_education_description" msgid="1160281719576715211">"새로운 대화가 플로팅 아이콘인 대화창으로 표시됩니다. 대화창을 열려면 탭하세요. 드래그하여 이동할 수 있습니다."</string>
<string name="bubbles_user_education_manage_title" msgid="2848511858160342320">"언제든지 대화창을 제어하세요"</string>
<string name="bubbles_user_education_manage" msgid="1391639189507036423">"이 앱에서 대화창을 사용 중지하려면 관리를 탭하세요."</string>
@@ -1024,17 +1014,20 @@
<string name="notification_content_system_nav_changed" msgid="5077913144844684544">"시스템 탐색이 업데이트되었습니다. 변경하려면 설정으로 이동하세요."</string>
<string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"설정으로 이동하여 시스템 탐색을 업데이트하세요."</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"대기"</string>
+ <string name="priority_onboarding_title" msgid="2893070698479227616">"대화가 우선순위 대화로 설정됨"</string>
+ <string name="priority_onboarding_behavior" msgid="5342816047020432929">"우선순위 대화에서 다음과 같은 동작을 합니다."</string>
<string name="priority_onboarding_show_at_top_text" msgid="1678400241025513541">"대화 섹션의 상단에 표시"</string>
<string name="priority_onboarding_show_avatar_text" msgid="5756291381124091508">"잠금 화면에서 프로필 사진 표시"</string>
<string name="priority_onboarding_appear_as_bubble_text" msgid="4227039772250263122">"앱 상단에서 플로팅 대화창으로 표시"</string>
<string name="priority_onboarding_ignores_dnd_text" msgid="2918952762719600529">"방해 금지 모드 무시"</string>
<string name="priority_onboarding_done_button_title" msgid="4569550984286506007">"확인"</string>
+ <string name="priority_onboarding_settings_button_title" msgid="6663601574303585927">"설정"</string>
<string name="magnification_overlay_title" msgid="6584179429612427958">"확대 오버레이 창"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"확대 창"</string>
<string name="magnification_controls_title" msgid="8421106606708891519">"확대 창 컨트롤"</string>
- <string name="quick_controls_title" msgid="6839108006171302273">"기기 제어"</string>
+ <string name="quick_controls_title" msgid="6839108006171302273">"기기 컨트롤"</string>
<string name="quick_controls_subtitle" msgid="1667408093326318053">"연결된 기기의 컨트롤을 추가합니다."</string>
- <string name="quick_controls_setup_title" msgid="8901436655997849822">"기기 제어 설정"</string>
+ <string name="quick_controls_setup_title" msgid="8901436655997849822">"기기 컨트롤 설정"</string>
<string name="quick_controls_setup_subtitle" msgid="1681506617879773824">"전원 버튼을 길게 눌러 컨트롤에 액세스하세요."</string>
<string name="controls_providers_title" msgid="6879775889857085056">"컨트롤을 추가할 앱을 선택하세요"</string>
<plurals name="controls_number_of_favorites" formatted="false" msgid="1057347832073807380">
@@ -1049,13 +1042,13 @@
<string name="accessibility_control_change_unfavorite" msgid="6997408061750740327">"즐겨찾기에서 삭제"</string>
<string name="accessibility_control_move" msgid="8980344493796647792">"다음 위치로 이동: <xliff:g id="NUMBER">%d</xliff:g>"</string>
<string name="controls_favorite_default_title" msgid="967742178688938137">"제어"</string>
- <string name="controls_favorite_subtitle" msgid="6604402232298443956">"전원 메뉴에서 액세스할 컨트롤을 선택합니다."</string>
+ <string name="controls_favorite_subtitle" msgid="6604402232298443956">"전원 메뉴에서 액세스할 컨트롤 선택"</string>
<string name="controls_favorite_rearrange" msgid="5616952398043063519">"길게 누르고 드래그하여 컨트롤 재정렬"</string>
<string name="controls_favorite_removed" msgid="5276978408529217272">"모든 컨트롤 삭제됨"</string>
<string name="controls_favorite_toast_no_changes" msgid="7094494210840877931">"변경사항이 저장되지 않음"</string>
<string name="controls_favorite_load_error" msgid="2533215155804455348">"전체 컨트롤 목록을 로드할 수 없습니다."</string>
<string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"기타"</string>
- <string name="controls_dialog_title" msgid="2343565267424406202">"기기 제어에 추가"</string>
+ <string name="controls_dialog_title" msgid="2343565267424406202">"기기 컨트롤에 추가"</string>
<string name="controls_dialog_ok" msgid="2770230012857881822">"추가"</string>
<string name="controls_dialog_message" msgid="342066938390663844">"<xliff:g id="APP">%s</xliff:g>에서 제안"</string>
<string name="controls_dialog_confirmation" msgid="586517302736263447">"컨트롤 업데이트됨"</string>
@@ -1070,9 +1063,13 @@
<string name="controls_structure_tooltip" msgid="4355922222944447867">"자세히 보려면 스와이프하세요."</string>
<string name="controls_seeding_in_progress" msgid="3033855341410264148">"추천 제어 기능 로드 중"</string>
<string name="controls_media_close_session" msgid="9023534788828414585">"이 미디어 세션 닫기"</string>
+ <string name="controls_media_resume" msgid="1933520684481586053">"다시 시작"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"비활성. 앱을 확인하세요."</string>
<string name="controls_error_retryable" msgid="864025882878378470">"오류 발생, 다시 시도 중…"</string>
- <string name="controls_error_removed" msgid="6299213591234723805">"기기가 삭제됨"</string>
+ <string name="controls_error_removed" msgid="6675638069846014366">"찾을 수 없음"</string>
+ <string name="controls_error_removed_title" msgid="1207794911208047818">"컨트롤을 사용할 수 없음"</string>
+ <string name="controls_error_removed_message" msgid="2885911717034750542">"<xliff:g id="DEVICE">%1$s</xliff:g>에 액세스할 수 없습니다. <xliff:g id="APPLICATION">%2$s</xliff:g> 앱에서 컨트롤을 계속 사용할 수 있는지와 앱 설정이 변경되지 않았는지 확인하세요."</string>
+ <string name="controls_open_app" msgid="483650971094300141">"앱 열기"</string>
<string name="controls_error_generic" msgid="352500456918362905">"통계를 로드할 수 없음"</string>
<string name="controls_error_failed" msgid="960228639198558525">"오류. 다시 시도하세요."</string>
<string name="controls_in_progress" msgid="4421080500238215939">"진행 중"</string>
diff --git a/packages/SystemUI/res/values-ky/strings.xml b/packages/SystemUI/res/values-ky/strings.xml
index fbf3dc05fc7b..a0f532acf9da 100644
--- a/packages/SystemUI/res/values-ky/strings.xml
+++ b/packages/SystemUI/res/values-ky/strings.xml
@@ -77,9 +77,6 @@
<string name="compat_mode_on" msgid="4963711187149440884">"Экрнд тлтр ү. чен өлч өзг"</string>
<string name="compat_mode_off" msgid="7682459748279487945">"Экранды толтуруу ү-н чоюу"</string>
<string name="global_action_screenshot" msgid="2760267567509131654">"Скриншот"</string>
- <string name="global_action_lock_message" product="default" msgid="4466026255205186456">"Дагы башка параметрлерди көрүү үчүн телефонуңуздун кулпусун ачыңыз"</string>
- <string name="global_action_lock_message" product="tablet" msgid="7621167597240332986">"Дагы башка параметрлерди көрүү үчүн планшетиңиздин кулпусун ачыңыз"</string>
- <string name="global_action_lock_message" product="device" msgid="538790401275363781">"Дагы башка параметрлерди көрүү үчүн түзмөгүңүздүн кулпусун ачыңыз"</string>
<string name="remote_input_image_insertion_text" msgid="4850791636452521123">"сүрөт жөнөттү"</string>
<string name="screenshot_saving_ticker" msgid="6519186952674544916">"Скриншот сакталууда…"</string>
<string name="screenshot_saving_title" msgid="2298349784913287333">"Скриншот сакталууда..."</string>
@@ -595,29 +592,21 @@
<string name="volume_odi_captions_hint_enable" msgid="2073091194012843195">"иштетүү"</string>
<string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"өчүрүү"</string>
<string name="accessibility_output_chooser" msgid="7807898688967194183">"Аудио түзмөктү которуштуруу"</string>
- <!-- no translation found for screen_pinning_title (9058007390337841305) -->
- <skip />
+ <string name="screen_pinning_title" msgid="9058007390337841305">"Колдонмо кадалды"</string>
<string name="screen_pinning_description" msgid="8699395373875667743">"Ал бошотулмайынча көрүнө берет. Бошотуу үчүн, \"Артка\" жана \"Карап чыгуу\" баскычтарын басып, кармап туруңуз."</string>
<string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"Ал бошотулмайынча көрүнө берет. Бошотуу үчүн, \"Артка\" жана \"Башкы бет\" баскычтарын басып, кармап туруңуз."</string>
<string name="screen_pinning_description_gestural" msgid="7246323931831232068">"Ал бошотулмайынча көрүнө берет. Бошотуу үчүн өйдө сүрүп, коё бербей басып туруңуз."</string>
<string name="screen_pinning_description_accessible" msgid="7386449191953535332">"Ал бошотулмайынча көрүнө берет. Бошотуу үчүн, \"Карап чыгуу\" баскычын басып, кармап туруңуз."</string>
<string name="screen_pinning_description_recents_invisible_accessible" msgid="2857071808674481986">"Ал бошотулмайынча көрүнө берет. Бошотуу үчүн, \"Башкы бет\" баскычын басып, кармап туруңуз."</string>
- <!-- no translation found for screen_pinning_exposes_personal_data (8189852022981524789) -->
- <skip />
- <!-- no translation found for screen_pinning_can_open_other_apps (7529756813231421455) -->
- <skip />
- <!-- no translation found for screen_pinning_toast (8177286912533744328) -->
- <skip />
- <!-- no translation found for screen_pinning_toast_recents_invisible (6850978077443052594) -->
- <skip />
- <!-- no translation found for screen_pinning_toast_gesture_nav (170699893395336705) -->
- <skip />
+ <string name="screen_pinning_exposes_personal_data" msgid="8189852022981524789">"Байланыштар жана электрондук почталардын мазмуну сыяктуу жеке дайындар ачык болушу мүмкүн."</string>
+ <string name="screen_pinning_can_open_other_apps" msgid="7529756813231421455">"Кадалган колдонмо башка колдонмолорду ача алат."</string>
+ <string name="screen_pinning_toast" msgid="8177286912533744328">"Бул колдонмону бошотуу үчүн \"Артка\" жана \"Назар салуу\" баскычтарын басып, кармап туруңуз"</string>
+ <string name="screen_pinning_toast_recents_invisible" msgid="6850978077443052594">"Бул колдонмону бошотуу үчүн \"Артка\" жана \"Башкы бет\" баскычтарын басып, кармап туруңуз"</string>
+ <string name="screen_pinning_toast_gesture_nav" msgid="170699893395336705">"Бул колдонмону бошотуу үчүн аны өйдө сүрүп, кармап туруңуз"</string>
<string name="screen_pinning_positive" msgid="3285785989665266984">"Түшүндүм"</string>
<string name="screen_pinning_negative" msgid="6882816864569211666">"Жок, рахмат"</string>
- <!-- no translation found for screen_pinning_start (7483998671383371313) -->
- <skip />
- <!-- no translation found for screen_pinning_exit (4553787518387346893) -->
- <skip />
+ <string name="screen_pinning_start" msgid="7483998671383371313">"Колдонмо кадалды"</string>
+ <string name="screen_pinning_exit" msgid="4553787518387346893">"Кадалган колдонмо бошотулду"</string>
<string name="quick_settings_reset_confirmation_title" msgid="463533331480997595">"<xliff:g id="TILE_LABEL">%1$s</xliff:g> жашырылсынбы?"</string>
<string name="quick_settings_reset_confirmation_message" msgid="2320586180785674186">"Бул кийинки жолу жөндөөлөрдөн күйгүзүлгөндө кайра көрүнөт."</string>
<string name="quick_settings_reset_confirmation_button" msgid="3341477479055016776">"Жашыруу"</string>
@@ -730,7 +719,7 @@
<string name="notification_channel_summary_priority" msgid="7952654515769021553">"Жазышуу бөлүмүнүн жогорку жагында калкып чыкма билдирме түрүндө көрүнүп, профиль сүрөтү кулпуланган экрандан чагылдырылат"</string>
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"Жөндөөлөр"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"Маанилүүлүгү"</string>
- <string name="no_shortcut" msgid="7176375126961212514">"<xliff:g id="APP_NAME">%1$s</xliff:g> колдонмосунда жазышууга болбойт"</string>
+ <string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> жазышуу функцияларын колдоого албайт"</string>
<string name="bubble_overflow_empty_title" msgid="3120029421991510842">"Акыркы калкып чыкма билдирмелер жок"</string>
<string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"Кайра жөнөтүлгөн жана жабылган калкып чыкма билдирмелер ушул жерде көрүнөт"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"Бул билдирмелерди өзгөртүүгө болбойт."</string>
@@ -867,7 +856,7 @@
<string name="left_icon" msgid="5036278531966897006">"¨Солго¨ сүрөтчөсү"</string>
<string name="right_icon" msgid="1103955040645237425">"¨Оңго¨ сүрөтчөсү"</string>
<string name="drag_to_add_tiles" msgid="8933270127508303672">"Керектүү элементтерди сүйрөп келиңиз"</string>
- <string name="drag_to_rearrange_tiles" msgid="2143204300089638620">"Элементтердин иретин өзгөртүү үчүн кармап туруп, сүйрөңүз"</string>
+ <string name="drag_to_rearrange_tiles" msgid="2143204300089638620">"Элементтердин иретин өзгөртүү үчүн, кармап туруп, сүйрөңүз"</string>
<string name="drag_to_remove_tiles" msgid="4682194717573850385">"Алып салуу үчүн бул жерге сүйрөңүз"</string>
<string name="drag_to_remove_disabled" msgid="933046987838658850">"Сизге жок дегенде <xliff:g id="MIN_NUM_TILES">%1$d</xliff:g> мозаика керек"</string>
<string name="qs_edit" msgid="5583565172803472437">"Түзөтүү"</string>
@@ -1013,7 +1002,8 @@
<string name="bubble_accessibility_action_move_top_right" msgid="6916868852433483569">"Жогорку оң жакка жылдырыңыз"</string>
<string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"Төмөнкү сол жакка жылдыруу"</string>
<string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"Төмөнкү оң жакка жылдырыңыз"</string>
- <string name="bubble_dismiss_text" msgid="7071770411580452911">"Жабуу"</string>
+ <!-- no translation found for bubble_dismiss_text (1314082410868930066) -->
+ <skip />
<string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"Жазышуу калкып чыкма билдирмеде көрүнбөсүн"</string>
<string name="bubbles_user_education_title" msgid="5547017089271445797">"Калкып чыкма билдирмелер аркылуу маектешүү"</string>
<string name="bubbles_user_education_description" msgid="1160281719576715211">"Жаңы жазышуулар калкыма сүрөтчөлөр же калкып чыкма билдирмелер болуп көрүнөт. Калкып чыкма билдирмелерди ачуу үчүн таптап коюңуз. Жылдыруу үчүн сүйрөңүз."</string>
@@ -1024,19 +1014,22 @@
<string name="notification_content_system_nav_changed" msgid="5077913144844684544">"Тутум чабыттоосу жаңырды. Өзгөртүү үчүн, Жөндөөлөргө өтүңүз."</string>
<string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"Тутум чабыттоосун жаңыртуу үчүн Жөндөөлөргө өтүңүз"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Көшүү режими"</string>
+ <string name="priority_onboarding_title" msgid="2893070698479227616">"Жазышуу маанилүү болуп коюлду"</string>
+ <string name="priority_onboarding_behavior" msgid="5342816047020432929">"Маанилүү жазышуулардын төмөнкүдөй артыкчылыктары бар:"</string>
<string name="priority_onboarding_show_at_top_text" msgid="1678400241025513541">"Жазышуу бөлүмүнүн үстүндө көрсөтүү"</string>
<string name="priority_onboarding_show_avatar_text" msgid="5756291381124091508">"Профилдин сүрөтүн кулпуланган экранда көрсөтүү"</string>
<string name="priority_onboarding_appear_as_bubble_text" msgid="4227039772250263122">"Калкым чыкма билдирме катары көрсөтүү"</string>
<string name="priority_onboarding_ignores_dnd_text" msgid="2918952762719600529">"\"Тынчымды алба\" режими үзгүлтүккө учурайт"</string>
<string name="priority_onboarding_done_button_title" msgid="4569550984286506007">"Түшүндүм"</string>
+ <string name="priority_onboarding_settings_button_title" msgid="6663601574303585927">"Жөндөөлөр"</string>
<string name="magnification_overlay_title" msgid="6584179429612427958">"Чоңойтуу терезесин үстүнө коюу"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"Чоңойтуу терезеси"</string>
<string name="magnification_controls_title" msgid="8421106606708891519">"Чоңойтуу терезесин башкаруу каражаттары"</string>
<string name="quick_controls_title" msgid="6839108006171302273">"Түзмөктү башкаруу элементтери"</string>
- <string name="quick_controls_subtitle" msgid="1667408093326318053">"Байланыштырылган түзмөктөрүңүз үчүн көзөмөлдөрдү кошуңуз"</string>
+ <string name="quick_controls_subtitle" msgid="1667408093326318053">"Байланышкан түзмөктөрүңүздү башкаруу элементтерин кошуңуз"</string>
<string name="quick_controls_setup_title" msgid="8901436655997849822">"Түзмөктү башкаруу элементтерин жөндөө"</string>
<string name="quick_controls_setup_subtitle" msgid="1681506617879773824">"Көзөмөлдөргө өтүү үчүн, күйгүзүү/өчүрүү баскычын басып туруңуз"</string>
- <string name="controls_providers_title" msgid="6879775889857085056">"Көзөмөлдөрдү кошуу үчүн колдонмо тандаңыз"</string>
+ <string name="controls_providers_title" msgid="6879775889857085056">"Башкаруу элементтери кошула турган колдонмону тандаңыз"</string>
<plurals name="controls_number_of_favorites" formatted="false" msgid="1057347832073807380">
<item quantity="other"><xliff:g id="NUMBER_1">%s</xliff:g> көзөмөл кошулду.</item>
<item quantity="one"><xliff:g id="NUMBER_0">%s</xliff:g> көзөмөл кошулду.</item>
@@ -1049,8 +1042,8 @@
<string name="accessibility_control_change_unfavorite" msgid="6997408061750740327">"сүйүктүүлөрдөн чыгаруу"</string>
<string name="accessibility_control_move" msgid="8980344493796647792">"<xliff:g id="NUMBER">%d</xliff:g>-позицияга жылдыруу"</string>
<string name="controls_favorite_default_title" msgid="967742178688938137">"Башкаруу элементтери"</string>
- <string name="controls_favorite_subtitle" msgid="6604402232298443956">"Күйгүзүү/өчүрүү баскычынын менюсу үчүн көзөмөлдөрдү тандаңыз"</string>
- <string name="controls_favorite_rearrange" msgid="5616952398043063519">"Башкаруу элементтеринин иретин өзгөртүү үчүн кармап туруп, сүйрөңүз"</string>
+ <string name="controls_favorite_subtitle" msgid="6604402232298443956">"Күйгүзүү/өчүрүү баскычынын менюсунда жеткиликтүү боло турган башкаруу элементтерин тандаңыз."</string>
+ <string name="controls_favorite_rearrange" msgid="5616952398043063519">"Башкаруу элементтеринин иретин өзгөртүү үчүн, кармап туруп, сүйрөңүз"</string>
<string name="controls_favorite_removed" msgid="5276978408529217272">"Бардык башкаруу элементтери өчүрүлдү"</string>
<string name="controls_favorite_toast_no_changes" msgid="7094494210840877931">"Өзгөртүүлөр сакталган жок"</string>
<string name="controls_favorite_load_error" msgid="2533215155804455348">"Бардык көзөмөлдөрдүн тизмеси жүктөлгөн жок."</string>
@@ -1059,7 +1052,7 @@
<string name="controls_dialog_ok" msgid="2770230012857881822">"Кошуу"</string>
<string name="controls_dialog_message" msgid="342066938390663844">"<xliff:g id="APP">%s</xliff:g> сунуштайт"</string>
<string name="controls_dialog_confirmation" msgid="586517302736263447">"Башкаруу элементтери жаңырды"</string>
- <string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"PIN код тамгаларды же символдорду камтыйт"</string>
+ <string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"PIN код тамгалардан же символдордон турат"</string>
<string name="controls_pin_verify" msgid="3452778292918877662">"<xliff:g id="DEVICE">%s</xliff:g> түзмөгүн ырастаңыз"</string>
<string name="controls_pin_wrong" msgid="6162694056042164211">"PIN код туура эмес"</string>
<string name="controls_pin_verifying" msgid="3755045989392131746">"Ырасталууда…"</string>
@@ -1070,13 +1063,17 @@
<string name="controls_structure_tooltip" msgid="4355922222944447867">"Дагы көрүү үчүн экранды сүрүп коюңуз"</string>
<string name="controls_seeding_in_progress" msgid="3033855341410264148">"Сунуштар жүктөлүүдө"</string>
<string name="controls_media_close_session" msgid="9023534788828414585">"Бул медиа сеансын жабуу"</string>
+ <string name="controls_media_resume" msgid="1933520684481586053">"Улантуу"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"Жигерсиз. Колдонмону текшериңиз"</string>
<string name="controls_error_retryable" msgid="864025882878378470">"Ката, дагы аракет жасалууда…"</string>
- <string name="controls_error_removed" msgid="6299213591234723805">"Түзмөктү көзөмөлдөө өчүрүлдү"</string>
+ <string name="controls_error_removed" msgid="6675638069846014366">"Табылган жок"</string>
+ <string name="controls_error_removed_title" msgid="1207794911208047818">"Көзөмөл жеткиликтүү эмес"</string>
+ <string name="controls_error_removed_message" msgid="2885911717034750542">"<xliff:g id="DEVICE">%1$s</xliff:g> түзмөгүнө кирүү мүмкүнчүлүгү жок. <xliff:g id="APPLICATION">%2$s</xliff:g> колдонмосуна өтүп, көзөмөл жеткиликтүү экенин жана колдонмонун жөндөөлөрү өзгөрбөгөнүн текшериңиз."</string>
+ <string name="controls_open_app" msgid="483650971094300141">"Колдонмону ачуу"</string>
<string name="controls_error_generic" msgid="352500456918362905">"Абалы жүктөлгөн жок"</string>
<string name="controls_error_failed" msgid="960228639198558525">"Ката, кайталап көрүңүз"</string>
<string name="controls_in_progress" msgid="4421080500238215939">"Аткарылууда"</string>
<string name="controls_added_tooltip" msgid="4842812921719153085">"Башкаруу элементтерин көрүү үчүн күйгүзүү/өчүрүү баскычын коё бербей басып туруңуз"</string>
- <string name="controls_menu_add" msgid="4447246119229920050">"Көзөмөлдөө функцияларын кошуу"</string>
- <string name="controls_menu_edit" msgid="890623986951347062">"Көзөмөлдөө функцияларын түзөтүү"</string>
+ <string name="controls_menu_add" msgid="4447246119229920050">"Башкаруу элементтерин кошуу"</string>
+ <string name="controls_menu_edit" msgid="890623986951347062">"Башкаруу элементтерин түзөтүү"</string>
</resources>
diff --git a/packages/SystemUI/res/values-lo/strings.xml b/packages/SystemUI/res/values-lo/strings.xml
index a59716c4be06..829d39aac864 100644
--- a/packages/SystemUI/res/values-lo/strings.xml
+++ b/packages/SystemUI/res/values-lo/strings.xml
@@ -77,9 +77,6 @@
<string name="compat_mode_on" msgid="4963711187149440884">"ຊູມໃຫ້ເຕັມໜ້າຈໍ"</string>
<string name="compat_mode_off" msgid="7682459748279487945">"ປັບໃຫ້ເຕັມໜ້າຈໍ"</string>
<string name="global_action_screenshot" msgid="2760267567509131654">"ພາບໜ້າຈໍ"</string>
- <string name="global_action_lock_message" product="default" msgid="4466026255205186456">"ປົດລັອກໂທລະສັບຂອງທ່ານເພື່ອໃຊ້ຕົວເລືອກເພີ່ມເຕີມ"</string>
- <string name="global_action_lock_message" product="tablet" msgid="7621167597240332986">"ປົດລັອກແທັບເລັດຂອງທ່ານເພື່ອໃຊ້ຕົວເລືອກເພີ່ມເຕີມ"</string>
- <string name="global_action_lock_message" product="device" msgid="538790401275363781">"ປົດລັອກອຸປະກອນຂອງທ່ານເພື່ອໃຊ້ຕົວເລືອກເພີ່ມເຕີມ"</string>
<string name="remote_input_image_insertion_text" msgid="4850791636452521123">"ສົ່ງຮູບແລ້ວ"</string>
<string name="screenshot_saving_ticker" msgid="6519186952674544916">"ກຳລັງບັນທຶກຮູບໜ້າຈໍ"</string>
<string name="screenshot_saving_title" msgid="2298349784913287333">"ກຳລັງບັນທຶກພາບໜ້າຈໍ..."</string>
@@ -722,7 +719,7 @@
<string name="notification_channel_summary_priority" msgid="7952654515769021553">"ສະແດງຢູ່ເທິງສຸດຂອງພາກສ່ວນການສົນທະນາ, ປາກົດເປັນ bubble ແບບລອຍ, ສະແດງຮູບໂປຣໄຟລ໌ຢູ່ໜ້າຈໍລັອກ"</string>
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"ຕັ້ງຄ່າ"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"ສຳຄັນ"</string>
- <string name="no_shortcut" msgid="7176375126961212514">"<xliff:g id="APP_NAME">%1$s</xliff:g> ບໍ່ຮອງຮັບການຕັ້ງຄ່າສະເພາະຂອງການສົນທະນາ"</string>
+ <string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> ບໍ່ຮອງຮັບຄຸນສົມບັດການສົນທະນາ"</string>
<string name="bubble_overflow_empty_title" msgid="3120029421991510842">"ບໍ່ມີຟອງຫຼ້າສຸດ"</string>
<string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"ຟອງຫຼ້າສຸດ ແລະ ຟອງທີ່ປິດໄປຈະປາກົດຢູ່ບ່ອນນີ້"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"ບໍ່ສາມາດແກ້ໄຂການແຈ້ງເຕືອນເຫຼົ່ານີ້ໄດ້."</string>
@@ -1005,7 +1002,8 @@
<string name="bubble_accessibility_action_move_top_right" msgid="6916868852433483569">"ຍ້າຍຂວາເທິງ"</string>
<string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"ຍ້າຍຊ້າຍລຸ່ມ"</string>
<string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"ຍ້າຍຂວາລຸ່ມ"</string>
- <string name="bubble_dismiss_text" msgid="7071770411580452911">"ປິດໄວ້"</string>
+ <!-- no translation found for bubble_dismiss_text (1314082410868930066) -->
+ <skip />
<string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"ຢ່າໃຊ້ຟອງໃນການສົນທະນາ"</string>
<string name="bubbles_user_education_title" msgid="5547017089271445797">"ສົນທະນາໂດຍໃຊ້ຟອງ"</string>
<string name="bubbles_user_education_description" msgid="1160281719576715211">"ການສົນທະນາໃໝ່ຈະປາກົດເປັນໄອຄອນ ຫຼື ຟອງແບບລອຍ. ແຕະເພື່ອເປີດຟອງ. ລາກເພື່ອຍ້າຍມັນ."</string>
@@ -1016,11 +1014,14 @@
<string name="notification_content_system_nav_changed" msgid="5077913144844684544">"ອັບເດດການນຳທາງລະບົບແລ້ວ. ເພື່ອປ່ຽນແປງ, ກະລຸນາໄປທີ່ການຕັ້ງຄ່າ."</string>
<string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"ໄປທີ່ການຕັ້ງຄ່າເພື່ອອັບເດດການນຳທາງລະບົບ"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"ສະແຕນບາຍ"</string>
+ <string name="priority_onboarding_title" msgid="2893070698479227616">"ຕັ້ງການສົນທະນາເປັນສຳຄັນແລ້ວ"</string>
+ <string name="priority_onboarding_behavior" msgid="5342816047020432929">"ການສົນທະນາສຳຄັນຈະ:"</string>
<string name="priority_onboarding_show_at_top_text" msgid="1678400241025513541">"ສະແດງຢູ່ເທິງສຸດຂອງພາກສ່ວນການສົນທະນາ"</string>
<string name="priority_onboarding_show_avatar_text" msgid="5756291381124091508">"ສະແດງຮູບໂປຣໄຟລ໌ຢູ່ໜ້າຈໍລັອກ"</string>
<string name="priority_onboarding_appear_as_bubble_text" msgid="4227039772250263122">"ປາກົດເປັນ bubble ລອຍຢູ່ເໜືອແອັບ"</string>
<string name="priority_onboarding_ignores_dnd_text" msgid="2918952762719600529">"ລົບກວນໂໝດຫ້າມລົບກວນ"</string>
<string name="priority_onboarding_done_button_title" msgid="4569550984286506007">"ເຂົ້າໃຈແລ້ວ"</string>
+ <string name="priority_onboarding_settings_button_title" msgid="6663601574303585927">"ການຕັ້ງຄ່າ"</string>
<string name="magnification_overlay_title" msgid="6584179429612427958">"ໜ້າຈໍວາງທັບການຂະຫຍາຍ"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"ໜ້າຈໍການຂະຫຍາຍ"</string>
<string name="magnification_controls_title" msgid="8421106606708891519">"ການຄວບຄຸມໜ້າຈໍການຂະຫຍາຍ"</string>
@@ -1062,9 +1063,13 @@
<string name="controls_structure_tooltip" msgid="4355922222944447867">"ປັດເພື່ອເບິ່ງເພີ່ມເຕີມ"</string>
<string name="controls_seeding_in_progress" msgid="3033855341410264148">"ກຳລັງໂຫຼດຄຳແນະນຳ"</string>
<string name="controls_media_close_session" msgid="9023534788828414585">"ປິດເຊດຊັນມີເດຍນີ້"</string>
+ <string name="controls_media_resume" msgid="1933520684481586053">"ສືບຕໍ່"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"ບໍ່ເຮັດວຽກ, ກະລຸນາກວດສອບແອັບ"</string>
<string name="controls_error_retryable" msgid="864025882878378470">"ຜິດພາດ, ກໍາລັງ​ລອງ​ໃໝ່…"</string>
- <string name="controls_error_removed" msgid="6299213591234723805">"ລຶບອຸປະກອນອອກແລ້ວ"</string>
+ <string name="controls_error_removed" msgid="6675638069846014366">"ບໍ່ພົບ"</string>
+ <string name="controls_error_removed_title" msgid="1207794911208047818">"ບໍ່ສາມາດໃຊ້ການຄວບຄຸມໄດ້"</string>
+ <string name="controls_error_removed_message" msgid="2885911717034750542">"ບໍ່ສາມາດເຂົ້າເຖິງ <xliff:g id="DEVICE">%1$s</xliff:g> ໄດ້. ກະລຸນາກວດສອບແອັບ <xliff:g id="APPLICATION">%2$s</xliff:g> ເພື່ອເບິ່ງວ່າຍັງສາມາດໃຊ້ການຄວບຄຸມໄດ້ຫຼືບໍ່ ແລະ ຍັງບໍ່ໄດ້ປ່ຽນການຕັ້ງຄ່າແອັບເທື່ອ."</string>
+ <string name="controls_open_app" msgid="483650971094300141">"ເປີດແອັບ"</string>
<string name="controls_error_generic" msgid="352500456918362905">"ບໍ່ສາມາດໂຫຼດສະຖານະໄດ້"</string>
<string name="controls_error_failed" msgid="960228639198558525">"​ຜິດ​ພາດ​, ກະລຸນາລອງໃໝ່"</string>
<string name="controls_in_progress" msgid="4421080500238215939">"ກຳລັງດຳເນີນການຢູ່"</string>
diff --git a/packages/SystemUI/res/values-lt/strings.xml b/packages/SystemUI/res/values-lt/strings.xml
index 1c51b8662fa3..de793947a037 100644
--- a/packages/SystemUI/res/values-lt/strings.xml
+++ b/packages/SystemUI/res/values-lt/strings.xml
@@ -77,9 +77,6 @@
<string name="compat_mode_on" msgid="4963711187149440884">"Keisti mast., kad atit. ekr."</string>
<string name="compat_mode_off" msgid="7682459748279487945">"Ištempti, kad atit. ekr."</string>
<string name="global_action_screenshot" msgid="2760267567509131654">"Ekrano kopija"</string>
- <string name="global_action_lock_message" product="default" msgid="4466026255205186456">"Atrakinkite telefoną, kad galėtumėte naudoti daugiau parinkčių"</string>
- <string name="global_action_lock_message" product="tablet" msgid="7621167597240332986">"Atrakinkite planšetinį kompiuterį, kad galėtumėte naudoti daugiau parinkčių"</string>
- <string name="global_action_lock_message" product="device" msgid="538790401275363781">"Atrakinkite įrenginį, kad galėtumėte naudoti daugiau parinkčių"</string>
<string name="remote_input_image_insertion_text" msgid="4850791636452521123">"išsiuntė vaizdą"</string>
<string name="screenshot_saving_ticker" msgid="6519186952674544916">"Išsaugoma ekrano kopija..."</string>
<string name="screenshot_saving_title" msgid="2298349784913287333">"Išsaugoma ekrano kopija..."</string>
@@ -601,29 +598,21 @@
<string name="volume_odi_captions_hint_enable" msgid="2073091194012843195">"įgalinti"</string>
<string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"išjungti"</string>
<string name="accessibility_output_chooser" msgid="7807898688967194183">"Perjungti išvesties įrenginį"</string>
- <!-- no translation found for screen_pinning_title (9058007390337841305) -->
- <skip />
+ <string name="screen_pinning_title" msgid="9058007390337841305">"Programa prisegta"</string>
<string name="screen_pinning_description" msgid="8699395373875667743">"Tai bus rodoma, kol atsegsite. Palieskite ir palaikykite „Atgal“ ir „Apžvalga“, kad atsegtumėte."</string>
<string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"Tai bus rodoma, kol atsegsite. Palieskite ir palaikykite „Atgal“ ir „Pagrindinis ekranas“, kad atsegtumėte."</string>
<string name="screen_pinning_description_gestural" msgid="7246323931831232068">"Tai bus rodoma, kol atsegsite. Perbraukite aukštyn ir palaikykite, kad atsegtumėte."</string>
<string name="screen_pinning_description_accessible" msgid="7386449191953535332">"Tai bus rodoma, kol atsegsite. Palieskite ir palaikykite „Apžvalga“, kad atsegtumėte."</string>
<string name="screen_pinning_description_recents_invisible_accessible" msgid="2857071808674481986">"Tai bus rodoma, kol atsegsite. Palieskite ir palaikykite „Pagrindinis ekranas“, kad atsegtumėte."</string>
- <!-- no translation found for screen_pinning_exposes_personal_data (8189852022981524789) -->
- <skip />
- <!-- no translation found for screen_pinning_can_open_other_apps (7529756813231421455) -->
- <skip />
- <!-- no translation found for screen_pinning_toast (8177286912533744328) -->
- <skip />
- <!-- no translation found for screen_pinning_toast_recents_invisible (6850978077443052594) -->
- <skip />
- <!-- no translation found for screen_pinning_toast_gesture_nav (170699893395336705) -->
- <skip />
+ <string name="screen_pinning_exposes_personal_data" msgid="8189852022981524789">"Gali būti pasiekiami asmens duomenys (pvz., kontaktai ir el. pašto turinys)."</string>
+ <string name="screen_pinning_can_open_other_apps" msgid="7529756813231421455">"Prisegta programa gali atidaryti kitas programas."</string>
+ <string name="screen_pinning_toast" msgid="8177286912533744328">"Kad atsegtumėte šią programą, palieskite ir palaikykite mygtukus „Atgal“ ir „Apžvalga“"</string>
+ <string name="screen_pinning_toast_recents_invisible" msgid="6850978077443052594">"Kad atsegtumėte šią programą, palieskite ir palaikykite mygtuką „Atgal“ ir pagrindinio ekrano mygtuką"</string>
+ <string name="screen_pinning_toast_gesture_nav" msgid="170699893395336705">"Kad atsegtumėte šią programą, perbraukite aukštyn ir palaikykite"</string>
<string name="screen_pinning_positive" msgid="3285785989665266984">"Supratau"</string>
<string name="screen_pinning_negative" msgid="6882816864569211666">"Ne, ačiū"</string>
- <!-- no translation found for screen_pinning_start (7483998671383371313) -->
- <skip />
- <!-- no translation found for screen_pinning_exit (4553787518387346893) -->
- <skip />
+ <string name="screen_pinning_start" msgid="7483998671383371313">"Programa prisegta"</string>
+ <string name="screen_pinning_exit" msgid="4553787518387346893">"Programa atsegta"</string>
<string name="quick_settings_reset_confirmation_title" msgid="463533331480997595">"Slėpti „<xliff:g id="TILE_LABEL">%1$s</xliff:g>“?"</string>
<string name="quick_settings_reset_confirmation_message" msgid="2320586180785674186">"Tai bus vėl parodyta, kai kitą kartą įjungsite tai nustatymuose."</string>
<string name="quick_settings_reset_confirmation_button" msgid="3341477479055016776">"Slėpti"</string>
@@ -736,7 +725,7 @@
<string name="notification_channel_summary_priority" msgid="7952654515769021553">"Rodoma pokalbių skilties viršuje, rodoma kaip slankusis burbulas, pateikiama profilio nuotrauka užrakinimo ekrane"</string>
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"Nustatymai"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"Prioritetas"</string>
- <string name="no_shortcut" msgid="7176375126961212514">"Programa „<xliff:g id="APP_NAME">%1$s</xliff:g>“ nepalaiko konkrečių pokalbių nustatymų"</string>
+ <string name="no_shortcut" msgid="8257177117568230126">"Programa „<xliff:g id="APP_NAME">%1$s</xliff:g>“ nepalaiko pokalbių funkcijų"</string>
<string name="bubble_overflow_empty_title" msgid="3120029421991510842">"Nėra naujausių burbulų"</string>
<string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"Naujausi ir atsisakyti burbulus bus rodomi čia"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"Šių pranešimų keisti negalima."</string>
@@ -1023,7 +1012,8 @@
<string name="bubble_accessibility_action_move_top_right" msgid="6916868852433483569">"Perkelti į viršų dešinėje"</string>
<string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"Perkelti į apačią kairėje"</string>
<string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"Perkelti į apačią dešinėje"</string>
- <string name="bubble_dismiss_text" msgid="7071770411580452911">"Atmesti"</string>
+ <!-- no translation found for bubble_dismiss_text (1314082410868930066) -->
+ <skip />
<string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"Nerodyti pokalbio burbule"</string>
<string name="bubbles_user_education_title" msgid="5547017089271445797">"Pokalbis naudojant burbulus"</string>
<string name="bubbles_user_education_description" msgid="1160281719576715211">"Nauji pokalbiai rodomi kaip slankiosios piktogramos arba burbulus. Palieskite, kad atidarytumėte burbulą. Vilkite, kad perkeltumėte."</string>
@@ -1034,11 +1024,14 @@
<string name="notification_content_system_nav_changed" msgid="5077913144844684544">"Sistemos naršymo funkcijos atnaujintos. Jei norite pakeisti, eikite į skiltį „Nustatymai“."</string>
<string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"Eikite į skiltį „Nustatymai“, kad atnaujintumėte sistemos naršymo funkcijas"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Budėjimo laikas"</string>
+ <string name="priority_onboarding_title" msgid="2893070698479227616">"Pokalbis nustatytas į prioritetinį"</string>
+ <string name="priority_onboarding_behavior" msgid="5342816047020432929">"Prioritetiniai pokalbiai bus:"</string>
<string name="priority_onboarding_show_at_top_text" msgid="1678400241025513541">"Rodyti pokalbių skilties viršuje"</string>
<string name="priority_onboarding_show_avatar_text" msgid="5756291381124091508">"Rodyti profilio nuotrauką užrakinimo ekrane"</string>
<string name="priority_onboarding_appear_as_bubble_text" msgid="4227039772250263122">"Rodyti kaip slankųjį debesėlį programų viršuje"</string>
<string name="priority_onboarding_ignores_dnd_text" msgid="2918952762719600529">"Pertraukti netrukdymo režimą"</string>
<string name="priority_onboarding_done_button_title" msgid="4569550984286506007">"Supratau"</string>
+ <string name="priority_onboarding_settings_button_title" msgid="6663601574303585927">"Nustatymai"</string>
<string name="magnification_overlay_title" msgid="6584179429612427958">"Didinimo perdangos langas"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"Didinimo langas"</string>
<string name="magnification_controls_title" msgid="8421106606708891519">"Didinimo lango valdikliai"</string>
@@ -1082,9 +1075,13 @@
<string name="controls_structure_tooltip" msgid="4355922222944447867">"Perbraukite, kad peržiūrėtumėte daugiau"</string>
<string name="controls_seeding_in_progress" msgid="3033855341410264148">"Įkeliamos rekomendacijos"</string>
<string name="controls_media_close_session" msgid="9023534788828414585">"Uždaryti šį medijos seansą"</string>
+ <string name="controls_media_resume" msgid="1933520684481586053">"Tęsti"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"Neaktyvu, patikrinkite progr."</string>
<string name="controls_error_retryable" msgid="864025882878378470">"Klaida, bandoma iš naujo…"</string>
- <string name="controls_error_removed" msgid="6299213591234723805">"Įrenginys pašalintas"</string>
+ <string name="controls_error_removed" msgid="6675638069846014366">"Nerasta"</string>
+ <string name="controls_error_removed_title" msgid="1207794911208047818">"Valdiklis nepasiekiamas"</string>
+ <string name="controls_error_removed_message" msgid="2885911717034750542">"Nepavyko pasiekti: <xliff:g id="DEVICE">%1$s</xliff:g>. Eikite į programą „<xliff:g id="APPLICATION">%2$s</xliff:g>“ ir įsitikinkite, kad valdiklis vis dar pasiekiamas ir kad programos nustatymai nepakeisti."</string>
+ <string name="controls_open_app" msgid="483650971094300141">"Atidaryti programą"</string>
<string name="controls_error_generic" msgid="352500456918362905">"Nepavyko įkelti būsenos"</string>
<string name="controls_error_failed" msgid="960228639198558525">"Klaida, bandykite dar kartą"</string>
<string name="controls_in_progress" msgid="4421080500238215939">"Vyksta"</string>
diff --git a/packages/SystemUI/res/values-lv/strings.xml b/packages/SystemUI/res/values-lv/strings.xml
index db20f065820b..ba6b8954f655 100644
--- a/packages/SystemUI/res/values-lv/strings.xml
+++ b/packages/SystemUI/res/values-lv/strings.xml
@@ -77,9 +77,6 @@
<string name="compat_mode_on" msgid="4963711187149440884">"Tālumm., lai aizp. ekr."</string>
<string name="compat_mode_off" msgid="7682459748279487945">"Stiepiet, lai aizp. ekr."</string>
<string name="global_action_screenshot" msgid="2760267567509131654">"Ekrānuzņēmums"</string>
- <string name="global_action_lock_message" product="default" msgid="4466026255205186456">"Atbloķējiet tālruni, lai skatītu citas opcijas."</string>
- <string name="global_action_lock_message" product="tablet" msgid="7621167597240332986">"Atbloķējiet planšetdatoru, lai skatītu citas opcijas."</string>
- <string name="global_action_lock_message" product="device" msgid="538790401275363781">"Atbloķējiet ierīci, lai skatītu citas opcijas."</string>
<string name="remote_input_image_insertion_text" msgid="4850791636452521123">"nosūtīts attēls"</string>
<string name="screenshot_saving_ticker" msgid="6519186952674544916">"Saglabā ekrānuzņēmumu…"</string>
<string name="screenshot_saving_title" msgid="2298349784913287333">"Notiek ekrānuzņēmuma saglabāšana..."</string>
@@ -725,7 +722,7 @@
<string name="notification_channel_summary_priority" msgid="7952654515769021553">"Parādās sarunu sadaļas augšdaļā un kā peldošs burbulis, kā arī bloķēšanas ekrānā tiek rādīts profila attēls"</string>
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"Iestatījumi"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"Prioritārs"</string>
- <string name="no_shortcut" msgid="7176375126961212514">"Lietotnē <xliff:g id="APP_NAME">%1$s</xliff:g> netiek atbalstīti atsevišķu sarunu iestatījumi."</string>
+ <string name="no_shortcut" msgid="8257177117568230126">"Lietotnē <xliff:g id="APP_NAME">%1$s</xliff:g> netiek atbalstītas sarunu funkcijas."</string>
<string name="bubble_overflow_empty_title" msgid="3120029421991510842">"Nav nesen aizvērtu burbuļu"</string>
<string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"Šeit būs redzami nesen rādītie burbuļi un aizvērtie burbuļi"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"Šos paziņojumus nevar modificēt."</string>
@@ -1010,7 +1007,8 @@
<string name="bubble_accessibility_action_move_top_right" msgid="6916868852433483569">"Pārvietot augšpusē pa labi"</string>
<string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"Pārvietot apakšpusē pa kreisi"</string>
<string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"Pārvietot apakšpusē pa labi"</string>
- <string name="bubble_dismiss_text" msgid="7071770411580452911">"Nerādīt"</string>
+ <!-- no translation found for bubble_dismiss_text (1314082410868930066) -->
+ <skip />
<string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"Nerādīt sarunu burbuļos"</string>
<string name="bubbles_user_education_title" msgid="5547017089271445797">"Tērzēšana, izmantojot burbuļus"</string>
<string name="bubbles_user_education_description" msgid="1160281719576715211">"Jaunas sarunas tiek rādītas kā peldošas ikonas vai burbuļi. Pieskarieties, lai atvērtu burbuli. Velciet, lai to pārvietotu."</string>
@@ -1021,11 +1019,14 @@
<string name="notification_content_system_nav_changed" msgid="5077913144844684544">"Sistēmas navigācija ir atjaunināta. Lai veiktu izmaiņas, atveriet iestatījumus."</string>
<string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"Atveriet iestatījumus, lai atjauninātu sistēmas navigāciju"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Gaidstāve"</string>
+ <string name="priority_onboarding_title" msgid="2893070698479227616">"Saruna iestatīta kā prioritāra"</string>
+ <string name="priority_onboarding_behavior" msgid="5342816047020432929">"Prioritārās sarunas:"</string>
<string name="priority_onboarding_show_at_top_text" msgid="1678400241025513541">"Tiek rādītas sarunu sadaļas augšdaļā"</string>
<string name="priority_onboarding_show_avatar_text" msgid="5756291381124091508">"Tiek rādīts profila attēls bloķēšanas ekrānā"</string>
<string name="priority_onboarding_appear_as_bubble_text" msgid="4227039772250263122">"Tiek rādītas kā peldošs burbulis virs lietotnēm"</string>
<string name="priority_onboarding_ignores_dnd_text" msgid="2918952762719600529">"Var tikt rādītas režīmā “Netraucēt”"</string>
<string name="priority_onboarding_done_button_title" msgid="4569550984286506007">"Labi"</string>
+ <string name="priority_onboarding_settings_button_title" msgid="6663601574303585927">"Iestatījumi"</string>
<string name="magnification_overlay_title" msgid="6584179429612427958">"Palielināšanas pārklājuma logs"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"Palielināšanas logs"</string>
<string name="magnification_controls_title" msgid="8421106606708891519">"Palielināšanas loga vadīklas"</string>
@@ -1068,9 +1069,13 @@
<string name="controls_structure_tooltip" msgid="4355922222944447867">"Velciet, lai skatītu citus vienumus"</string>
<string name="controls_seeding_in_progress" msgid="3033855341410264148">"Notiek ieteikumu ielāde"</string>
<string name="controls_media_close_session" msgid="9023534788828414585">"Aizvērt multivides sesiju"</string>
+ <string name="controls_media_resume" msgid="1933520684481586053">"Atsākt"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"Neaktīva, pārbaudiet lietotni"</string>
<string name="controls_error_retryable" msgid="864025882878378470">"Radās kļūda. Mēģina vēlreiz…"</string>
- <string name="controls_error_removed" msgid="6299213591234723805">"Ierīce ir noņemta."</string>
+ <string name="controls_error_removed" msgid="6675638069846014366">"Netika atrasta"</string>
+ <string name="controls_error_removed_title" msgid="1207794911208047818">"Vadīkla nav pieejama"</string>
+ <string name="controls_error_removed_message" msgid="2885911717034750542">"Nevarēja piekļūt ierīcei “<xliff:g id="DEVICE">%1$s</xliff:g>”. Lietotnē <xliff:g id="APPLICATION">%2$s</xliff:g> pārbaudiet, vai vadīkla joprojām ir pieejama un vai nav mainīti lietotnes iestatījumi."</string>
+ <string name="controls_open_app" msgid="483650971094300141">"Atvērt lietotni"</string>
<string name="controls_error_generic" msgid="352500456918362905">"Nevar ielādēt statusu."</string>
<string name="controls_error_failed" msgid="960228639198558525">"Radās kļūda. Mēģiniet vēlreiz."</string>
<string name="controls_in_progress" msgid="4421080500238215939">"Sākta"</string>
diff --git a/packages/SystemUI/res/values-mk/strings.xml b/packages/SystemUI/res/values-mk/strings.xml
index a897a8f492e3..522cebd8ea6c 100644
--- a/packages/SystemUI/res/values-mk/strings.xml
+++ b/packages/SystemUI/res/values-mk/strings.xml
@@ -77,9 +77,6 @@
<string name="compat_mode_on" msgid="4963711187149440884">"Зумирај да се исполни екранот"</string>
<string name="compat_mode_off" msgid="7682459748279487945">"Растегни да се исполни екранот"</string>
<string name="global_action_screenshot" msgid="2760267567509131654">"Слика од екранот"</string>
- <string name="global_action_lock_message" product="default" msgid="4466026255205186456">"Отклучето го вашиот телефон за повеќе опции"</string>
- <string name="global_action_lock_message" product="tablet" msgid="7621167597240332986">"Отклучето го вашиот таблет за повеќе опции"</string>
- <string name="global_action_lock_message" product="device" msgid="538790401275363781">"Отклучето го вашиот уред за повеќе опции"</string>
<string name="remote_input_image_insertion_text" msgid="4850791636452521123">"испрати слика"</string>
<string name="screenshot_saving_ticker" msgid="6519186952674544916">"Сликата на екранот се зачувува..."</string>
<string name="screenshot_saving_title" msgid="2298349784913287333">"Сликата на екранот се зачувува..."</string>
@@ -514,7 +511,7 @@
<string name="manage_notifications_text" msgid="6885645344647733116">"Управувајте"</string>
<string name="manage_notifications_history_text" msgid="57055985396576230">"Историја"</string>
<string name="notification_section_header_incoming" msgid="5295312809341711367">"Дојдовни"</string>
- <string name="notification_section_header_gentle" msgid="6804099527336337197">"Тивко"</string>
+ <string name="notification_section_header_gentle" msgid="6804099527336337197">"Безгласно"</string>
<string name="notification_section_header_alerting" msgid="5581175033680477651">"Известувања"</string>
<string name="notification_section_header_conversations" msgid="821834744538345661">"Разговори"</string>
<string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"Избриши ги сите тивки известувања"</string>
@@ -595,29 +592,21 @@
<string name="volume_odi_captions_hint_enable" msgid="2073091194012843195">"овозможи"</string>
<string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"оневозможи"</string>
<string name="accessibility_output_chooser" msgid="7807898688967194183">"Префрлете го излезниот уред"</string>
- <!-- no translation found for screen_pinning_title (9058007390337841305) -->
- <skip />
+ <string name="screen_pinning_title" msgid="9058007390337841305">"Апликацијата е прикачена"</string>
<string name="screen_pinning_description" msgid="8699395373875667743">"Ќе се гледа сѐ додека не го откачите. Допрете и држете „Назад“ и „Краток преглед“ за откачување."</string>
<string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"Ќе се гледа сѐ додека не го откачите. Допрете и задржете „Назад“ и „Почетен екран“ за откачување."</string>
<string name="screen_pinning_description_gestural" msgid="7246323931831232068">"Ќе се гледа сѐ додека не го откачите. Лизгајте нагоре и задржете за откачување."</string>
<string name="screen_pinning_description_accessible" msgid="7386449191953535332">"Ќе се гледа сѐ додека не го откачите. Допрете и држете „Краток преглед“ за откачување."</string>
<string name="screen_pinning_description_recents_invisible_accessible" msgid="2857071808674481986">"Ќе се гледа сѐ додека не го откачите. Допрете и задржете „Почетен екран“ за откачување."</string>
- <!-- no translation found for screen_pinning_exposes_personal_data (8189852022981524789) -->
- <skip />
- <!-- no translation found for screen_pinning_can_open_other_apps (7529756813231421455) -->
- <skip />
- <!-- no translation found for screen_pinning_toast (8177286912533744328) -->
- <skip />
- <!-- no translation found for screen_pinning_toast_recents_invisible (6850978077443052594) -->
- <skip />
- <!-- no translation found for screen_pinning_toast_gesture_nav (170699893395336705) -->
- <skip />
+ <string name="screen_pinning_exposes_personal_data" msgid="8189852022981524789">"Личните податоци може да се пристапни (како контакти и содржини од е-пошта)."</string>
+ <string name="screen_pinning_can_open_other_apps" msgid="7529756813231421455">"Прикачените апликации може да отворат други апликации."</string>
+ <string name="screen_pinning_toast" msgid="8177286912533744328">"За откачување на апликацијава, допрете и држете на копчињата „Назад“ и „Преглед“"</string>
+ <string name="screen_pinning_toast_recents_invisible" msgid="6850978077443052594">"За откачување на апликацијава, допрете и држете на копчињата „Назад“ и „Почетен екран“"</string>
+ <string name="screen_pinning_toast_gesture_nav" msgid="170699893395336705">"За откачување на апликацијава, повлечете нагоре и држете"</string>
<string name="screen_pinning_positive" msgid="3285785989665266984">"Сфатив"</string>
<string name="screen_pinning_negative" msgid="6882816864569211666">"Не, фала"</string>
- <!-- no translation found for screen_pinning_start (7483998671383371313) -->
- <skip />
- <!-- no translation found for screen_pinning_exit (4553787518387346893) -->
- <skip />
+ <string name="screen_pinning_start" msgid="7483998671383371313">"Апликацијата е прикачена"</string>
+ <string name="screen_pinning_exit" msgid="4553787518387346893">"Апликацијата е откачена"</string>
<string name="quick_settings_reset_confirmation_title" msgid="463533331480997595">"Сокриј <xliff:g id="TILE_LABEL">%1$s</xliff:g>?"</string>
<string name="quick_settings_reset_confirmation_message" msgid="2320586180785674186">"Ќе се појави повторно следниот пат кога ќе го вклучите во поставки."</string>
<string name="quick_settings_reset_confirmation_button" msgid="3341477479055016776">"Сокриј"</string>
@@ -713,13 +702,13 @@
<string name="inline_block_button" msgid="479892866568378793">"Блокирај"</string>
<string name="inline_keep_button" msgid="299631874103662170">"Продолжи да ги прикажуваш"</string>
<string name="inline_minimize_button" msgid="1474436209299333445">"Минимизирај"</string>
- <string name="inline_silent_button_silent" msgid="525243786649275816">"Тивко"</string>
+ <string name="inline_silent_button_silent" msgid="525243786649275816">"Безгласно"</string>
<string name="inline_silent_button_stay_silent" msgid="2129254868305468743">"Продолжи со безгласно прикажување"</string>
<string name="inline_silent_button_alert" msgid="5705343216858250354">"Предупредувај"</string>
<string name="inline_silent_button_keep_alerting" msgid="6577845442184724992">"Продолжи да ме предупредуваш"</string>
<string name="inline_turn_off_notifications" msgid="8543989584403106071">"Исклучи известувања"</string>
<string name="inline_keep_showing_app" msgid="4393429060390649757">"Дали да продолжат да се прикажуваат известувања од апликацијава?"</string>
- <string name="notification_silence_title" msgid="8608090968400832335">"Тивко"</string>
+ <string name="notification_silence_title" msgid="8608090968400832335">"Безгласно"</string>
<string name="notification_alert_title" msgid="3656229781017543655">"Стандардно"</string>
<string name="notification_bubble_title" msgid="8330481035191903164">"Балонче"</string>
<string name="notification_channel_summary_low" msgid="4860617986908931158">"Без звук или вибрации"</string>
@@ -730,7 +719,7 @@
<string name="notification_channel_summary_priority" msgid="7952654515769021553">"Се појавува на горниот дел од секцијата на разговорот во вид на лебдечко меурче, покажувајќи ја профилната слика на заклучениот екран"</string>
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"Поставки"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"Приоритет"</string>
- <string name="no_shortcut" msgid="7176375126961212514">"<xliff:g id="APP_NAME">%1$s</xliff:g> не поддржува поставки поврзани со разговорите"</string>
+ <string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> не поддржува функции за разговор"</string>
<string name="bubble_overflow_empty_title" msgid="3120029421991510842">"Нема неодамнешни балончиња"</string>
<string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"Неодамнешните и отфрлените балончиња ќе се појавуваат тука"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"Овие известувања не може да се изменат"</string>
@@ -1013,7 +1002,8 @@
<string name="bubble_accessibility_action_move_top_right" msgid="6916868852433483569">"Премести горе десно"</string>
<string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"Премести долу лево"</string>
<string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"Премести долу десно"</string>
- <string name="bubble_dismiss_text" msgid="7071770411580452911">"Отфрли"</string>
+ <!-- no translation found for bubble_dismiss_text (1314082410868930066) -->
+ <skip />
<string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"Не прикажувај го разговорот во балончиња"</string>
<string name="bubbles_user_education_title" msgid="5547017089271445797">"Разговор во балончиња"</string>
<string name="bubbles_user_education_description" msgid="1160281719576715211">"Новите разговори ќе се појавуваат како лебдечки икони или балончиња. Допрете за отворање на балончето. Повлечете за да го преместите."</string>
@@ -1024,11 +1014,14 @@
<string name="notification_content_system_nav_changed" msgid="5077913144844684544">"Навигацијата на системот е ажурирана. За да извршите промени, одете во „Поставки“."</string>
<string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"Одете во „Поставки“ за да ја ажурирате навигацијата на системот"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Подготвеност"</string>
+ <string name="priority_onboarding_title" msgid="2893070698479227616">"Разговорот е поставен како приоритетен"</string>
+ <string name="priority_onboarding_behavior" msgid="5342816047020432929">"Приорететните разговори ќе:"</string>
<string name="priority_onboarding_show_at_top_text" msgid="1678400241025513541">"Се прикажува најгоре во делот со разговори"</string>
<string name="priority_onboarding_show_avatar_text" msgid="5756291381124091508">"Се прикажува профилна слика на заклучен екран"</string>
<string name="priority_onboarding_appear_as_bubble_text" msgid="4227039772250263122">"Се појавува како лебдечко балонче врз апликациите"</string>
<string name="priority_onboarding_ignores_dnd_text" msgid="2918952762719600529">"Прекинува „Не вознемирувај“"</string>
<string name="priority_onboarding_done_button_title" msgid="4569550984286506007">"Сфатив"</string>
+ <string name="priority_onboarding_settings_button_title" msgid="6663601574303585927">"Поставки"</string>
<string name="magnification_overlay_title" msgid="6584179429612427958">"Прозорец за преклопување на зголемувањето"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"Прозорец за зголемување"</string>
<string name="magnification_controls_title" msgid="8421106606708891519">"Контроли на прозорец за зголемување"</string>
@@ -1070,9 +1063,13 @@
<string name="controls_structure_tooltip" msgid="4355922222944447867">"Повлечете за да видите повеќе"</string>
<string name="controls_seeding_in_progress" msgid="3033855341410264148">"Се вчитуваат препораки"</string>
<string name="controls_media_close_session" msgid="9023534788828414585">"Затвори ја аудиовизуелнава сесија"</string>
+ <string name="controls_media_resume" msgid="1933520684481586053">"Продолжи"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"Неактивна, провери апликација"</string>
<string name="controls_error_retryable" msgid="864025882878378470">"Грешка, повторен обид…"</string>
- <string name="controls_error_removed" msgid="6299213591234723805">"Уредот е отстранет"</string>
+ <string name="controls_error_removed" msgid="6675638069846014366">"Не е најдено"</string>
+ <string name="controls_error_removed_title" msgid="1207794911208047818">"Контролата не е достапна"</string>
+ <string name="controls_error_removed_message" msgid="2885911717034750542">"Не може да се пристапи до <xliff:g id="DEVICE">%1$s</xliff:g>. Проверете ја апликацијата <xliff:g id="APPLICATION">%2$s</xliff:g> за да се осигурите дека контролата е сè уште достапна и дека поставките за апликацијата не се сменети."</string>
+ <string name="controls_open_app" msgid="483650971094300141">"Отвори ја апликација"</string>
<string name="controls_error_generic" msgid="352500456918362905">"Не може да се вчита статусот"</string>
<string name="controls_error_failed" msgid="960228639198558525">"Грешка, обидете се повторно"</string>
<string name="controls_in_progress" msgid="4421080500238215939">"Во тек"</string>
diff --git a/packages/SystemUI/res/values-ml/strings.xml b/packages/SystemUI/res/values-ml/strings.xml
index 43fc1bb0e514..03e826f54e45 100644
--- a/packages/SystemUI/res/values-ml/strings.xml
+++ b/packages/SystemUI/res/values-ml/strings.xml
@@ -77,9 +77,6 @@
<string name="compat_mode_on" msgid="4963711187149440884">"സ്‌ക്രീനിൽ ഉൾക്കൊള്ളിക്കാൻ സൂം ചെയ്യുക"</string>
<string name="compat_mode_off" msgid="7682459748279487945">"സ്‌ക്രീനിൽ ഉൾക്കൊള്ളിക്കാൻ വലിച്ചുനീട്ടുക"</string>
<string name="global_action_screenshot" msgid="2760267567509131654">"സ്ക്രീൻഷോട്ട്"</string>
- <string name="global_action_lock_message" product="default" msgid="4466026255205186456">"കൂടുതൽ ഓപ്ഷനുകൾക്ക് നിങ്ങളുടെ ഫോൺ അൺലോക്ക് ചെയ്യുക"</string>
- <string name="global_action_lock_message" product="tablet" msgid="7621167597240332986">"കൂടുതൽ ഓപ്ഷനുകൾക്ക് നിങ്ങളുടെ ടാബ്‌ലെറ്റ് അൺലോക്ക് ചെയ്യുക"</string>
- <string name="global_action_lock_message" product="device" msgid="538790401275363781">"കൂടുതൽ ഓപ്ഷനുകൾക്ക് നിങ്ങളുടെ ഉപകരണം അൺലോക്ക് ചെയ്യുക"</string>
<string name="remote_input_image_insertion_text" msgid="4850791636452521123">"ചിത്രം അയച്ചു"</string>
<string name="screenshot_saving_ticker" msgid="6519186952674544916">"സ്‌ക്രീൻഷോട്ട് സംരക്ഷിക്കുന്നു..."</string>
<string name="screenshot_saving_title" msgid="2298349784913287333">"സ്‌ക്രീൻഷോട്ട് സംരക്ഷിക്കുന്നു..."</string>
@@ -722,7 +719,7 @@
<string name="notification_channel_summary_priority" msgid="7952654515769021553">"സംഭാഷണ വിഭാഗത്തിന് മുകളിലായി കാണിക്കുന്നു, ഫ്ലോട്ടിംഗ് ബബിളായി ദൃശ്യമാകുന്നു, ലോക്ക് സ്ക്രീനിൽ പ്രൊഫൈൽ ചിത്രം പ്രദർശിപ്പിക്കുന്നു"</string>
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"ക്രമീകരണം"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"മുൻഗണന"</string>
- <string name="no_shortcut" msgid="7176375126961212514">"സംഭാഷണ നിർദ്ദിഷ്ട ക്രമീകരണം <xliff:g id="APP_NAME">%1$s</xliff:g> പിന്തുണയ്ക്കുന്നില്ല"</string>
+ <string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> സംഭാഷണ സവിശേഷതകളെ പിന്തുണയ്‌ക്കുന്നില്ല"</string>
<string name="bubble_overflow_empty_title" msgid="3120029421991510842">"അടുത്തിടെയുള്ള ബബിളുകൾ ഒന്നുമില്ല"</string>
<string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"അടുത്തിടെയുള്ള ബബിളുകൾ, ഡിസ്മിസ് ചെയ്ത ബബിളുകൾ എന്നിവ ഇവിടെ ദൃശ്യമാവും"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"ഈ അറിയിപ്പുകൾ പരിഷ്ക്കരിക്കാനാവില്ല."</string>
@@ -1005,7 +1002,8 @@
<string name="bubble_accessibility_action_move_top_right" msgid="6916868852433483569">"മുകളിൽ വലതുഭാഗത്തേക്ക് നീക്കുക"</string>
<string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"ചുവടെ ഇടതുഭാഗത്തേക്ക് നീക്കുക"</string>
<string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"ചുവടെ വലതുഭാഗത്തേക്ക് നീക്കുക"</string>
- <string name="bubble_dismiss_text" msgid="7071770411580452911">"ഡിസ്‌മിസ് ചെയ്യുക"</string>
+ <!-- no translation found for bubble_dismiss_text (1314082410868930066) -->
+ <skip />
<string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"സംഭാഷണം ബബിൾ ചെയ്യരുത്"</string>
<string name="bubbles_user_education_title" msgid="5547017089271445797">"ബബിളുകൾ ഉപയോഗിച്ച് ചാറ്റ് ചെയ്യുക"</string>
<string name="bubbles_user_education_description" msgid="1160281719576715211">"പുതിയ സംഭാഷണങ്ങൾ ഫ്ലോട്ടിംഗ് ഐക്കണുകളോ ബബിളുകളോ ആയി ദൃശ്യമാവുന്നു. ബബിൾ തുറക്കാൻ ടാപ്പ് ചെയ്യു. ഇത് നീക്കാൻ വലിച്ചിടുക."</string>
@@ -1016,11 +1014,17 @@
<string name="notification_content_system_nav_changed" msgid="5077913144844684544">"സിസ്‌റ്റം നാവിഗേഷൻ അപ്‌ഡേറ്റ് ചെയ്‌തു. മാറ്റങ്ങൾ വരുത്താൻ ക്രമീകരണത്തിലേക്ക് പോവുക."</string>
<string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"സിസ്‌റ്റം നാവിഗേഷൻ അപ്‌ഡേറ്റ് ചെയ്യാൻ ക്രമീകരണത്തിലേക്ക് പോവുക"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"സ്‌റ്റാൻഡ്‌ബൈ"</string>
+ <!-- no translation found for priority_onboarding_title (2893070698479227616) -->
+ <skip />
+ <!-- no translation found for priority_onboarding_behavior (5342816047020432929) -->
+ <skip />
<string name="priority_onboarding_show_at_top_text" msgid="1678400241025513541">"സംഭാഷണ വിഭാഗത്തിന്റെ മുകളിൽ കാണിക്കുക"</string>
<string name="priority_onboarding_show_avatar_text" msgid="5756291381124091508">"ലോക്ക് സ്ക്രീനിൽ പ്രൊഫൈൽ ചിത്രം കാണിക്കുക"</string>
<string name="priority_onboarding_appear_as_bubble_text" msgid="4227039772250263122">"ആപ്പുകളുടെ മുകളിൽ ഫ്ലോട്ടിംഗ് ബബിൾ ആയി ദൃശ്യമാകും"</string>
<string name="priority_onboarding_ignores_dnd_text" msgid="2918952762719600529">"\'ശല്യപ്പെടുത്തരുത്\' തടസ്സപ്പെടുത്തുക"</string>
<string name="priority_onboarding_done_button_title" msgid="4569550984286506007">"മനസ്സിലായി"</string>
+ <!-- no translation found for priority_onboarding_settings_button_title (6663601574303585927) -->
+ <skip />
<string name="magnification_overlay_title" msgid="6584179429612427958">"മാഗ്നിഫിക്കേഷൻ ഓവർലേ വിൻഡോ"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"മാഗ്നിഫിക്കേഷൻ വിൻഡോ"</string>
<string name="magnification_controls_title" msgid="8421106606708891519">"മാഗ്നിഫിക്കേഷൻ വിൻഡോ നിയന്ത്രണങ്ങൾ"</string>
@@ -1042,7 +1046,7 @@
<string name="accessibility_control_move" msgid="8980344493796647792">"<xliff:g id="NUMBER">%d</xliff:g>-ാം സ്ഥാനത്തേയ്ക്ക് നീക്കുക"</string>
<string name="controls_favorite_default_title" msgid="967742178688938137">"നിയന്ത്രണങ്ങൾ"</string>
<string name="controls_favorite_subtitle" msgid="6604402232298443956">"പവർ മെനുവിൽ നിന്ന് ആക്സസ് ചെയ്യേണ്ട നിയന്ത്രണങ്ങൾ തിരഞ്ഞെടുക്കുക"</string>
- <string name="controls_favorite_rearrange" msgid="5616952398043063519">"നിയന്ത്രണങ്ങൾ പുനഃക്രമീകരിക്കാൻ പിടിച്ച് വലിച്ചിടുക"</string>
+ <string name="controls_favorite_rearrange" msgid="5616952398043063519">"നിയന്ത്രണങ്ങൾ പുനഃക്രമീകരിക്കാൻ അമർത്തിപ്പിടിച്ച് വലിച്ചിടുക"</string>
<string name="controls_favorite_removed" msgid="5276978408529217272">"എല്ലാ നിയന്ത്രണങ്ങളും നീക്കം ചെയ്തു"</string>
<string name="controls_favorite_toast_no_changes" msgid="7094494210840877931">"മാറ്റങ്ങൾ സംരക്ഷിച്ചിട്ടില്ല"</string>
<string name="controls_favorite_load_error" msgid="2533215155804455348">"എല്ലാ നിയന്ത്രണങ്ങളുടെയും ലിസ്റ്റ് ലോഡ് ചെയ്യാനായില്ല."</string>
@@ -1062,9 +1066,13 @@
<string name="controls_structure_tooltip" msgid="4355922222944447867">"കൂടുതൽ കാണാൻ സ്വൈപ്പ് ചെയ്യുക"</string>
<string name="controls_seeding_in_progress" msgid="3033855341410264148">"നിർദ്ദേശങ്ങൾ ലോഡ് ചെയ്യുന്നു"</string>
<string name="controls_media_close_session" msgid="9023534788828414585">"ഈ മീഡിയ സെഷൻ അടയ്ക്കുക"</string>
+ <string name="controls_media_resume" msgid="1933520684481586053">"പുനരാരംഭിക്കുക"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"നിഷ്‌ക്രിയം, ആപ്പ് പരിശോധിക്കൂ"</string>
<string name="controls_error_retryable" msgid="864025882878378470">"പിശക്, വീണ്ടും ശ്രമിക്കുന്നു…"</string>
- <string name="controls_error_removed" msgid="6299213591234723805">"ഉപകരണം നീക്കം ചെയ്തു"</string>
+ <string name="controls_error_removed" msgid="6675638069846014366">"കണ്ടെത്തിയില്ല"</string>
+ <string name="controls_error_removed_title" msgid="1207794911208047818">"നിയന്ത്രണം ലഭ്യമല്ല"</string>
+ <string name="controls_error_removed_message" msgid="2885911717034750542">"<xliff:g id="DEVICE">%1$s</xliff:g> ആക്‌സസ് ചെയ്യാനായില്ല. നിയന്ത്രണം ഇപ്പോഴും ലഭ്യമാണെന്നും ആപ്പ് ക്രമീകരണം മാറ്റിയിട്ടില്ലെന്നും ഉറപ്പാക്കാൻ <xliff:g id="APPLICATION">%2$s</xliff:g> ആപ്പ് പരിശോധിക്കുക."</string>
+ <string name="controls_open_app" msgid="483650971094300141">"ആപ്പ് തുറക്കുക"</string>
<string name="controls_error_generic" msgid="352500456918362905">"നില ലോഡ് ചെയ്യാനാകുന്നില്ല"</string>
<string name="controls_error_failed" msgid="960228639198558525">"പിശക്, വീണ്ടും ശ്രമിക്കുക"</string>
<string name="controls_in_progress" msgid="4421080500238215939">"പുരോഗതിയിലാണ്"</string>
diff --git a/packages/SystemUI/res/values-mn/strings.xml b/packages/SystemUI/res/values-mn/strings.xml
index 6d4c8c650ca6..9a15e98fa763 100644
--- a/packages/SystemUI/res/values-mn/strings.xml
+++ b/packages/SystemUI/res/values-mn/strings.xml
@@ -77,9 +77,6 @@
<string name="compat_mode_on" msgid="4963711187149440884">"Дэлгэц дүүргэх бол өсгөнө үү"</string>
<string name="compat_mode_off" msgid="7682459748279487945">"Дэлгэц дүүргэх бол татна уу"</string>
<string name="global_action_screenshot" msgid="2760267567509131654">"Дэлгэцийн зураг дарах"</string>
- <string name="global_action_lock_message" product="default" msgid="4466026255205186456">"Бусад сонголтыг харахын тулд утасныхаа түгжээг тайлна уу"</string>
- <string name="global_action_lock_message" product="tablet" msgid="7621167597240332986">"Бусад сонголтыг харахын тулд таблетынхаа түгжээг тайлна уу"</string>
- <string name="global_action_lock_message" product="device" msgid="538790401275363781">"Бусад сонголтыг харахын тулд төхөөрөмжийнхөө түгжээг тайлна уу"</string>
<string name="remote_input_image_insertion_text" msgid="4850791636452521123">"зураг илгээсэн"</string>
<string name="screenshot_saving_ticker" msgid="6519186952674544916">"Дэлгэцийн агшинг хадгалж байна…"</string>
<string name="screenshot_saving_title" msgid="2298349784913287333">"Дэлгэцийн агшинг хадгалж байна…"</string>
@@ -595,29 +592,21 @@
<string name="volume_odi_captions_hint_enable" msgid="2073091194012843195">"идэвхжүүлэх"</string>
<string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"идэвхгүй болгох"</string>
<string name="accessibility_output_chooser" msgid="7807898688967194183">"Гаралтын төхөөрөмжийг солих"</string>
- <!-- no translation found for screen_pinning_title (9058007390337841305) -->
- <skip />
+ <string name="screen_pinning_title" msgid="9058007390337841305">"Аппыг бэхэлсэн"</string>
<string name="screen_pinning_description" msgid="8699395373875667743">"Таныг тогтоосныг болиулах хүртэл үүнийг харуулна. Тогтоосныг болиулахын тулд Буцах, Тоймыг дараад хүлээнэ үү."</string>
<string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"Таныг тогтоосныг болиулах хүртэл үүнийг харуулсан хэвээр байна. Тогтоосныг болиулахын тулд Буцах, Нүүр хуудас товчлуурыг дараад хүлээнэ үү."</string>
<string name="screen_pinning_description_gestural" msgid="7246323931831232068">"Та тогтоосныг болиулах хүртэл үүнийг харуулсан хэвээр байна. Тогтоосныг болиулахын тулд дээш удаан шударна уу."</string>
<string name="screen_pinning_description_accessible" msgid="7386449191953535332">"Таныг тогтоосныг болиулах хүртэл харагдах болно. Тогтоосныг болиулахын тулд Буцах товчлуурыг дараад, хүлээнэ үү."</string>
<string name="screen_pinning_description_recents_invisible_accessible" msgid="2857071808674481986">"Таныг тогтоосныг болиулах хүртэл үүнийг харуулсан хэвээр байна. Тогтоосныг болиулахын тулд Нүүр хуудас товчлуурыг дараад хүлээнэ үү."</string>
- <!-- no translation found for screen_pinning_exposes_personal_data (8189852022981524789) -->
- <skip />
- <!-- no translation found for screen_pinning_can_open_other_apps (7529756813231421455) -->
- <skip />
- <!-- no translation found for screen_pinning_toast (8177286912533744328) -->
- <skip />
- <!-- no translation found for screen_pinning_toast_recents_invisible (6850978077443052594) -->
- <skip />
- <!-- no translation found for screen_pinning_toast_gesture_nav (170699893395336705) -->
- <skip />
+ <string name="screen_pinning_exposes_personal_data" msgid="8189852022981524789">"Хувийн мэдээлэлд хандах боломжтой байж магадгүй (харилцагчид, имэйлийн контент зэрэг)."</string>
+ <string name="screen_pinning_can_open_other_apps" msgid="7529756813231421455">"Тогтоосон апп бусад аппыг нээж магадгүй."</string>
+ <string name="screen_pinning_toast" msgid="8177286912533744328">"Энэ аппыг тогтоосныг болиулахын тулд Буцах, Тойм товчлуурыг дараад хүлээнэ үү"</string>
+ <string name="screen_pinning_toast_recents_invisible" msgid="6850978077443052594">"Энэ аппыг тогтоосныг болиулахын тулд Буцах, Нүүр хуудасны товчлуурыг дараад хүлээнэ үү"</string>
+ <string name="screen_pinning_toast_gesture_nav" msgid="170699893395336705">"Энэ аппыг тогтоосныг болиулахын тулд дээш шудраад хүлээнэ үү"</string>
<string name="screen_pinning_positive" msgid="3285785989665266984">"Ойлголоо"</string>
<string name="screen_pinning_negative" msgid="6882816864569211666">"Үгүй"</string>
- <!-- no translation found for screen_pinning_start (7483998671383371313) -->
- <skip />
- <!-- no translation found for screen_pinning_exit (4553787518387346893) -->
- <skip />
+ <string name="screen_pinning_start" msgid="7483998671383371313">"Аппыг бэхэлсэн"</string>
+ <string name="screen_pinning_exit" msgid="4553787518387346893">"Аппыг тогтоосныг болиулсан"</string>
<string name="quick_settings_reset_confirmation_title" msgid="463533331480997595">"<xliff:g id="TILE_LABEL">%1$s</xliff:g>-ийг нуух уу?"</string>
<string name="quick_settings_reset_confirmation_message" msgid="2320586180785674186">"Тохируулгын хэсэгт үүнийг асаахад энэ дахин харагдана."</string>
<string name="quick_settings_reset_confirmation_button" msgid="3341477479055016776">"Нуух"</string>
@@ -724,13 +713,13 @@
<string name="notification_bubble_title" msgid="8330481035191903164">"Бөмбөлөг"</string>
<string name="notification_channel_summary_low" msgid="4860617986908931158">"Дуу эсвэл чичиргээ байхгүй"</string>
<string name="notification_conversation_summary_low" msgid="1734433426085468009">"Дуу эсвэл чичиргээ байхгүй бөгөөд харицан ярианы хэсгийн доод талд харагдана"</string>
- <string name="notification_channel_summary_default" msgid="3282930979307248890">"Утасны тохиргоонд тулгуурлан хонх дуугаргах буюу эсхүл чичирхийлж болзошгүй"</string>
- <string name="notification_channel_summary_default_with_bubbles" msgid="1782419896613644568">"Утасны тохиргоонд тулгуурлан хонх дуугаргах буюу эсхүл чичирхийлж болзошгүй. <xliff:g id="APP_NAME">%1$s</xliff:g>-н харилцан яриаг өгөгдмөл тохиргооны дагуу бөмбөлөг болгоно."</string>
+ <string name="notification_channel_summary_default" msgid="3282930979307248890">"Утасны тохиргоонд тулгуурлан хонх дуугаргах эсвэл чичирхийлж болзошгүй"</string>
+ <string name="notification_channel_summary_default_with_bubbles" msgid="1782419896613644568">"Утасны тохиргоонд тулгуурлан хонх дуугаргах эсвэл чичирхийлж болзошгүй. <xliff:g id="APP_NAME">%1$s</xliff:g>-н харилцан яриаг өгөгдмөл тохиргооны дагуу бөмбөлөг болгоно."</string>
<string name="notification_channel_summary_bubble" msgid="7235935211580860537">"Энэ контентын хөвөн гарч ирэх товчлолтойгоор таны анхаарлыг татдаг."</string>
<string name="notification_channel_summary_priority" msgid="7952654515769021553">"Харилцан ярианы хэсгийн дээд талд хөвж буй бөмбөлөг хэлбэрээр харагдах бөгөөд профайлын зургийг түгжигдсэн дэлгэцэд үзүүлнэ"</string>
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"Тохиргоо"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"Ач холбогдол"</string>
- <string name="no_shortcut" msgid="7176375126961212514">"<xliff:g id="APP_NAME">%1$s</xliff:g> харилцан ярианы тодорхой тохиргоог дэмждэггүй"</string>
+ <string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> нь харилцан ярианы онцлогуудыг дэмждэггүй"</string>
<string name="bubble_overflow_empty_title" msgid="3120029421991510842">"Саяхны бөмбөлөг алга байна"</string>
<string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"Саяхны бөмбөлгүүд болон үл хэрэгссэн бөмбөлгүүд энд харагдана"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"Эдгээр мэдэгдлийг өөрчлөх боломжгүй."</string>
@@ -1013,7 +1002,8 @@
<string name="bubble_accessibility_action_move_top_right" msgid="6916868852433483569">"Баруун дээш зөөх"</string>
<string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"Зүүн доош зөөх"</string>
<string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"Баруун доош зөөх"</string>
- <string name="bubble_dismiss_text" msgid="7071770411580452911">"Үл хэрэгсэх"</string>
+ <!-- no translation found for bubble_dismiss_text (1314082410868930066) -->
+ <skip />
<string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"Харилцан яриаг бүү бөмбөлөг болго"</string>
<string name="bubbles_user_education_title" msgid="5547017089271445797">"Бөмбөлөг ашиглан чатлаарай"</string>
<string name="bubbles_user_education_description" msgid="1160281719576715211">"Шинэ харилцан яриа нь хөвөгч дүрс тэмдэг эсвэл бөмбөлөг хэлбэрээр харагддаг. Бөмбөлгийг нээхийн тулд товшино уу. Түүнийг зөөхийн тулд чирнэ үү."</string>
@@ -1024,11 +1014,14 @@
<string name="notification_content_system_nav_changed" msgid="5077913144844684544">"Системийн навигацыг шинэчиллээ. Өөрчлөхийн тулд Тохиргоо руу очно уу."</string>
<string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"Системийн навигацыг шинэчлэхийн тулд Тохиргоо руу очно уу"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Зогсолтын горим"</string>
+ <string name="priority_onboarding_title" msgid="2893070698479227616">"Харилцан яриаг чухал гэж тохируулсан"</string>
+ <string name="priority_onboarding_behavior" msgid="5342816047020432929">"Чухал харилцан яриа нь:"</string>
<string name="priority_onboarding_show_at_top_text" msgid="1678400241025513541">"Харилцан ярианы хэсгийн дээд талд харуулна"</string>
<string name="priority_onboarding_show_avatar_text" msgid="5756291381124091508">"Түгжигдсэн дэлгэц дээр профайлын зургийг харуулна"</string>
<string name="priority_onboarding_appear_as_bubble_text" msgid="4227039772250263122">"Аппуудын дээр хөвөгч бөмбөлөг хэлбэрээр харагдана"</string>
<string name="priority_onboarding_ignores_dnd_text" msgid="2918952762719600529">"Бүү саад бол онцлогийг үл хэрэгсэн тасалдуулна"</string>
<string name="priority_onboarding_done_button_title" msgid="4569550984286506007">"Ойлголоо"</string>
+ <string name="priority_onboarding_settings_button_title" msgid="6663601574303585927">"Тохиргоо"</string>
<string name="magnification_overlay_title" msgid="6584179429612427958">"Томруулалтыг давхарласан цонх"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"Томруулалтын цонх"</string>
<string name="magnification_controls_title" msgid="8421106606708891519">"Томруулалтын цонхны хяналт"</string>
@@ -1070,9 +1063,13 @@
<string name="controls_structure_tooltip" msgid="4355922222944447867">"Илүү ихийг харахын тулд шударна уу"</string>
<string name="controls_seeding_in_progress" msgid="3033855341410264148">"Зөвлөмжүүдийг ачаалж байна"</string>
<string name="controls_media_close_session" msgid="9023534788828414585">"Медианы энэ харилцан үйлдлийг хаах"</string>
+ <string name="controls_media_resume" msgid="1933520684481586053">"Үргэлжлүүлэх"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"Идэвхгүй байна, аппыг шалгана уу"</string>
<string name="controls_error_retryable" msgid="864025882878378470">"Алдаа, дахин оролдож байна…"</string>
- <string name="controls_error_removed" msgid="6299213591234723805">"Төхөөрөмжийг хассан"</string>
+ <string name="controls_error_removed" msgid="6675638069846014366">"Олдсонгүй"</string>
+ <string name="controls_error_removed_title" msgid="1207794911208047818">"Хяналт боломжгүй байна"</string>
+ <string name="controls_error_removed_message" msgid="2885911717034750542">"<xliff:g id="DEVICE">%1$s</xliff:g>-д хандаж чадсангүй. Хяналт боломжтой хэвээр байгаа бөгөөд аппын тохиргоог өөрчлөөгүй эсэхийг нягтлахын тулд <xliff:g id="APPLICATION">%2$s</xliff:g> аппыг шалгана уу."</string>
+ <string name="controls_open_app" msgid="483650971094300141">"Аппыг нээх"</string>
<string name="controls_error_generic" msgid="352500456918362905">"Статус ачаалах боломжгүй"</string>
<string name="controls_error_failed" msgid="960228639198558525">"Алдаа гарав, дахин оролдоно уу"</string>
<string name="controls_in_progress" msgid="4421080500238215939">"Үргэлжилж байна"</string>
diff --git a/packages/SystemUI/res/values-mr/strings.xml b/packages/SystemUI/res/values-mr/strings.xml
index 12acadeb1d61..cbc50b90e300 100644
--- a/packages/SystemUI/res/values-mr/strings.xml
+++ b/packages/SystemUI/res/values-mr/strings.xml
@@ -77,9 +77,6 @@
<string name="compat_mode_on" msgid="4963711187149440884">"स्क्रीन भरण्यासाठी झूम करा"</string>
<string name="compat_mode_off" msgid="7682459748279487945">"स्क्रीन भरण्यासाठी ताणा"</string>
<string name="global_action_screenshot" msgid="2760267567509131654">"स्क्रीनशॉट"</string>
- <string name="global_action_lock_message" product="default" msgid="4466026255205186456">"आणखी पर्यायांसाठी तुमचा फोन अनलॉक करा"</string>
- <string name="global_action_lock_message" product="tablet" msgid="7621167597240332986">"आणखी पर्यायांसाठी तुमचा टॅबलेट अनलॉक करा"</string>
- <string name="global_action_lock_message" product="device" msgid="538790401275363781">"आणखी पर्यायांसाठी तुमचे डिव्हाइस अनलॉक करा"</string>
<string name="remote_input_image_insertion_text" msgid="4850791636452521123">"इमेज पाठवली आहे"</string>
<string name="screenshot_saving_ticker" msgid="6519186952674544916">"स्क्रीनशॉट सेव्ह करत आहे…"</string>
<string name="screenshot_saving_title" msgid="2298349784913287333">"स्क्रीनशॉट सेव्ह करत आहे…"</string>
@@ -595,29 +592,21 @@
<string name="volume_odi_captions_hint_enable" msgid="2073091194012843195">"सुरू करा"</string>
<string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"बंद करा"</string>
<string name="accessibility_output_chooser" msgid="7807898688967194183">"आउटपुट डिव्‍हाइस स्विच करा"</string>
- <!-- no translation found for screen_pinning_title (9058007390337841305) -->
- <skip />
+ <string name="screen_pinning_title" msgid="9058007390337841305">"ॲप पिन केले आहे"</string>
<string name="screen_pinning_description" msgid="8699395373875667743">"तुम्ही अनपिन करेर्यंत हे यास दृश्यामध्ये ठेवते. अनपिन करण्‍यासाठी परत आणि विहंगावलोकनास स्पर्श करा आणि धरून ठेवा."</string>
<string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"तुम्ही अनपिन करेर्यंत हे त्याला दृश्यामध्ये ठेवते. अनपिन करण्‍यासाठी मागे आणि होम वर स्पर्श करा आणि धरून ठेवा."</string>
<string name="screen_pinning_description_gestural" msgid="7246323931831232068">"हे तुम्ही अनपिन करेपर्यंत दृश्यमान ठेवते. वरती स्‍वाइप करा आणि अनपिन करण्यासाठी धरून ठेवा."</string>
<string name="screen_pinning_description_accessible" msgid="7386449191953535332">"तुम्ही अनपिन करेर्यंत हे यास दृश्यामध्ये ठेवते. अनपिन करण्‍यासाठी विहंगावलोकनास स्पर्श करा आणि धरून ठेवा."</string>
<string name="screen_pinning_description_recents_invisible_accessible" msgid="2857071808674481986">"तुम्ही अनपिन करेपर्यंत हे त्यास दृश्यामध्ये ठेवते. अनपिन करण्यासाठी होमला स्पर्श करा आणि धरून ठेवा."</string>
- <!-- no translation found for screen_pinning_exposes_personal_data (8189852022981524789) -->
- <skip />
- <!-- no translation found for screen_pinning_can_open_other_apps (7529756813231421455) -->
- <skip />
- <!-- no translation found for screen_pinning_toast (8177286912533744328) -->
- <skip />
- <!-- no translation found for screen_pinning_toast_recents_invisible (6850978077443052594) -->
- <skip />
- <!-- no translation found for screen_pinning_toast_gesture_nav (170699893395336705) -->
- <skip />
+ <string name="screen_pinning_exposes_personal_data" msgid="8189852022981524789">"वैयक्‍तिक डेटा अ‍ॅक्सेस केला जाऊ शकतो (जसे की संपर्क आणि ईमेल आशय)."</string>
+ <string name="screen_pinning_can_open_other_apps" msgid="7529756813231421455">"पिन केलेले ॲप इतर ॲप्‍स उघडू शकते."</string>
+ <string name="screen_pinning_toast" msgid="8177286912533744328">"हे ॲप अनपिन करण्यासाठी, मागे आणि अवलोकन बटणांना स्पर्श करून धरून ठेवा"</string>
+ <string name="screen_pinning_toast_recents_invisible" msgid="6850978077443052594">"हे ॲप अनपिन करण्यासाठी, मागे आणि होम बटणांना स्पर्श करून धरून ठेवा"</string>
+ <string name="screen_pinning_toast_gesture_nav" msgid="170699893395336705">"हे ॲप अनपिन करण्यासाठी, वर स्‍वाइप करा आणि धरून ठेवा"</string>
<string name="screen_pinning_positive" msgid="3285785989665266984">"समजले"</string>
<string name="screen_pinning_negative" msgid="6882816864569211666">"नाही, नको"</string>
- <!-- no translation found for screen_pinning_start (7483998671383371313) -->
- <skip />
- <!-- no translation found for screen_pinning_exit (4553787518387346893) -->
- <skip />
+ <string name="screen_pinning_start" msgid="7483998671383371313">"पिन केलेले ॲप"</string>
+ <string name="screen_pinning_exit" msgid="4553787518387346893">"अनपिन केलेले ॲप"</string>
<string name="quick_settings_reset_confirmation_title" msgid="463533331480997595">"<xliff:g id="TILE_LABEL">%1$s</xliff:g> लपवायचे?"</string>
<string name="quick_settings_reset_confirmation_message" msgid="2320586180785674186">"तुम्ही सेटिंग्जमध्ये ते पुढील वेळी सुरू कराल तेव्हा ते पुन्हा दिसेल."</string>
<string name="quick_settings_reset_confirmation_button" msgid="3341477479055016776">"लपवा"</string>
@@ -724,13 +713,13 @@
<string name="notification_bubble_title" msgid="8330481035191903164">"बबल"</string>
<string name="notification_channel_summary_low" msgid="4860617986908931158">"आवाज किंवा व्हायब्रेशन नाही"</string>
<string name="notification_conversation_summary_low" msgid="1734433426085468009">"आवाज किंवा व्हायब्रेशन नाही आणि संभाषण विभागात सर्वात तळाशी दिसते"</string>
- <string name="notification_channel_summary_default" msgid="3282930979307248890">"फोन सेटिंग्जच्या आधारावर रिंग किंवा व्हायब्रेट होऊ शकतो"</string>
+ <string name="notification_channel_summary_default" msgid="3282930979307248890">"फोन सेटिंग्जनुसार फोन रिंग किंवा व्हायब्रेट होऊ शकतो"</string>
<string name="notification_channel_summary_default_with_bubbles" msgid="1782419896613644568">"फोन सेटिंग्जच्या आधारावर रिंग किंवा व्हायब्रेट होऊ शकतो. <xliff:g id="APP_NAME">%1$s</xliff:g> मधील संभाषणे बाय डीफॉल्ट बबल होतात."</string>
<string name="notification_channel_summary_bubble" msgid="7235935211580860537">"या आशयाच्या फ्लोटिंग शॉर्टकटसह तुमचे लक्ष केंद्रित करते."</string>
<string name="notification_channel_summary_priority" msgid="7952654515769021553">"संभाषण विभागात सर्वात वरती फ्लोटिंग बबल म्हणून दिसते, लॉक स्क्रीनवर प्रोफाइल पिक्चर दाखवते"</string>
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"सेटिंग्ज"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"प्राधान्य"</string>
- <string name="no_shortcut" msgid="7176375126961212514">"<xliff:g id="APP_NAME">%1$s</xliff:g> संभाषण विशिष्ट सेटिंग्जना सपोर्ट करत नाही"</string>
+ <string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> हे संभाषण वैशिष्ट्यांना सपोर्ट करत नाही"</string>
<string name="bubble_overflow_empty_title" msgid="3120029421991510842">"अलीकडील कोणतेही बबल नाहीत"</string>
<string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"अलीकडील बबल आणि डिसमिस केलेले बबल येथे दिसतील"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"या सूचनांमध्ये सुधारणा केली जाऊ शकत नाही."</string>
@@ -1013,7 +1002,8 @@
<string name="bubble_accessibility_action_move_top_right" msgid="6916868852433483569">"वर उजवीकडे हलवा"</string>
<string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"तळाशी डावीकडे हलवा"</string>
<string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"तळाशी उजवीकडे हलवा"</string>
- <string name="bubble_dismiss_text" msgid="7071770411580452911">"डिसमिस करा"</string>
+ <!-- no translation found for bubble_dismiss_text (1314082410868930066) -->
+ <skip />
<string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"संभाषणाला बबल करू नका"</string>
<string name="bubbles_user_education_title" msgid="5547017089271445797">"बबल वापरून चॅट करा"</string>
<string name="bubbles_user_education_description" msgid="1160281719576715211">"नवीन संभाषणे फ्लोटिंग आयकन किंवा बबल म्हणून दिसतात. बबल उघडण्यासाठी टॅप करा. हे हलवण्यासाठी ड्रॅग करा."</string>
@@ -1024,11 +1014,17 @@
<string name="notification_content_system_nav_changed" msgid="5077913144844684544">"सिस्टम नेव्हिगेशन अपडेट केले. बदल करण्यासाठी, सेटिंग्जवर जा."</string>
<string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"सिस्टम नेव्हिगेशन अपडेट करण्यासाठी सेटिंग्जवर जा"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"स्टँडबाय"</string>
+ <!-- no translation found for priority_onboarding_title (2893070698479227616) -->
+ <skip />
+ <!-- no translation found for priority_onboarding_behavior (5342816047020432929) -->
+ <skip />
<string name="priority_onboarding_show_at_top_text" msgid="1678400241025513541">"संभाषण विभागाच्या सर्वात वरती दाखवा"</string>
<string name="priority_onboarding_show_avatar_text" msgid="5756291381124091508">"लॉक स्‍क्रीनवर प्रोफाइल फोटो दाखवा"</string>
<string name="priority_onboarding_appear_as_bubble_text" msgid="4227039772250263122">"ॲप्सच्या सर्वात वरती फ्लोटिंग बबल म्हणून दिसतील"</string>
<string name="priority_onboarding_ignores_dnd_text" msgid="2918952762719600529">"व्यत्यय आणू नका मध्ये अडथळा आणतील"</string>
<string name="priority_onboarding_done_button_title" msgid="4569550984286506007">"समजले"</string>
+ <!-- no translation found for priority_onboarding_settings_button_title (6663601574303585927) -->
+ <skip />
<string name="magnification_overlay_title" msgid="6584179429612427958">"मॅग्निफिकेशन ओव्हरले विंडो"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"मॅग्निफिकेशन विंडो"</string>
<string name="magnification_controls_title" msgid="8421106606708891519">"मॅग्निफिकेशन विंडो नियंत्रणे"</string>
@@ -1059,7 +1055,7 @@
<string name="controls_dialog_ok" msgid="2770230012857881822">"जोडा"</string>
<string name="controls_dialog_message" msgid="342066938390663844">"<xliff:g id="APP">%s</xliff:g> ने सुचवले आहे"</string>
<string name="controls_dialog_confirmation" msgid="586517302736263447">"नियंत्रणे अपडेट केली आहेत"</string>
- <string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"पिनमध्ये अक्षरांचा किंवा चिन्हांचा समावेश असतो"</string>
+ <string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"पिनमध्ये अक्षरे किंवा चिन्हे आहेत"</string>
<string name="controls_pin_verify" msgid="3452778292918877662">"<xliff:g id="DEVICE">%s</xliff:g> ची पडताळणी करा"</string>
<string name="controls_pin_wrong" msgid="6162694056042164211">"चुकीचा पिन"</string>
<string name="controls_pin_verifying" msgid="3755045989392131746">"पडताळणी करत आहे…"</string>
@@ -1070,9 +1066,13 @@
<string name="controls_structure_tooltip" msgid="4355922222944447867">"अधिक पाहण्यासाठी स्वाइप करा"</string>
<string name="controls_seeding_in_progress" msgid="3033855341410264148">"शिफारशी लोड करत आहे"</string>
<string name="controls_media_close_session" msgid="9023534788828414585">"हे मीडिया सेशन बंद करा"</string>
+ <string name="controls_media_resume" msgid="1933520684481586053">"पुन्हा सुरू करा"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"निष्क्रिय, ॲप तपासा"</string>
<string name="controls_error_retryable" msgid="864025882878378470">"एरर, पुन्हा प्रयत्न करत आहे…"</string>
- <string name="controls_error_removed" msgid="6299213591234723805">"डिव्हाइस काढून टाकले आहे"</string>
+ <string name="controls_error_removed" msgid="6675638069846014366">"आढळले नाही"</string>
+ <string name="controls_error_removed_title" msgid="1207794911208047818">"नियंत्रण उपलब्ध नाही"</string>
+ <string name="controls_error_removed_message" msgid="2885911717034750542">"<xliff:g id="DEVICE">%1$s</xliff:g> अ‍ॅक्सेस करता आले नाही. नियंत्रण अजूनही उपलब्ध असल्याची आणि ॲपची सेटिंग्ज बदलली नसल्याची खात्री करण्यासाठी <xliff:g id="APPLICATION">%2$s</xliff:g> ॲप तपासा."</string>
+ <string name="controls_open_app" msgid="483650971094300141">"अ‍ॅप उघडा"</string>
<string name="controls_error_generic" msgid="352500456918362905">"स्थिती लोड करू शकत नाही"</string>
<string name="controls_error_failed" msgid="960228639198558525">"एरर, पुन्हा प्रयत्न करा"</string>
<string name="controls_in_progress" msgid="4421080500238215939">"प्रगतीपथावर आहे"</string>
diff --git a/packages/SystemUI/res/values-ms/strings.xml b/packages/SystemUI/res/values-ms/strings.xml
index 63b6f1cb4b79..f89d5a0a4d4a 100644
--- a/packages/SystemUI/res/values-ms/strings.xml
+++ b/packages/SystemUI/res/values-ms/strings.xml
@@ -77,9 +77,6 @@
<string name="compat_mode_on" msgid="4963711187149440884">"Zum untuk memenuhi skrin"</string>
<string name="compat_mode_off" msgid="7682459748279487945">"Regang utk memenuhi skrin"</string>
<string name="global_action_screenshot" msgid="2760267567509131654">"Tangkapan skrin"</string>
- <string name="global_action_lock_message" product="default" msgid="4466026255205186456">"Buka kunci telefon anda untuk mendapatkan lagi pilihan"</string>
- <string name="global_action_lock_message" product="tablet" msgid="7621167597240332986">"Buka kunci tablet anda untuk mendapatkan lagi pilihan"</string>
- <string name="global_action_lock_message" product="device" msgid="538790401275363781">"Buka kunci peranti anda untuk mendapatkan lagi pilihan"</string>
<string name="remote_input_image_insertion_text" msgid="4850791636452521123">"menghantar imej"</string>
<string name="screenshot_saving_ticker" msgid="6519186952674544916">"Menyimpan tangkapan skrin..."</string>
<string name="screenshot_saving_title" msgid="2298349784913287333">"Menyimpan tangkapan skrin..."</string>
@@ -595,29 +592,21 @@
<string name="volume_odi_captions_hint_enable" msgid="2073091194012843195">"dayakan"</string>
<string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"lumpuhkan"</string>
<string name="accessibility_output_chooser" msgid="7807898688967194183">"Tukar peranti output"</string>
- <!-- no translation found for screen_pinning_title (9058007390337841305) -->
- <skip />
+ <string name="screen_pinning_title" msgid="9058007390337841305">"Apl telah disemat"</string>
<string name="screen_pinning_description" msgid="8699395373875667743">"Tindakan ini memastikan skrin kelihatan sehingga anda menyahsemat. Sentuh &amp; tahan Kembali dan Ikhtisar untuk menyahsemat."</string>
<string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"Tindakan ini memastikan skrin kelihatan sehingga anda menyahsemat. Sentuh &amp; tahan Kembali dan Skrin Utama untuk menyahsemat."</string>
<string name="screen_pinning_description_gestural" msgid="7246323931831232068">"Tindakan ini memastikan skrin kelihatan sehingga anda menyahsemat. Leret ke atas &amp; tahan untuk menyahsemat."</string>
<string name="screen_pinning_description_accessible" msgid="7386449191953535332">"Tindakan ini memastikan skrin kelihatan sehingga anda menyahsemat. Sentuh &amp; tahan Ikhtisar untuk menyahsemat."</string>
<string name="screen_pinning_description_recents_invisible_accessible" msgid="2857071808674481986">"Tindakan ini memastikan skrin kelihatan sehingga anda menyahsemat. Sentuh &amp; tahan Skrin Utama untuk menyahsemat."</string>
- <!-- no translation found for screen_pinning_exposes_personal_data (8189852022981524789) -->
- <skip />
- <!-- no translation found for screen_pinning_can_open_other_apps (7529756813231421455) -->
- <skip />
- <!-- no translation found for screen_pinning_toast (8177286912533744328) -->
- <skip />
- <!-- no translation found for screen_pinning_toast_recents_invisible (6850978077443052594) -->
- <skip />
- <!-- no translation found for screen_pinning_toast_gesture_nav (170699893395336705) -->
- <skip />
+ <string name="screen_pinning_exposes_personal_data" msgid="8189852022981524789">"Data peribadi mungkin boleh diakses (seperti kenalan dan kandungan e-mel)."</string>
+ <string name="screen_pinning_can_open_other_apps" msgid="7529756813231421455">"Apl yang disematkan boleh membuka aplikasi lain."</string>
+ <string name="screen_pinning_toast" msgid="8177286912533744328">"Untuk menyahsemat apl ini, sentuh &amp; tahan butang Kembali dan Ikhtisar"</string>
+ <string name="screen_pinning_toast_recents_invisible" msgid="6850978077443052594">"Untuk menyahsemat apl ini, sentuh &amp; tahan butang Kembali dan Skrin Utama"</string>
+ <string name="screen_pinning_toast_gesture_nav" msgid="170699893395336705">"Untuk menyahsemat apl ini, leret ke atas &amp; tahan"</string>
<string name="screen_pinning_positive" msgid="3285785989665266984">"Faham"</string>
<string name="screen_pinning_negative" msgid="6882816864569211666">"Tidak"</string>
- <!-- no translation found for screen_pinning_start (7483998671383371313) -->
- <skip />
- <!-- no translation found for screen_pinning_exit (4553787518387346893) -->
- <skip />
+ <string name="screen_pinning_start" msgid="7483998671383371313">"Apl disemat"</string>
+ <string name="screen_pinning_exit" msgid="4553787518387346893">"Apl dinyahsemat"</string>
<string name="quick_settings_reset_confirmation_title" msgid="463533331480997595">"Sembunyikan <xliff:g id="TILE_LABEL">%1$s</xliff:g>?"</string>
<string name="quick_settings_reset_confirmation_message" msgid="2320586180785674186">"Mesej itu akan terpapar semula pada kali seterusnya anda menghidupkan apl dalam tetapan."</string>
<string name="quick_settings_reset_confirmation_button" msgid="3341477479055016776">"Sembunyikan"</string>
@@ -730,7 +719,7 @@
<string name="notification_channel_summary_priority" msgid="7952654515769021553">"Ditunjukkan di sebelah atas bahagian perbualan, muncul sebagai gelembung terapung, memaparkan gambar profil pada skrin kunci"</string>
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"Tetapan"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"Keutamaan"</string>
- <string name="no_shortcut" msgid="7176375126961212514">"<xliff:g id="APP_NAME">%1$s</xliff:g> tidak menyokong tetapan khusus perbualan"</string>
+ <string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> tidak menyokong ciri perbualan"</string>
<string name="bubble_overflow_empty_title" msgid="3120029421991510842">"Tiada gelembung terbaharu"</string>
<string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"Gelembung baharu dan gelembung yang diketepikan akan dipaparkan di sini"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"Pemberitahuan ini tidak boleh diubah suai."</string>
@@ -1013,7 +1002,8 @@
<string name="bubble_accessibility_action_move_top_right" msgid="6916868852433483569">"Alihkan ke atas sebelah kanan"</string>
<string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"Alihkan ke bawah sebelah kiri"</string>
<string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"Alihkan ke bawah sebelah kanan"</string>
- <string name="bubble_dismiss_text" msgid="7071770411580452911">"Ketepikan"</string>
+ <!-- no translation found for bubble_dismiss_text (1314082410868930066) -->
+ <skip />
<string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"Jangan jadikan perbualan dalam bentuk gelembung"</string>
<string name="bubbles_user_education_title" msgid="5547017089271445797">"Bersembang menggunakan gelembung"</string>
<string name="bubbles_user_education_description" msgid="1160281719576715211">"Perbualan baharu muncul sebagai ikon terapung atau gelembung. Ketik untuk membuka gelembung. Seret untuk mengalihkan gelembung tersebut."</string>
@@ -1024,11 +1014,14 @@
<string name="notification_content_system_nav_changed" msgid="5077913144844684544">"Navigasi sistem dikemas kini. Untuk membuat perubahan, pergi ke Tetapan."</string>
<string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"Pergi ke Tetapan untuk mengemas kini navigasi sistem"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Tunggu sedia"</string>
+ <string name="priority_onboarding_title" msgid="2893070698479227616">"Perbualan ditetapkan kepada keutamaan"</string>
+ <string name="priority_onboarding_behavior" msgid="5342816047020432929">"Perbualan keutamaan akan:"</string>
<string name="priority_onboarding_show_at_top_text" msgid="1678400241025513541">"Tunjukkan di atas bahagian perbualan"</string>
<string name="priority_onboarding_show_avatar_text" msgid="5756291381124091508">"Tunjukkan gambar profil pada skrin kunci"</string>
<string name="priority_onboarding_appear_as_bubble_text" msgid="4227039772250263122">"Dipaparkan sebagai gelembung terapung di atas apl"</string>
<string name="priority_onboarding_ignores_dnd_text" msgid="2918952762719600529">"Ganggu ciri Jangan Ganggu"</string>
<string name="priority_onboarding_done_button_title" msgid="4569550984286506007">"OK"</string>
+ <string name="priority_onboarding_settings_button_title" msgid="6663601574303585927">"Tetapan"</string>
<string name="magnification_overlay_title" msgid="6584179429612427958">"Tetingkap Tindanan Pembesaran"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"Tetingkap Pembesaran"</string>
<string name="magnification_controls_title" msgid="8421106606708891519">"Kawalan Tetingkap Pembesaran"</string>
@@ -1070,9 +1063,13 @@
<string name="controls_structure_tooltip" msgid="4355922222944447867">"Leret untuk melihat selanjutnya"</string>
<string name="controls_seeding_in_progress" msgid="3033855341410264148">"Memuatkan cadangan"</string>
<string name="controls_media_close_session" msgid="9023534788828414585">"Tutup sesi media ini"</string>
+ <string name="controls_media_resume" msgid="1933520684481586053">"Sambung semula"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"Tidak aktif, semak apl"</string>
<string name="controls_error_retryable" msgid="864025882878378470">"Ralat, mencuba semula…"</string>
- <string name="controls_error_removed" msgid="6299213591234723805">"Peranti dialih keluar"</string>
+ <string name="controls_error_removed" msgid="6675638069846014366">"Tidak ditemui"</string>
+ <string name="controls_error_removed_title" msgid="1207794911208047818">"Kawalan tidak tersedia"</string>
+ <string name="controls_error_removed_message" msgid="2885911717034750542">"Tidak dapat mengakses <xliff:g id="DEVICE">%1$s</xliff:g>. Periksa apl <xliff:g id="APPLICATION">%2$s</xliff:g> untuk memastikan kawalan masih tersedia dan tetapan apl tidak berubah."</string>
+ <string name="controls_open_app" msgid="483650971094300141">"Buka apl"</string>
<string name="controls_error_generic" msgid="352500456918362905">"Tidak dapat memuatkan status"</string>
<string name="controls_error_failed" msgid="960228639198558525">"Ralat, cuba lagi"</string>
<string name="controls_in_progress" msgid="4421080500238215939">"Sedang berlangsung"</string>
diff --git a/packages/SystemUI/res/values-my/strings.xml b/packages/SystemUI/res/values-my/strings.xml
index 991e774ac4c2..dc70e80a7125 100644
--- a/packages/SystemUI/res/values-my/strings.xml
+++ b/packages/SystemUI/res/values-my/strings.xml
@@ -42,7 +42,7 @@
<string name="status_bar_settings_auto_rotation" msgid="8329080442278431708">"မျက်နှာပြင်အလိုအလျောက်လှည့်ရန်"</string>
<string name="status_bar_settings_mute_label" msgid="914392730086057522">"MUTE"</string>
<string name="status_bar_settings_auto_brightness_label" msgid="2151934479226017725">"AUTO"</string>
- <string name="status_bar_settings_notifications" msgid="5285316949980621438">"သတိပေးချက်များ"</string>
+ <string name="status_bar_settings_notifications" msgid="5285316949980621438">"အကြောင်းကြားချက်များ"</string>
<string name="bluetooth_tethered" msgid="4171071193052799041">"ဘလူးတုသ်မှတဆင့်ပြန်လည်ချိတ်ဆက်ခြင်း"</string>
<string name="status_bar_input_method_settings_configure_input_methods" msgid="2972273031043777851">"ထည့်သွင်းနည်းများ သတ်မှတ်ခြင်း"</string>
<string name="status_bar_use_physical_keyboard" msgid="4849251850931213371">"ခလုတ်ပါဝင်သော ကီးဘုတ်"</string>
@@ -77,9 +77,6 @@
<string name="compat_mode_on" msgid="4963711187149440884">"ဇူးမ်အပြည့်ဆွဲခြင်း"</string>
<string name="compat_mode_off" msgid="7682459748279487945">"ဖန်သားပြင်အပြည့်ဆန့်ခြင်း"</string>
<string name="global_action_screenshot" msgid="2760267567509131654">"ဖန်သားပြင်ဓာတ်ပုံ"</string>
- <string name="global_action_lock_message" product="default" msgid="4466026255205186456">"နောက်ထပ် ထိန်းချုပ်မှုများအတွက် သင့်ဖုန်းကို လော့ခ်ဖွင့်ပါ"</string>
- <string name="global_action_lock_message" product="tablet" msgid="7621167597240332986">"နောက်ထပ် ထိန်းချုပ်မှုများအတွက် သင့်တက်ဘလက်ကို လော့ခ်ဖွင့်ပါ"</string>
- <string name="global_action_lock_message" product="device" msgid="538790401275363781">"နောက်ထပ် ထိန်းချုပ်မှုများအတွက် သင့်စက်ကို လော့ခ်ဖွင့်ပါ"</string>
<string name="remote_input_image_insertion_text" msgid="4850791636452521123">"ပုံပို့ထားသည်"</string>
<string name="screenshot_saving_ticker" msgid="6519186952674544916">"ဖန်သားပြင်ဓါတ်ပုံသိမ်းစဉ်.."</string>
<string name="screenshot_saving_title" msgid="2298349784913287333">"ဖန်သားပြင်ဓါတ်ပုံရိုက်ခြင်းအား သိမ်းဆည်းပါမည်"</string>
@@ -595,7 +592,7 @@
<string name="volume_odi_captions_hint_enable" msgid="2073091194012843195">"ဖွင့်ရန်"</string>
<string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"ပိတ်ရန်"</string>
<string name="accessibility_output_chooser" msgid="7807898688967194183">"အထွက် စက်ပစ္စည်းကို ပြောင်းပါ"</string>
- <string name="screen_pinning_title" msgid="9058007390337841305">"အက်ပ်ကို ပင်ထိုးလိုက်သည်"</string>
+ <string name="screen_pinning_title" msgid="9058007390337841305">"အက်ပ်ကို ပင်ထိုးထားသည်"</string>
<string name="screen_pinning_description" msgid="8699395373875667743">"သင်ပင်မဖြုတ်မခြင်း ၎င်းကို ပြသထားပါမည်။ ပင်ဖြုတ်ရန် Back နှင့် Overview ကို ထိ၍ဖိထားပါ။"</string>
<string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"သင်က ပင်မဖြုတ်မခြင်း ၎င်းကို ပြသထားပါမည်။ ပင်ဖြုတ်ရန် \'နောက်သို့\' နှင့် \'ပင်မ\' ခလုတ်တို့ကို တို့၍ဖိထားပါ။"</string>
<string name="screen_pinning_description_gestural" msgid="7246323931831232068">"သင်က ပင်မဖြုတ်မချင်း ၎င်းကို ပြသထားပါမည်။ ပင်ဖြုတ်ရန် အပေါ်သို့ပွတ်ဆွဲပြီး ဖိထားပါ။"</string>
@@ -722,7 +719,7 @@
<string name="notification_channel_summary_priority" msgid="7952654515769021553">"စကားဝိုင်းကဏ္ဍ၏ ထိပ်ပိုင်းတွင် ပြပြီး ပူဖောင်းကွက်အဖြစ် မြင်ရသည်၊ လော့ခ်ချထားချိန် မျက်နှာပြင်တွင် ပရိုဖိုင်ပုံကို ပြသည်"</string>
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"ဆက်တင်များ"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"ဦးစားပေး"</string>
- <string name="no_shortcut" msgid="7176375126961212514">"<xliff:g id="APP_NAME">%1$s</xliff:g> က စကားဝိုင်းအလိုက် ဆက်တင်များကို မပံ့ပိုးပါ"</string>
+ <string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> က စကားဝိုင်းဝန်ဆောင်မှုများကို မပံ့ပိုးပါ"</string>
<string name="bubble_overflow_empty_title" msgid="3120029421991510842">"လတ်တလော ပူဖောင်းကွက်များ မရှိပါ"</string>
<string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"လတ်တလော ပူဖောင်းကွက်များနှင့် ပိတ်လိုက်သော ပူဖောင်းကွက်များကို ဤနေရာတွင် မြင်ရပါမည်"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"ဤအကြောင်းကြားချက်များကို ပြုပြင်၍ မရပါ။"</string>
@@ -1005,7 +1002,8 @@
<string name="bubble_accessibility_action_move_top_right" msgid="6916868852433483569">"ညာဘက်ထိပ်သို့ ရွှေ့ပါ"</string>
<string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"ဘယ်အောက်ခြေသို့ ရွှေ့ရန်"</string>
<string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"ညာအောက်ခြေသို့ ရွှေ့ပါ"</string>
- <string name="bubble_dismiss_text" msgid="7071770411580452911">"ပယ်ရန်"</string>
+ <!-- no translation found for bubble_dismiss_text (1314082410868930066) -->
+ <skip />
<string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"စကားဝိုင်းကို ပူဖောင်းကွက် မပြုလုပ်ပါနှင့်"</string>
<string name="bubbles_user_education_title" msgid="5547017089271445797">"ပူဖောင်းကွက် သုံး၍ ချတ်လုပ်ခြင်း"</string>
<string name="bubbles_user_education_description" msgid="1160281719576715211">"စကားဝိုင်းအသစ်များကို မျောနေသည့် သင်္ကေတများ သို့မဟုတ် ပူဖောင်းကွက်များအဖြစ် မြင်ရပါမည်။ ပူဖောင်းကွက်ကိုဖွင့်ရန် တို့ပါ။ ရွှေ့ရန် ၎င်းကို ဖိဆွဲပါ။"</string>
@@ -1016,16 +1014,19 @@
<string name="notification_content_system_nav_changed" msgid="5077913144844684544">"စနစ်လမ်းညွှန်ခြင်း အပ်ဒိတ်လုပ်ပြီးပါပြီ။ အပြောင်းအလဲများ ပြုလုပ်ရန် \'ဆက်တင်များ\' သို့သွားပါ။"</string>
<string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"စနစ်လမ်းညွှန်ခြင်း အပ်ဒိတ်လုပ်ရန် \'ဆက်တင်များ\' သို့သွားပါ"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"အသင့်အနေအထား"</string>
+ <string name="priority_onboarding_title" msgid="2893070698479227616">"စကားဝိုင်းကို ဦးစားပေးအဖြစ် သတ်မှတ်ထားသည်"</string>
+ <string name="priority_onboarding_behavior" msgid="5342816047020432929">"ဦးစားပေး စကားဝိုင်းသည်-"</string>
<string name="priority_onboarding_show_at_top_text" msgid="1678400241025513541">"စကားဝိုင်းကဏ္ဍ၏ အပေါ်ဘက်တွင်ပြရန်"</string>
<string name="priority_onboarding_show_avatar_text" msgid="5756291381124091508">"လော့ခ်မျက်နှာပြင်တွင် ပရိုဖိုင်ပုံကို ပြရန်"</string>
<string name="priority_onboarding_appear_as_bubble_text" msgid="4227039772250263122">"အက်ပ်အပေါ်တွင် မျောနေသောပူ‌ဖောင်းကွက်အဖြစ် ပေါ်မည်"</string>
<string name="priority_onboarding_ignores_dnd_text" msgid="2918952762719600529">"\'မနှောင့်ယှက်ရ\' ကို ကြားဖြတ်ခြင်း"</string>
<string name="priority_onboarding_done_button_title" msgid="4569550984286506007">"Ok"</string>
+ <string name="priority_onboarding_settings_button_title" msgid="6663601574303585927">"ဆက်တင်များ"</string>
<string name="magnification_overlay_title" msgid="6584179429612427958">"ဝင်းဒိုး ထပ်ပိုးလွှာ ချဲ့ခြင်း"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"ဝင်းဒိုး ချဲ့ခြင်း"</string>
<string name="magnification_controls_title" msgid="8421106606708891519">"ဝင်းဒိုး ထိန်းချုပ်မှုများ ချဲ့ခြင်း"</string>
<string name="quick_controls_title" msgid="6839108006171302273">"စက်ထိန်းစနစ်"</string>
- <string name="quick_controls_subtitle" msgid="1667408093326318053">"သင့်ချိတ်ဆက်ထားသော စက်များအတွက် ထိန်းချုပ်မှုများ ထည့်ပါ"</string>
+ <string name="quick_controls_subtitle" msgid="1667408093326318053">"ချိတ်ဆက်စက်များအတွက် ထိန်းချုပ်မှုများထည့်ပါ"</string>
<string name="quick_controls_setup_title" msgid="8901436655997849822">"စက်ထိန်းစနစ် ထည့်သွင်းခြင်း"</string>
<string name="quick_controls_setup_subtitle" msgid="1681506617879773824">"သင့်ထိန်းချုပ်မှုများကို အသုံးပြုရန် \'ပါဝါ\' ခလုတ်ကို ဖိထားပါ"</string>
<string name="controls_providers_title" msgid="6879775889857085056">"ထိန်းချုပ်မှုများထည့်ရန် အက်ပ်ရွေးခြင်း"</string>
@@ -1062,9 +1063,13 @@
<string name="controls_structure_tooltip" msgid="4355922222944447867">"ပိုမိုကြည့်ရှုရန် ပွတ်ဆွဲပါ"</string>
<string name="controls_seeding_in_progress" msgid="3033855341410264148">"အကြံပြုချက်များ ဖွင့်နေသည်"</string>
<string name="controls_media_close_session" msgid="9023534788828414585">"ဤမီဒီယာစက်ရှင်ကို ပိတ်ပါ"</string>
+ <string name="controls_media_resume" msgid="1933520684481586053">"ဆက်လုပ်ရန်"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"ရပ်နေသည်၊ အက်ပ်ကို စစ်ဆေးပါ"</string>
<string name="controls_error_retryable" msgid="864025882878378470">"မှားသွားသည်၊ ပြန်စမ်းနေသည်…"</string>
- <string name="controls_error_removed" msgid="6299213591234723805">"စက်ကို ဖယ်ရှားထားသည်"</string>
+ <string name="controls_error_removed" msgid="6675638069846014366">"မတွေ့ပါ"</string>
+ <string name="controls_error_removed_title" msgid="1207794911208047818">"ထိန်းချုပ်၍ မရတော့ပါ"</string>
+ <string name="controls_error_removed_message" msgid="2885911717034750542">"<xliff:g id="DEVICE">%1$s</xliff:g> အသုံးပြု၍ မရပါ။ ထိန်းချုပ်၍ ရသေးကြောင်းနှင့် အက်ပ်ဆက်တင်များ ပြောင်းမထားကြောင်း သေချာစေရန် <xliff:g id="APPLICATION">%2$s</xliff:g> အက်ပ်ကို စစ်ဆေးပါ။"</string>
+ <string name="controls_open_app" msgid="483650971094300141">"အက်ပ်ဖွင့်ရန်"</string>
<string name="controls_error_generic" msgid="352500456918362905">"အခြေအနေကို ဖွင့်၍မရပါ"</string>
<string name="controls_error_failed" msgid="960228639198558525">"မှားသွားသည်၊ ပြန်စမ်းကြည့်ပါ"</string>
<string name="controls_in_progress" msgid="4421080500238215939">"ဆောင်ရွက်နေသည်"</string>
diff --git a/packages/SystemUI/res/values-nb/strings.xml b/packages/SystemUI/res/values-nb/strings.xml
index 22a7ff88cd55..53806a7e4daa 100644
--- a/packages/SystemUI/res/values-nb/strings.xml
+++ b/packages/SystemUI/res/values-nb/strings.xml
@@ -77,9 +77,6 @@
<string name="compat_mode_on" msgid="4963711187149440884">"Zoom for å fylle skjermen"</string>
<string name="compat_mode_off" msgid="7682459748279487945">"Strekk for å fylle skjerm"</string>
<string name="global_action_screenshot" msgid="2760267567509131654">"Skjermdump"</string>
- <string name="global_action_lock_message" product="default" msgid="4466026255205186456">"Lås opp telefonen din for å få flere alternativer"</string>
- <string name="global_action_lock_message" product="tablet" msgid="7621167597240332986">"Lås opp nettbrettet ditt for å få flere alternativer"</string>
- <string name="global_action_lock_message" product="device" msgid="538790401275363781">"Lås opp enheten din for å få flere alternativer"</string>
<string name="remote_input_image_insertion_text" msgid="4850791636452521123">"har sendt et bilde"</string>
<string name="screenshot_saving_ticker" msgid="6519186952674544916">"Lagrer skjermdumpen …"</string>
<string name="screenshot_saving_title" msgid="2298349784913287333">"Lagrer skjermdumpen …"</string>
@@ -595,29 +592,21 @@
<string name="volume_odi_captions_hint_enable" msgid="2073091194012843195">"slå på"</string>
<string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"slå av"</string>
<string name="accessibility_output_chooser" msgid="7807898688967194183">"Bytt enhet for lydutgang"</string>
- <!-- no translation found for screen_pinning_title (9058007390337841305) -->
- <skip />
+ <string name="screen_pinning_title" msgid="9058007390337841305">"Appen er festet"</string>
<string name="screen_pinning_description" msgid="8699395373875667743">"På denne måten blir skjermen synlig frem til du løsner den. Trykk og hold inne Tilbake og Oversikt for å løsne den."</string>
<string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"På denne måten blir skjermen synlig frem til du løsner den. Trykk og hold inne Tilbake og Startside for å løsne den."</string>
<string name="screen_pinning_description_gestural" msgid="7246323931831232068">"På denne måten blir skjermen synlig frem til du løsner den. Sveip opp og hold for å løsne."</string>
<string name="screen_pinning_description_accessible" msgid="7386449191953535332">"På denne måten blir skjermen synlig frem til du løsner den. Trykk og hold inne Oversikt for å løsne den."</string>
<string name="screen_pinning_description_recents_invisible_accessible" msgid="2857071808674481986">"På denne måten blir skjermen synlig frem til du løsner den. Trykk og hold inne Startside for å løsne den."</string>
- <!-- no translation found for screen_pinning_exposes_personal_data (8189852022981524789) -->
- <skip />
- <!-- no translation found for screen_pinning_can_open_other_apps (7529756813231421455) -->
- <skip />
- <!-- no translation found for screen_pinning_toast (8177286912533744328) -->
- <skip />
- <!-- no translation found for screen_pinning_toast_recents_invisible (6850978077443052594) -->
- <skip />
- <!-- no translation found for screen_pinning_toast_gesture_nav (170699893395336705) -->
- <skip />
+ <string name="screen_pinning_exposes_personal_data" msgid="8189852022981524789">"Personlige data kan være tilgjengelige (for eksempel kontakter og e-postinnhold)."</string>
+ <string name="screen_pinning_can_open_other_apps" msgid="7529756813231421455">"Den festede appen kan åpne andre apper."</string>
+ <string name="screen_pinning_toast" msgid="8177286912533744328">"For å løsne denne appen, trykk og hold inne tilbakeknappen og oversiktsknappen"</string>
+ <string name="screen_pinning_toast_recents_invisible" msgid="6850978077443052594">"For å løsne denne appen, trykk og hold inne tilbakeknappen og hjemknappen"</string>
+ <string name="screen_pinning_toast_gesture_nav" msgid="170699893395336705">"For å løsne denne appen, sveip opp og hold"</string>
<string name="screen_pinning_positive" msgid="3285785989665266984">"Skjønner"</string>
<string name="screen_pinning_negative" msgid="6882816864569211666">"Nei takk"</string>
- <!-- no translation found for screen_pinning_start (7483998671383371313) -->
- <skip />
- <!-- no translation found for screen_pinning_exit (4553787518387346893) -->
- <skip />
+ <string name="screen_pinning_start" msgid="7483998671383371313">"Appen er festet"</string>
+ <string name="screen_pinning_exit" msgid="4553787518387346893">"Appen er løsnet"</string>
<string name="quick_settings_reset_confirmation_title" msgid="463533331480997595">"Vil du skjule <xliff:g id="TILE_LABEL">%1$s</xliff:g>?"</string>
<string name="quick_settings_reset_confirmation_message" msgid="2320586180785674186">"Den vises igjen neste gang du slår den på i innstillingene."</string>
<string name="quick_settings_reset_confirmation_button" msgid="3341477479055016776">"Skjul"</string>
@@ -730,7 +719,7 @@
<string name="notification_channel_summary_priority" msgid="7952654515769021553">"Vises øverst i samtaledelen, vises som en flytende boble, viser profilbildet på låseskjermen"</string>
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"Innstillinger"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"Prioritet"</string>
- <string name="no_shortcut" msgid="7176375126961212514">"<xliff:g id="APP_NAME">%1$s</xliff:g> støtter ikke samtalespesifikke innstillinger"</string>
+ <string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> støtter ikke samtalefunksjoner"</string>
<string name="bubble_overflow_empty_title" msgid="3120029421991510842">"Ingen nylige bobler"</string>
<string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"Nylige bobler og avviste bobler vises her"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"Disse varslene kan ikke endres."</string>
@@ -1013,10 +1002,11 @@
<string name="bubble_accessibility_action_move_top_right" msgid="6916868852433483569">"Flytt til øverst til høyre"</string>
<string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"Flytt til nederst til venstre"</string>
<string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"Flytt til nederst til høyre"</string>
- <string name="bubble_dismiss_text" msgid="7071770411580452911">"Avvis"</string>
+ <!-- no translation found for bubble_dismiss_text (1314082410868930066) -->
+ <skip />
<string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"Ikke vis samtaler i bobler"</string>
<string name="bubbles_user_education_title" msgid="5547017089271445797">"Chat med bobler"</string>
- <string name="bubbles_user_education_description" msgid="1160281719576715211">"Nye samtaler vises som flytende ikoner, eller bobler. Trykk for å åpne bobler. Dra for å flytte dem."</string>
+ <string name="bubbles_user_education_description" msgid="1160281719576715211">"Nye samtaler vises som flytende ikoner eller bobler. Trykk for å åpne bobler. Dra for å flytte dem."</string>
<string name="bubbles_user_education_manage_title" msgid="2848511858160342320">"Kontrollér bobler når som helst"</string>
<string name="bubbles_user_education_manage" msgid="1391639189507036423">"Trykk på Administrer for å slå av bobler for denne appen"</string>
<string name="bubbles_user_education_got_it" msgid="8282812431953161143">"Greit"</string>
@@ -1024,11 +1014,14 @@
<string name="notification_content_system_nav_changed" msgid="5077913144844684544">"Systemnavigeringen er oppdatert. For å gjøre endringer, gå til Innstillinger."</string>
<string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"Gå til Innstillinger for å oppdatere systemnavigeringen"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Ventemodus"</string>
+ <string name="priority_onboarding_title" msgid="2893070698479227616">"Samtalen er satt som prioritert"</string>
+ <string name="priority_onboarding_behavior" msgid="5342816047020432929">"Dette skjer med prioriterte samtaler:"</string>
<string name="priority_onboarding_show_at_top_text" msgid="1678400241025513541">"Vis øverst i samtaledelen"</string>
<string name="priority_onboarding_show_avatar_text" msgid="5756291381124091508">"Vis profilbildet på låseskjermen"</string>
<string name="priority_onboarding_appear_as_bubble_text" msgid="4227039772250263122">"Vises som en svevende boble over apper"</string>
<string name="priority_onboarding_ignores_dnd_text" msgid="2918952762719600529">"Overstyr «Ikke forstyrr»"</string>
<string name="priority_onboarding_done_button_title" msgid="4569550984286506007">"Greit"</string>
+ <string name="priority_onboarding_settings_button_title" msgid="6663601574303585927">"Innstillinger"</string>
<string name="magnification_overlay_title" msgid="6584179429612427958">"Overleggsvindu for forstørring"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"Forstørringsvindu"</string>
<string name="magnification_controls_title" msgid="8421106606708891519">"Kontroller for forstørringsvindu"</string>
@@ -1070,9 +1063,13 @@
<string name="controls_structure_tooltip" msgid="4355922222944447867">"Sveip for å se flere"</string>
<string name="controls_seeding_in_progress" msgid="3033855341410264148">"Laster inn anbefalinger"</string>
<string name="controls_media_close_session" msgid="9023534788828414585">"Lukk denne medieøkten"</string>
+ <string name="controls_media_resume" msgid="1933520684481586053">"Gjenoppta"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"Inaktiv. Sjekk appen"</string>
<string name="controls_error_retryable" msgid="864025882878378470">"Feil. Prøver igjen …"</string>
- <string name="controls_error_removed" msgid="6299213591234723805">"Enheten er fjernet"</string>
+ <string name="controls_error_removed" msgid="6675638069846014366">"Ikke funnet"</string>
+ <string name="controls_error_removed_title" msgid="1207794911208047818">"Kontrollen er utilgjengelig"</string>
+ <string name="controls_error_removed_message" msgid="2885911717034750542">"Fikk ikke tilgang til <xliff:g id="DEVICE">%1$s</xliff:g>. Sjekk <xliff:g id="APPLICATION">%2$s</xliff:g>-appen for å sjekke at kontrollen fremdeles er tilgjengelig, og at appinnstillingene ikke er endret."</string>
+ <string name="controls_open_app" msgid="483650971094300141">"Åpne appen"</string>
<string name="controls_error_generic" msgid="352500456918362905">"Kan ikke laste inn status"</string>
<string name="controls_error_failed" msgid="960228639198558525">"En feil oppsto. Prøv på nytt"</string>
<string name="controls_in_progress" msgid="4421080500238215939">"Pågår"</string>
diff --git a/packages/SystemUI/res/values-ne/strings.xml b/packages/SystemUI/res/values-ne/strings.xml
index 8f703f9d0098..19cf233fa092 100644
--- a/packages/SystemUI/res/values-ne/strings.xml
+++ b/packages/SystemUI/res/values-ne/strings.xml
@@ -77,9 +77,6 @@
<string name="compat_mode_on" msgid="4963711187149440884">"स्क्रिन भर्न जुम गर्नुहोस्"</string>
<string name="compat_mode_off" msgid="7682459748279487945">"स्क्रिन भर्न तन्काउनुहोस्"</string>
<string name="global_action_screenshot" msgid="2760267567509131654">"स्क्रिनसट"</string>
- <string name="global_action_lock_message" product="default" msgid="4466026255205186456">"थप विकल्पहरू हेर्न आफ्नो फोन अनलक गर्नुहोस्"</string>
- <string name="global_action_lock_message" product="tablet" msgid="7621167597240332986">"थप विकल्पहरू हेर्न आफ्नो ट्याब्लेट अनलक गर्नुहोस्"</string>
- <string name="global_action_lock_message" product="device" msgid="538790401275363781">"थप विकल्पहरू हेर्न आफ्नो यन्त्र अनलक गर्नुहोस्"</string>
<string name="remote_input_image_insertion_text" msgid="4850791636452521123">"कुनै छवि पठाइयो"</string>
<string name="screenshot_saving_ticker" msgid="6519186952674544916">"स्क्रिनसट बचत गर्दै…"</string>
<string name="screenshot_saving_title" msgid="2298349784913287333">"स्क्रिनसट बचत गर्दै…"</string>
@@ -595,29 +592,21 @@
<string name="volume_odi_captions_hint_enable" msgid="2073091194012843195">"सक्षम पार्नुहोस्"</string>
<string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"असक्षम पार्नुहोस्"</string>
<string name="accessibility_output_chooser" msgid="7807898688967194183">"आउटपुट यन्त्र बदल्नुहोस्"</string>
- <!-- no translation found for screen_pinning_title (9058007390337841305) -->
- <skip />
+ <string name="screen_pinning_title" msgid="9058007390337841305">"एप पिन गरिएको छ"</string>
<string name="screen_pinning_description" msgid="8699395373875667743">"तपाईंले अनपिन नगरेसम्म यसले त्यसलाई दृश्यमा कायम राख्छ। अनपिन गर्न पछाडि र परिदृश्य बटनलाई छोइराख्नुहोस्।"</string>
<string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"तपाईंले अनपिन नगरेसम्म यसले त्यसलाई दृश्यमा कायम राख्छ। अनपिन गर्न पछाडि र गृह नामक बटनहरूलाई छोइराख्नुहोस्।"</string>
<string name="screen_pinning_description_gestural" msgid="7246323931831232068">"तपाईंले अनपिन नगरेसम्म यस कार्यले यसलाई दृश्यमा राख्छ। अनपिन गर्न माथितिर स्वाइप गरी होल्ड गर्नुहोस्।"</string>
<string name="screen_pinning_description_accessible" msgid="7386449191953535332">"तपाईंले अनपिन नगरेसम्म यसले त्यसलाई दृश्यमा कायम राख्छ। अनपिन गर्न परिदृश्य बटनलाई छोइराख्नुहोस्।"</string>
<string name="screen_pinning_description_recents_invisible_accessible" msgid="2857071808674481986">"तपाईंले अनपिन नगरेसम्म यसले त्यसलाई दृश्यमा कायम राख्छ। अनपिन गर्न गृह नामक बटनलाई छोइराख्नुहोस्।"</string>
- <!-- no translation found for screen_pinning_exposes_personal_data (8189852022981524789) -->
- <skip />
- <!-- no translation found for screen_pinning_can_open_other_apps (7529756813231421455) -->
- <skip />
- <!-- no translation found for screen_pinning_toast (8177286912533744328) -->
- <skip />
- <!-- no translation found for screen_pinning_toast_recents_invisible (6850978077443052594) -->
- <skip />
- <!-- no translation found for screen_pinning_toast_gesture_nav (170699893395336705) -->
- <skip />
+ <string name="screen_pinning_exposes_personal_data" msgid="8189852022981524789">"स्क्रिनमा व्यक्तिगत डेटा (जस्तै सम्पर्क ठेगाना र इमेलको सामग्री) देखिन सक्छ।"</string>
+ <string name="screen_pinning_can_open_other_apps" msgid="7529756813231421455">"पिन गरिएको एपले अन्य एप खोल्न सक्छ।"</string>
+ <string name="screen_pinning_toast" msgid="8177286912533744328">"यो एप अनपनि गर्न पछाडि र विवरण नामक बटनहरूलाई छोइराख्नुहोस्"</string>
+ <string name="screen_pinning_toast_recents_invisible" msgid="6850978077443052594">"यो एप अनपनि गर्न पछाडि र होम बटनलाई छोइराख्नुहोस्"</string>
+ <string name="screen_pinning_toast_gesture_nav" msgid="170699893395336705">"यो एप अनपिन गर्न माथितिर स्वाइप गरी स्क्रिनमा छोइराख्नुहोस्"</string>
<string name="screen_pinning_positive" msgid="3285785989665266984">"बुझेँ"</string>
<string name="screen_pinning_negative" msgid="6882816864569211666">"धन्यवाद पर्दैन"</string>
- <!-- no translation found for screen_pinning_start (7483998671383371313) -->
- <skip />
- <!-- no translation found for screen_pinning_exit (4553787518387346893) -->
- <skip />
+ <string name="screen_pinning_start" msgid="7483998671383371313">"एप पिन गरियो"</string>
+ <string name="screen_pinning_exit" msgid="4553787518387346893">"एप अनपिन गरियो"</string>
<string name="quick_settings_reset_confirmation_title" msgid="463533331480997595">"लुकाउनुहुन्छ <xliff:g id="TILE_LABEL">%1$s</xliff:g>?"</string>
<string name="quick_settings_reset_confirmation_message" msgid="2320586180785674186">"यो तपाईं सेटिङ् मा यो बारी अर्को समय देखापर्नेछ।"</string>
<string name="quick_settings_reset_confirmation_button" msgid="3341477479055016776">"लुकाउनुहोस्"</string>
@@ -730,7 +719,7 @@
<string name="notification_channel_summary_priority" msgid="7952654515769021553">"वार्तालाप खण्डको सिरानमा देखा पर्छ, तैरने बबलका रूपमा देखा पर्छ, लक स्क्रिनमा प्रोफाइल तस्बिर देखाइन्छ"</string>
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"सेटिङ"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"प्राथमिकता"</string>
- <string name="no_shortcut" msgid="7176375126961212514">"<xliff:g id="APP_NAME">%1$s</xliff:g> मा वार्तालापविशेषका लागि सेटिङ उपलब्ध छैन"</string>
+ <string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> मा वार्तालापसम्बन्धी सुविधा प्रयोग गर्न मिल्दैन"</string>
<string name="bubble_overflow_empty_title" msgid="3120029421991510842">"हालैका बबलहरू छैनन्"</string>
<string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"हालैका बबल र खारेज गरिएका बबलहरू यहाँ देखिने छन्"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"यी सूचनाहरू परिमार्जन गर्न मिल्दैन।"</string>
@@ -1013,7 +1002,8 @@
<string name="bubble_accessibility_action_move_top_right" msgid="6916868852433483569">"सिरानमा दायाँतिर सार्नुहोस्"</string>
<string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"पुछारमा बायाँतिर सार्नुहोस्"</string>
<string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"पुछारमा दायाँतिर सार्नुहोस्"</string>
- <string name="bubble_dismiss_text" msgid="7071770411580452911">"हटाउनुहोस्"</string>
+ <!-- no translation found for bubble_dismiss_text (1314082410868930066) -->
+ <skip />
<string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"वार्तालाप बबलको रूपमा नदेखाइयोस्"</string>
<string name="bubbles_user_education_title" msgid="5547017089271445797">"बबलहरू प्रयोग गरी कुराकानी गर्नुहोस्"</string>
<string name="bubbles_user_education_description" msgid="1160281719576715211">"नयाँ वार्तालापहरू तैरने आइकन वा बबलका रूपमा देखिन्छन्। बबल खोल्न ट्याप गर्नुहोस्। बबल सार्न सो बबललाई ड्र्याग गर्नुहोस्।"</string>
@@ -1024,11 +1014,17 @@
<string name="notification_content_system_nav_changed" msgid="5077913144844684544">"प्रणालीको नेभिगेसन अद्यावधिक गरियो। परिवर्तन गर्न सेटिङमा जानुहोस्।"</string>
<string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"प्रणालीको नेभिगेसन अद्यावधिक गर्न सेटिङमा जानुहोस्"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"स्ट्यान्डबाई"</string>
+ <!-- no translation found for priority_onboarding_title (2893070698479227616) -->
+ <skip />
+ <!-- no translation found for priority_onboarding_behavior (5342816047020432929) -->
+ <skip />
<string name="priority_onboarding_show_at_top_text" msgid="1678400241025513541">"वार्तालाप खण्डको सिरानमा देखाइयोस्"</string>
<string name="priority_onboarding_show_avatar_text" msgid="5756291381124091508">"लक स्क्रिनमा प्रोफाइल तस्बिर देखाइयोस्"</string>
<string name="priority_onboarding_appear_as_bubble_text" msgid="4227039772250263122">"एपहरूमाथि तैरिने बबलका रूपमा देखाइयोस्"</string>
<string name="priority_onboarding_ignores_dnd_text" msgid="2918952762719600529">"बाधा नपुऱ्याउनुहोस् मोडलाई बेवास्ता गरियोस्"</string>
<string name="priority_onboarding_done_button_title" msgid="4569550984286506007">"बुझेँ"</string>
+ <!-- no translation found for priority_onboarding_settings_button_title (6663601574303585927) -->
+ <skip />
<string name="magnification_overlay_title" msgid="6584179429612427958">"म्याग्निफिकेसन ओभरले विन्डो"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"म्याग्निफिकेसन विन्डो"</string>
<string name="magnification_controls_title" msgid="8421106606708891519">"म्याग्निफिकेसन विन्डोका नियन्त्रणहरू"</string>
@@ -1070,9 +1066,13 @@
<string name="controls_structure_tooltip" msgid="4355922222944447867">"थप हेर्न स्वाइप गर्नुहोस्"</string>
<string name="controls_seeding_in_progress" msgid="3033855341410264148">"सिफारिसहरू लोड गर्दै"</string>
<string name="controls_media_close_session" msgid="9023534788828414585">"यो मिडिया सत्र बन्द गर्नुहोस्"</string>
+ <string name="controls_media_resume" msgid="1933520684481586053">"सुचारु गर्नुहोस्"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"निष्क्रिय छ, एप जाँच गर्नु…"</string>
<string name="controls_error_retryable" msgid="864025882878378470">"त्रुटि भयो, फेरि प्रयास गर्दै…"</string>
- <string name="controls_error_removed" msgid="6299213591234723805">"यन्त्र हटाइयो"</string>
+ <string name="controls_error_removed" msgid="6675638069846014366">"फेला परेन"</string>
+ <string name="controls_error_removed_title" msgid="1207794911208047818">"नियन्त्रण सुविधा उपलब्ध छैन"</string>
+ <string name="controls_error_removed_message" msgid="2885911717034750542">"<xliff:g id="DEVICE">%1$s</xliff:g> माथि पहुँच राख्न सकिएन। यो नियन्त्रण सुविधा अझै पनि उपलब्ध छ र <xliff:g id="APPLICATION">%2$s</xliff:g> एपका सेटिङ परिवर्तन गरिएका छैनन् भन्ने कुरा सुनिश्चित गर्न यो एप जाँच्नुहोस्।"</string>
+ <string name="controls_open_app" msgid="483650971094300141">"एप खोल्नुहोस्"</string>
<string name="controls_error_generic" msgid="352500456918362905">"वस्तुस्थिति लोड गर्न सकिएन"</string>
<string name="controls_error_failed" msgid="960228639198558525">"त्रुटि भयो, फेरि प्रयास गर्नु…"</string>
<string name="controls_in_progress" msgid="4421080500238215939">"कार्य हुँदै छ"</string>
diff --git a/packages/SystemUI/res/values-night/styles.xml b/packages/SystemUI/res/values-night/styles.xml
index 4fdeb6fa4a92..50261e1b2139 100644
--- a/packages/SystemUI/res/values-night/styles.xml
+++ b/packages/SystemUI/res/values-night/styles.xml
@@ -29,4 +29,9 @@
<item name="android:textColor">?android:attr/textColorPrimary</item>
</style>
+ <style name="qs_security_footer" parent="@style/qs_theme">
+ <item name="android:textColor">#B3FFFFFF</item> <!-- 70% white -->
+ <item name="android:tint">#FFFFFFFF</item>
+ </style>
+
</resources>
diff --git a/packages/SystemUI/res/values-nl/strings.xml b/packages/SystemUI/res/values-nl/strings.xml
index bcf9c6189482..21e66ab67cd8 100644
--- a/packages/SystemUI/res/values-nl/strings.xml
+++ b/packages/SystemUI/res/values-nl/strings.xml
@@ -77,9 +77,6 @@
<string name="compat_mode_on" msgid="4963711187149440884">"Zoom om scherm te vullen"</string>
<string name="compat_mode_off" msgid="7682459748279487945">"Rek uit v. schermvulling"</string>
<string name="global_action_screenshot" msgid="2760267567509131654">"Screenshot"</string>
- <string name="global_action_lock_message" product="default" msgid="4466026255205186456">"Ontgrendel je telefoon voor meer opties"</string>
- <string name="global_action_lock_message" product="tablet" msgid="7621167597240332986">"Ontgrendel je tablet voor meer opties"</string>
- <string name="global_action_lock_message" product="device" msgid="538790401275363781">"Ontgrendel je apparaat voor meer opties"</string>
<string name="remote_input_image_insertion_text" msgid="4850791636452521123">"heeft een afbeelding gestuurd"</string>
<string name="screenshot_saving_ticker" msgid="6519186952674544916">"Screenshot opslaan..."</string>
<string name="screenshot_saving_title" msgid="2298349784913287333">"Screenshot opslaan..."</string>
@@ -722,7 +719,7 @@
<string name="notification_channel_summary_priority" msgid="7952654515769021553">"Wordt bovenaan het gedeelte met gesprekken weergegeven, verschijnt als zwevende bubbel, geeft de profielfoto weer op het vergrendelingsscherm"</string>
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"Instellingen"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"Prioriteit"</string>
- <string name="no_shortcut" msgid="7176375126961212514">"<xliff:g id="APP_NAME">%1$s</xliff:g> ondersteunt geen gespreksspecifieke instellingen"</string>
+ <string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> ondersteunt geen gespreksfuncties"</string>
<string name="bubble_overflow_empty_title" msgid="3120029421991510842">"Geen recente bubbels"</string>
<string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"Recente bubbels en gesloten bubbels worden hier weergegeven"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"Deze meldingen kunnen niet worden aangepast."</string>
@@ -1005,7 +1002,8 @@
<string name="bubble_accessibility_action_move_top_right" msgid="6916868852433483569">"Naar rechtsboven verplaatsen"</string>
<string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"Naar linksonder verplaatsen"</string>
<string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"Naar rechtsonder verplaatsen"</string>
- <string name="bubble_dismiss_text" msgid="7071770411580452911">"Sluiten"</string>
+ <!-- no translation found for bubble_dismiss_text (1314082410868930066) -->
+ <skip />
<string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"Gesprekken niet in bubbels weergeven"</string>
<string name="bubbles_user_education_title" msgid="5547017089271445797">"Chatten met bubbels"</string>
<string name="bubbles_user_education_description" msgid="1160281719576715211">"Nieuwe gesprekken worden weergegeven als zwevende iconen of \'bubbels\'. Tik om een bubbel te openen. Sleep om de bubbel te verplaatsen."</string>
@@ -1016,11 +1014,14 @@
<string name="notification_content_system_nav_changed" msgid="5077913144844684544">"Systeemnavigatie geüpdatet. Als je wijzigingen wilt aanbrengen, ga je naar Instellingen."</string>
<string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"Ga naar Instellingen om de systeemnavigatie te updaten"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Stand-by"</string>
+ <string name="priority_onboarding_title" msgid="2893070698479227616">"Gesprek ingesteld als prioriteit"</string>
+ <string name="priority_onboarding_behavior" msgid="5342816047020432929">"Bij prioriteitsgesprekken gebeurt het volgende:"</string>
<string name="priority_onboarding_show_at_top_text" msgid="1678400241025513541">"Worden bovenaan het gespreksgedeelte weergegeven"</string>
<string name="priority_onboarding_show_avatar_text" msgid="5756291381124091508">"Tonen profielafbeelding op vergrendelingsscherm"</string>
<string name="priority_onboarding_appear_as_bubble_text" msgid="4227039772250263122">"Worden als zwevende ballon weergegeven vóór apps"</string>
<string name="priority_onboarding_ignores_dnd_text" msgid="2918952762719600529">"Onderbreken \'Niet storen\'"</string>
<string name="priority_onboarding_done_button_title" msgid="4569550984286506007">"OK"</string>
+ <string name="priority_onboarding_settings_button_title" msgid="6663601574303585927">"Instellingen"</string>
<string name="magnification_overlay_title" msgid="6584179429612427958">"Overlay voor vergrotingsvenster"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"Vergrotingsvenster"</string>
<string name="magnification_controls_title" msgid="8421106606708891519">"Bediening van vergrotingsvenster"</string>
@@ -1056,15 +1057,19 @@
<string name="controls_pin_wrong" msgid="6162694056042164211">"Onjuiste pincode"</string>
<string name="controls_pin_verifying" msgid="3755045989392131746">"Verifiëren…"</string>
<string name="controls_pin_instructions" msgid="6363309783822475238">"Geef de pincode op"</string>
- <string name="controls_pin_instructions_retry" msgid="1566667581012131046">"Een andere pincode proberen"</string>
+ <string name="controls_pin_instructions_retry" msgid="1566667581012131046">"Andere pincode proberen"</string>
<string name="controls_confirmation_confirming" msgid="2596071302617310665">"Bevestigen…"</string>
<string name="controls_confirmation_message" msgid="7744104992609594859">"Bevestig de wijziging voor <xliff:g id="DEVICE">%s</xliff:g>"</string>
<string name="controls_structure_tooltip" msgid="4355922222944447867">"Swipe om meer te zien"</string>
<string name="controls_seeding_in_progress" msgid="3033855341410264148">"Aanbevelingen laden"</string>
<string name="controls_media_close_session" msgid="9023534788828414585">"Deze mediasessie sluiten"</string>
+ <string name="controls_media_resume" msgid="1933520684481586053">"Hervatten"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"Inactief, check de app"</string>
<string name="controls_error_retryable" msgid="864025882878378470">"Fout. Opnieuw proberen…"</string>
- <string name="controls_error_removed" msgid="6299213591234723805">"Apparaat verwijderd"</string>
+ <string name="controls_error_removed" msgid="6675638069846014366">"Niet gevonden"</string>
+ <string name="controls_error_removed_title" msgid="1207794911208047818">"Beheeroptie niet beschikbaar"</string>
+ <string name="controls_error_removed_message" msgid="2885911717034750542">"Kan geen toegang krijgen tot <xliff:g id="DEVICE">%1$s</xliff:g>. Check de <xliff:g id="APPLICATION">%2$s</xliff:g>-app om na te gaan of de beheeroptie nog steeds beschikbaar is en of de app-instellingen niet zijn gewijzigd."</string>
+ <string name="controls_open_app" msgid="483650971094300141">"App openen"</string>
<string name="controls_error_generic" msgid="352500456918362905">"Kan status niet laden"</string>
<string name="controls_error_failed" msgid="960228639198558525">"Fout, probeer het opnieuw"</string>
<string name="controls_in_progress" msgid="4421080500238215939">"Bezig"</string>
diff --git a/packages/SystemUI/res/values-or/strings.xml b/packages/SystemUI/res/values-or/strings.xml
index 73c36907ed8e..f575f9868427 100644
--- a/packages/SystemUI/res/values-or/strings.xml
+++ b/packages/SystemUI/res/values-or/strings.xml
@@ -77,9 +77,6 @@
<string name="compat_mode_on" msgid="4963711187149440884">"ସ୍କ୍ରୀନ ଭରିବା ପାଇଁ ଜୁମ୍ କରନ୍ତୁ"</string>
<string name="compat_mode_off" msgid="7682459748279487945">"ସ୍କ୍ରୀନ୍‌କୁ ଭରିବା ପାଇଁ ଟାଣନ୍ତୁ"</string>
<string name="global_action_screenshot" msgid="2760267567509131654">"ସ୍କ୍ରିନ୍‌ସଟ୍ ନିଅନ୍ତୁ"</string>
- <string name="global_action_lock_message" product="default" msgid="4466026255205186456">"ଅଧିକ ବିକଳ୍ପ ପାଇଁ ଆପଣଙ୍କ ଫୋନ୍ ଅନଲକ୍ କରନ୍ତୁ"</string>
- <string name="global_action_lock_message" product="tablet" msgid="7621167597240332986">"ଅଧିକ ବିକଳ୍ପ ପାଇଁ ଆପଣଙ୍କ ଟାବଲେଟ୍ ଅନଲକ୍ କରନ୍ତୁ"</string>
- <string name="global_action_lock_message" product="device" msgid="538790401275363781">"ଅଧିକ ବିକଳ୍ପ ପାଇଁ ଆପଣଙ୍କ ଡିଭାଇସ୍ ଅନଲକ୍ କରନ୍ତୁ"</string>
<string name="remote_input_image_insertion_text" msgid="4850791636452521123">"ଏକ ଛବି ପଠାଯାଇଛି"</string>
<string name="screenshot_saving_ticker" msgid="6519186952674544916">"ସ୍କ୍ରୀନଶଟ୍‍ ସେଭ୍‍ କରାଯାଉଛି…"</string>
<string name="screenshot_saving_title" msgid="2298349784913287333">"ସ୍କ୍ରୀନଶଟ୍‍ ସେଭ୍‍ କରାଯାଉଛି…"</string>
@@ -595,29 +592,21 @@
<string name="volume_odi_captions_hint_enable" msgid="2073091194012843195">"ସକ୍ଷମ କରନ୍ତୁ"</string>
<string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"ଅକ୍ଷମ କରନ୍ତୁ"</string>
<string name="accessibility_output_chooser" msgid="7807898688967194183">"ଆଉଟପୁଟ୍ ଡିଭାଇସ୍‌କୁ ଯାଆନ୍ତୁ"</string>
- <!-- no translation found for screen_pinning_title (9058007390337841305) -->
- <skip />
+ <string name="screen_pinning_title" msgid="9058007390337841305">"ଆପକୁ ପିନ୍ କରାଯାଇଛି"</string>
<string name="screen_pinning_description" msgid="8699395373875667743">"ଆପଣ ଅନପିନ୍‍ ନକରିବା ପର୍ଯ୍ୟନ୍ତ ଏହା ଦେଖାଉଥିବ। ଅନପିନ୍‍ କରିବାକୁ ସ୍ପର୍ଶ କରି ଧରିରଖନ୍ତୁ ଓ ଦେଖନ୍ତୁ।"</string>
<string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"ଆପଣ ଅନପିନ୍‍ ନକରିବା ପର୍ଯ୍ୟନ୍ତ ଏହା ଦେଖାଉଥିବ। ଅନପିନ୍‍ କରିବା ପାଇଁ ହୋମ୍ ଓ ବ୍ୟାକ୍ ବଟନ୍‌କୁ ଧରିରଖନ୍ତୁ।"</string>
<string name="screen_pinning_description_gestural" msgid="7246323931831232068">"ଆପଣ ଅନ୍‌ପିନ୍ ନକରିବା ପର୍ଯ୍ୟନ୍ତ ଏହା ଦେଖାଯାଉଥିବ। ଅନ୍‌ପିନ୍ କରିବା ପାଇଁ ଉପରକୁ ସ୍ୱାଇପ୍‌ କରି ଧରି ରଖନ୍ତୁ"</string>
<string name="screen_pinning_description_accessible" msgid="7386449191953535332">"ଆପଣ ଅନପିନ୍‍ ନକରିବା ପର୍ଯ୍ୟନ୍ତ ଏହା ଦେଖାଉଥିବ। ଅନପିନ୍‍ କରିବାକୁ ସ୍ପର୍ଶ କରନ୍ତୁ ଏବଂ ଓଭରଭ୍ୟୁକୁ ଧରିରଖନ୍ତୁ।"</string>
<string name="screen_pinning_description_recents_invisible_accessible" msgid="2857071808674481986">"ଆପଣ ଅନପିନ୍‍ ନକରିବା ପର୍ଯ୍ୟନ୍ତ ଏହା ଦେଖାଉଥିବ। ଅନପିନ୍‍ କରିବା ପର୍ଯ୍ୟନ୍ତ ହୋମ୍‌କୁ ଦାବିଧରନ୍ତୁ।"</string>
- <!-- no translation found for screen_pinning_exposes_personal_data (8189852022981524789) -->
- <skip />
- <!-- no translation found for screen_pinning_can_open_other_apps (7529756813231421455) -->
- <skip />
- <!-- no translation found for screen_pinning_toast (8177286912533744328) -->
- <skip />
- <!-- no translation found for screen_pinning_toast_recents_invisible (6850978077443052594) -->
- <skip />
- <!-- no translation found for screen_pinning_toast_gesture_nav (170699893395336705) -->
- <skip />
+ <string name="screen_pinning_exposes_personal_data" msgid="8189852022981524789">"ବ୍ୟକ୍ତିଗତ ଡାଟାକୁ ଆକ୍ସେସ୍ କରାଯାଇପାରେ (ଯେପରିକି ଯୋଗାଯୋଗଗୁଡ଼ିକ ଏବଂ ଇମେଲ୍ ବିଷୟବସ୍ତୁ)।"</string>
+ <string name="screen_pinning_can_open_other_apps" msgid="7529756813231421455">"ପିନ୍ କରାଯାଇଥିବା ଆପଟି ଅନ୍ୟ ଆପଗୁଡ଼ିକୁ ଖୋଲିପାରେ।"</string>
+ <string name="screen_pinning_toast" msgid="8177286912533744328">"ଏହି ଆପକୁ ଅନପିନ୍ କରିବା ପାଇଁ, \"ବ୍ୟାକ୍\" ଏବଂ \"ଓଭରଭିଉ\" ବଟନକୁ ସ୍ପର୍ଶ କରି ଧରି ରଖନ୍ତୁ"</string>
+ <string name="screen_pinning_toast_recents_invisible" msgid="6850978077443052594">"ଏହି ଆପକୁ ଅନପିନ୍ କରିବାକୁ, \"ବ୍ୟାକ୍\" ଏବଂ \"ହୋମ୍\" ବଟନକୁ ସ୍ପର୍ଶ କରି ଧରି ରଖନ୍ତୁ"</string>
+ <string name="screen_pinning_toast_gesture_nav" msgid="170699893395336705">"ଏହି ଆପକୁ ଅନପିନ୍ କରିବାକୁ, ଉପରକୁ ସ୍ୱାଇପ୍ କରି ଧରି ରଖନ୍ତୁ"</string>
<string name="screen_pinning_positive" msgid="3285785989665266984">"ବୁଝିଗଲି"</string>
<string name="screen_pinning_negative" msgid="6882816864569211666">"ନାହିଁ, ଥାଉ"</string>
- <!-- no translation found for screen_pinning_start (7483998671383371313) -->
- <skip />
- <!-- no translation found for screen_pinning_exit (4553787518387346893) -->
- <skip />
+ <string name="screen_pinning_start" msgid="7483998671383371313">"ଆପ୍ ପିନ୍ କରାଯାଇଛି"</string>
+ <string name="screen_pinning_exit" msgid="4553787518387346893">"ଆପ୍ ଅନପିନ୍ କରାଯାଇଛି"</string>
<string name="quick_settings_reset_confirmation_title" msgid="463533331480997595">"<xliff:g id="TILE_LABEL">%1$s</xliff:g> ଲୁଚାନ୍ତୁ?"</string>
<string name="quick_settings_reset_confirmation_message" msgid="2320586180785674186">"ଆଗକୁ ଆପଣ ଯେତେବେଳେ ଏହି ସେଟିଙ୍ଗକୁ ଚାଲୁ କରିବେ, ଏହା ପୁଣି ଦେଖାଦେବ।"</string>
<string name="quick_settings_reset_confirmation_button" msgid="3341477479055016776">"ଲୁଚାନ୍ତୁ"</string>
@@ -715,7 +704,7 @@
<string name="inline_minimize_button" msgid="1474436209299333445">"ଛୋଟ କରନ୍ତୁ"</string>
<string name="inline_silent_button_silent" msgid="525243786649275816">"ନୀରବ"</string>
<string name="inline_silent_button_stay_silent" msgid="2129254868305468743">"ନୀରବ ରହନ୍ତୁ"</string>
- <string name="inline_silent_button_alert" msgid="5705343216858250354">"ଆଲର୍ଟ କରିବା"</string>
+ <string name="inline_silent_button_alert" msgid="5705343216858250354">"ଆଲର୍ଟିଂ"</string>
<string name="inline_silent_button_keep_alerting" msgid="6577845442184724992">"ଆଲର୍ଟ କରିବା ଜାରି ରଖନ୍ତୁ"</string>
<string name="inline_turn_off_notifications" msgid="8543989584403106071">"ବିଜ୍ଞପ୍ତି ବନ୍ଦ କରନ୍ତୁ"</string>
<string name="inline_keep_showing_app" msgid="4393429060390649757">"ଏହି ଆପ୍‌ରୁ ବିଜ୍ଞପ୍ତିଗୁଡ଼ିକୁ ଦେଖାଇବା ଜାରି ରଖିବେ?"</string>
@@ -730,7 +719,7 @@
<string name="notification_channel_summary_priority" msgid="7952654515769021553">"ବାର୍ତ୍ତାଳାପ ବିଭାଗର ଶୀର୍ଷରେ ଦେଖାଏ, ଭାସମାନ ବବଲ୍ ଭାବେ ଦେଖାଯାଏ, ଲକ୍ ସ୍କ୍ରିନରେ ପ୍ରୋଫାଇଲ୍ ଛବି ଡିସପ୍ଲେ କରେ"</string>
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"ସେଟିଂସ୍"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"ପ୍ରାଥମିକତା"</string>
- <string name="no_shortcut" msgid="7176375126961212514">"<xliff:g id="APP_NAME">%1$s</xliff:g> ବାର୍ତ୍ତାଳାପ ସମ୍ବନ୍ଧିତ ନିର୍ଦ୍ଦିଷ୍ଟ ସେଟିଂସକୁ ସମର୍ଥନ କରେ ନାହିଁ"</string>
+ <string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> ବାର୍ତ୍ତାଳାପ ଫିଚରଗୁଡ଼ିକୁ ସମର୍ଥନ କରେ ନାହିଁ"</string>
<string name="bubble_overflow_empty_title" msgid="3120029421991510842">"ବର୍ତ୍ତମାନ କୌଣସି ବବଲ୍ ନାହିଁ"</string>
<string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"ବର୍ତ୍ତମାନର ଏବଂ ଖାରଜ କରାଯାଇଥିବା ବବଲଗୁଡ଼ିକ ଏଠାରେ ଦେଖାଯିବ"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"ଏହି ବିଜ୍ଞପ୍ତିଗୁଡ଼ିକ ପରିବର୍ତ୍ତନ କରିହେବ ନାହିଁ।"</string>
@@ -758,7 +747,7 @@
<string name="notification_conversation_favorite" msgid="1905240206975921907">"ଗୁରୁତ୍ୱପୂର୍ଣ୍ଣ ବାର୍ତ୍ତାଳାପ"</string>
<string name="notification_conversation_unfavorite" msgid="181383708304763807">"କୌଣସି ଗୁରୁତ୍ୱପୂର୍ଣ୍ଣ ବାର୍ତ୍ତାଳାପ ନାହିଁ"</string>
<string name="notification_conversation_mute" msgid="268951550222925548">"ନିରବ କରାଯାଇଛି"</string>
- <string name="notification_conversation_unmute" msgid="2692255619510896710">"ଆଲର୍ଟ କରୁଛି"</string>
+ <string name="notification_conversation_unmute" msgid="2692255619510896710">"ଆଲର୍ଟିଂ"</string>
<string name="notification_conversation_bubble" msgid="2242180995373949022">"ବବଲ୍ ଦେଖାନ୍ତୁ"</string>
<string name="notification_conversation_unbubble" msgid="6908427185031099868">"ବବଲଗୁଡ଼ିକ କାଢ଼ି ଦିଅନ୍ତୁ"</string>
<string name="notification_conversation_home_screen" msgid="8347136037958438935">"ମୂଳ ସ୍କ୍ରିନରେ ଯୋଗ କରନ୍ତୁ"</string>
@@ -1013,7 +1002,8 @@
<string name="bubble_accessibility_action_move_top_right" msgid="6916868852433483569">"ଉପର-ଡାହାଣକୁ ନିଅନ୍ତୁ"</string>
<string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"ତଳ ବାମକୁ ନିଅନ୍ତୁ"</string>
<string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"ତଳ ଡାହାଣକୁ ନିଅନ୍ତୁ"</string>
- <string name="bubble_dismiss_text" msgid="7071770411580452911">"ଖାରଜ କରନ୍ତୁ"</string>
+ <!-- no translation found for bubble_dismiss_text (1314082410868930066) -->
+ <skip />
<string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"ବାର୍ତ୍ତାଳାପକୁ ବବଲ୍ କରନ୍ତୁ ନାହିଁ"</string>
<string name="bubbles_user_education_title" msgid="5547017089271445797">"ବବଲଗୁଡ଼ିକୁ ବ୍ୟବହାର କରି ଚାଟ୍ କରନ୍ତୁ"</string>
<string name="bubbles_user_education_description" msgid="1160281719576715211">"ନୂଆ ବାର୍ତ୍ତାଳାପଗୁଡ଼ିକ ଫ୍ଲୋଟିଂ ଆଇକନ୍ କିମ୍ବା ବବଲ୍ ଭାବେ ଦେଖାଯିବ। ବବଲ୍ ଖୋଲିବାକୁ ଟାପ୍ କରନ୍ତୁ। ଏହାକୁ ମୁଭ୍ କରିବାକୁ ଟାଣନ୍ତୁ।"</string>
@@ -1024,11 +1014,17 @@
<string name="notification_content_system_nav_changed" msgid="5077913144844684544">"ସିଷ୍ଟମ୍ ନାଭିଗେସନ୍ ଅପ୍‌ଡେଟ୍ ହୋଇଛି। ପରିବର୍ତ୍ତନ କରିବା ପାଇଁ, ସେଟିଂସ୍‌କୁ ଯାଆନ୍ତୁ।"</string>
<string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"ସିଷ୍ଟମ୍ ନାଭିଗେସନ୍ ଅପ୍‌ଡେଟ୍ କରିବା ପାଇଁ ସେଟିଂସ୍‍କୁ ଯାଆନ୍ତୁ"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"ଷ୍ଟାଣ୍ଡବାଏ"</string>
+ <!-- no translation found for priority_onboarding_title (2893070698479227616) -->
+ <skip />
+ <!-- no translation found for priority_onboarding_behavior (5342816047020432929) -->
+ <skip />
<string name="priority_onboarding_show_at_top_text" msgid="1678400241025513541">"ବାର୍ତ୍ତାଳାପ ବିଭାଗର ଶୀର୍ଷରେ ଦେଖାନ୍ତୁ"</string>
<string name="priority_onboarding_show_avatar_text" msgid="5756291381124091508">"ଲକ୍ ସ୍କ୍ରିନରେ ପ୍ରୋଫାଇଲ୍ ଛବି ଦେଖାନ୍ତୁ"</string>
<string name="priority_onboarding_appear_as_bubble_text" msgid="4227039772250263122">"ଆପଗୁଡ଼ିକ ଉପରେ ଫ୍ଲୋଟିଂ ବବଲ୍ ପରି ଦେଖାଯିବ"</string>
<string name="priority_onboarding_ignores_dnd_text" msgid="2918952762719600529">"\'ବିରକ୍ତ କରନ୍ତୁ ନାହିଁ\' ମୋଡରେ ବାଧା"</string>
<string name="priority_onboarding_done_button_title" msgid="4569550984286506007">"ବୁଝିଗଲି"</string>
+ <!-- no translation found for priority_onboarding_settings_button_title (6663601574303585927) -->
+ <skip />
<string name="magnification_overlay_title" msgid="6584179429612427958">"ମ୍ୟାଗ୍ନିଫିକେସନ୍ ଓଭର୍‌ଲେ ୱିଣ୍ଡୋ"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"ମ୍ୟାଗ୍ନିଫିକେସନ୍ ୱିଣ୍ଡୋ"</string>
<string name="magnification_controls_title" msgid="8421106606708891519">"ମ୍ୟାଗ୍ନିଫିକେସନ୍ ୱିଣ୍ଡୋ ନିୟନ୍ତ୍ରଣଗୁଡ଼ିକ"</string>
@@ -1059,7 +1055,7 @@
<string name="controls_dialog_ok" msgid="2770230012857881822">"ଯୋଗ କରନ୍ତୁ"</string>
<string name="controls_dialog_message" msgid="342066938390663844">"<xliff:g id="APP">%s</xliff:g> ଦ୍ଵାରା ପ୍ରସ୍ତାବିତ"</string>
<string name="controls_dialog_confirmation" msgid="586517302736263447">"ନିୟନ୍ତ୍ରଣଗୁଡ଼ିକ ଅପଡେଟ୍ କରାଯାଇଛି"</string>
- <string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"PINରେ ଅକ୍ଷର କିମ୍ୱା ସଙ୍କେତଗୁଡ଼ିକ ଥାଏ"</string>
+ <string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"PINରେ ଅକ୍ଷର କିମ୍ୱା ପ୍ରତୀକଗୁଡ଼ିକ ଥାଏ"</string>
<string name="controls_pin_verify" msgid="3452778292918877662">"<xliff:g id="DEVICE">%s</xliff:g> ଯାଞ୍ଚ କରନ୍ତୁ"</string>
<string name="controls_pin_wrong" msgid="6162694056042164211">"ଭୁଲ PIN"</string>
<string name="controls_pin_verifying" msgid="3755045989392131746">"ଯାଞ୍ଚ କରାଯାଉଛି…"</string>
@@ -1070,9 +1066,13 @@
<string name="controls_structure_tooltip" msgid="4355922222944447867">"ଅଧିକ ଦେଖିବାକୁ ସ୍ୱାଇପ୍ କରନ୍ତୁ"</string>
<string name="controls_seeding_in_progress" msgid="3033855341410264148">"ସୁପାରିଶଗୁଡ଼ିକ ଲୋଡ୍ କରାଯାଉଛି"</string>
<string name="controls_media_close_session" msgid="9023534788828414585">"ଏହି ମିଡିଆ ସେସନ୍ ବନ୍ଦ କରନ୍ତୁ"</string>
+ <string name="controls_media_resume" msgid="1933520684481586053">"ପୁଣି ଆରମ୍ଭ କରନ୍ତୁ"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"ନିଷ୍କ୍ରିୟ ଅଛି, ଆପ ଯାଞ୍ଚ କରନ୍ତୁ"</string>
<string name="controls_error_retryable" msgid="864025882878378470">"ତ୍ରୁଟି, ପୁଣି ଚେଷ୍ଟା କରୁଛି…"</string>
- <string name="controls_error_removed" msgid="6299213591234723805">"ଡିଭାଇସ୍ କାଢ଼ି ଦିଆଯାଇଛି"</string>
+ <string name="controls_error_removed" msgid="6675638069846014366">"ମିଳୁ ନାହିଁ"</string>
+ <string name="controls_error_removed_title" msgid="1207794911208047818">"ନିୟନ୍ତ୍ରଣ ଉପଲବ୍ଧ ନାହିଁ"</string>
+ <string name="controls_error_removed_message" msgid="2885911717034750542">"<xliff:g id="DEVICE">%1$s</xliff:g>କୁ ଆକ୍ସେସ୍ କରିହେଲା ନାହିଁ। ନିୟନ୍ତ୍ରଣ ଏବେ ବି ଉପଲବ୍ଧ ଅଛି ଏବଂ ଆପ୍ ସେଟିଂସ୍ ବଦଳାଯାଇ ନାହିଁ ବୋଲି ସୁନିଶ୍ଚିତ କରିବାକୁ <xliff:g id="APPLICATION">%2$s</xliff:g> ଆପ୍ ଯାଞ୍ଚ କରନ୍ତୁ।"</string>
+ <string name="controls_open_app" msgid="483650971094300141">"ଆପ୍ ଖୋଲନ୍ତୁ"</string>
<string name="controls_error_generic" msgid="352500456918362905">"ସ୍ଥିତି ଲୋଡ୍ କରାଯାଇପାରିବ ନାହିଁ"</string>
<string name="controls_error_failed" msgid="960228639198558525">"ତ୍ରୁଟି ହୋଇଛି, ପୁଣି ଚେଷ୍ଟା କର"</string>
<string name="controls_in_progress" msgid="4421080500238215939">"ପ୍ରଗତିରେ ଅଛି"</string>
diff --git a/packages/SystemUI/res/values-pa/strings.xml b/packages/SystemUI/res/values-pa/strings.xml
index 59009a1f94b0..3389a18c8f9c 100644
--- a/packages/SystemUI/res/values-pa/strings.xml
+++ b/packages/SystemUI/res/values-pa/strings.xml
@@ -77,9 +77,6 @@
<string name="compat_mode_on" msgid="4963711187149440884">"ਸਕ੍ਰੀਨ ਭਰਨ ਲਈ ਜ਼ੂਮ ਕਰੋ"</string>
<string name="compat_mode_off" msgid="7682459748279487945">"ਸਕ੍ਰੀਨ ਭਰਨ ਲਈ ਸਟ੍ਰੈਚ ਕਰੋ"</string>
<string name="global_action_screenshot" msgid="2760267567509131654">"ਸਕ੍ਰੀਨਸ਼ਾਟ"</string>
- <string name="global_action_lock_message" product="default" msgid="4466026255205186456">"ਹੋਰ ਵਿਕਲਪਾਂ ਲਈ ਆਪਣਾ ਫ਼ੋਨ ਅਣਲਾਕ ਕਰੋ"</string>
- <string name="global_action_lock_message" product="tablet" msgid="7621167597240332986">"ਹੋਰ ਵਿਕਲਪਾਂ ਲਈ ਆਪਣਾ ਟੈਬਲੈੱਟ ਅਣਲਾਕ ਕਰੋ"</string>
- <string name="global_action_lock_message" product="device" msgid="538790401275363781">"ਹੋਰ ਵਿਕਲਪਾਂ ਲਈ ਆਪਣਾ ਡੀਵਾਈਸ ਅਣਲਾਕ ਕਰੋ"</string>
<string name="remote_input_image_insertion_text" msgid="4850791636452521123">"ਚਿੱਤਰ ਭੇਜਿਆ ਗਿਆ"</string>
<string name="screenshot_saving_ticker" msgid="6519186952674544916">"ਸਕ੍ਰੀਨਸ਼ਾਟ ਸੁਰੱਖਿਅਤ ਕਰ ਰਿਹਾ ਹੈ…"</string>
<string name="screenshot_saving_title" msgid="2298349784913287333">"ਸਕ੍ਰੀਨਸ਼ਾਟ ਸੁਰੱਖਿਅਤ ਕਰ ਰਿਹਾ ਹੈ…"</string>
@@ -276,7 +273,7 @@
<string name="accessibility_quick_settings_airplane_on" msgid="8106176561295294255">"ਏਅਰਪਲੇਨ ਮੋਡ ਚਾਲੂ।"</string>
<string name="accessibility_quick_settings_airplane_changed_off" msgid="8880183481476943754">"ਏਅਰਪਲੇਨ ਮੋਡ ਬੰਦ ਹੈ।"</string>
<string name="accessibility_quick_settings_airplane_changed_on" msgid="6327378061894076288">"ਏਅਰਪਲੇਨ ਮੋਡ ਚਾਲੂ ਹੋਇਆ"</string>
- <string name="accessibility_quick_settings_dnd_none_on" msgid="3235552940146035383">"ਸੰਪੂਰਨ ਖਾਮੋਸ਼ੀ"</string>
+ <string name="accessibility_quick_settings_dnd_none_on" msgid="3235552940146035383">"ਪੂਰਾ ਸ਼ਾਂਤ"</string>
<string name="accessibility_quick_settings_dnd_alarms_on" msgid="3375848309132140014">"ਸਿਰਫ਼ ਅਲਾਰਮ"</string>
<string name="accessibility_quick_settings_dnd" msgid="2415967452264206047">"ਪਰੇਸ਼ਾਨ ਨਾ ਕਰੋ।"</string>
<string name="accessibility_quick_settings_dnd_changed_off" msgid="1457150026842505799">"\'ਪਰੇਸ਼ਾਨ ਨਾ ਕਰੋ\' ਨੂੰ ਬੰਦ ਕੀਤਾ ਗਿਆ।"</string>
@@ -722,7 +719,7 @@
<string name="notification_channel_summary_priority" msgid="7952654515769021553">"ਗੱਲਬਾਤ ਸੈਕਸ਼ਨ ਦੇ ਸਿਖਰ \'ਤੇ ਦਿਖਾਈਆਂ ਜਾਂਦੀਆਂ ਹਨ, ਬਬਲ ਵਜੋਂ ਦਿਸਦੀਆਂ ਹਨ, ਲਾਕ ਸਕ੍ਰੀਨ \'ਤੇ ਪ੍ਰੋਫਾਈਲ ਤਸਵੀਰ ਦਿਖਾਈ ਜਾਂਦੀ ਹੈ"</string>
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"ਸੈਟਿੰਗਾਂ"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"ਤਰਜੀਹ"</string>
- <string name="no_shortcut" msgid="7176375126961212514">"<xliff:g id="APP_NAME">%1$s</xliff:g> ਗੱਲਬਾਤ ਸੰਬੰਧੀ ਵਿਸ਼ੇਸ਼ ਸੈਟਿੰਗਾਂ ਦਾ ਸਮਰਥਨ ਨਹੀਂ ਕਰਦੀ"</string>
+ <string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> ਐਪ ਗੱਲਬਾਤ ਵਿਸ਼ੇਸ਼ਤਾਵਾਂ ਦਾ ਸਮਰਥਨ ਨਹੀਂ ਕਰਦੀ"</string>
<string name="bubble_overflow_empty_title" msgid="3120029421991510842">"ਕੋਈ ਹਾਲੀਆ ਬਬਲ ਨਹੀਂ"</string>
<string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"ਹਾਲੀਆ ਬਬਲ ਅਤੇ ਖਾਰਜ ਕੀਤੇ ਬਬਲ ਇੱਥੇ ਦਿਸਣਗੇ"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"ਇਹਨਾਂ ਸੂਚਨਾਵਾਂ ਨੂੰ ਸੋਧਿਆ ਨਹੀਂ ਜਾ ਸਕਦਾ।"</string>
@@ -1005,7 +1002,8 @@
<string name="bubble_accessibility_action_move_top_right" msgid="6916868852433483569">"ਉੱਪਰ ਵੱਲ ਸੱਜੇ ਲਿਜਾਓ"</string>
<string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"ਹੇਠਾਂ ਵੱਲ ਖੱਬੇ ਲਿਜਾਓ"</string>
<string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"ਹੇਠਾਂ ਵੱਲ ਸੱਜੇ ਲਿਜਾਓ"</string>
- <string name="bubble_dismiss_text" msgid="7071770411580452911">"ਖਾਰਜ ਕਰੋ"</string>
+ <!-- no translation found for bubble_dismiss_text (1314082410868930066) -->
+ <skip />
<string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"ਗੱਲਬਾਤ \'ਤੇ ਬਬਲ ਨਾ ਲਾਓ"</string>
<string name="bubbles_user_education_title" msgid="5547017089271445797">"ਬਬਲ ਵਰਤਦੇ ਹੋਏ ਚੈਟ ਕਰੋ"</string>
<string name="bubbles_user_education_description" msgid="1160281719576715211">"ਨਵੀਆਂ ਗੱਲਾਂਬਾਤਾਂ ਫਲੋਟਿੰਗ ਪ੍ਰਤੀਕਾਂ ਜਾਂ ਬਬਲ ਦੇ ਰੂਪ ਵਿੱਚ ਦਿਸਦੀਆਂ ਹਨ। ਬਬਲ ਨੂੰ ਖੋਲ੍ਹਣ ਲਈ ਟੈਪ ਕਰੋ। ਇਸਨੂੰ ਲਿਜਾਣ ਲਈ ਘਸੀਟੋ।"</string>
@@ -1016,11 +1014,14 @@
<string name="notification_content_system_nav_changed" msgid="5077913144844684544">"ਸਿਸਟਮ ਨੈਵੀਗੇਸ਼ਨ ਅੱਪਡੇਟ ਹੋ ਗਿਆ। ਤਬਦੀਲੀਆਂ ਕਰਨ ਲਈ, ਸੈਟਿੰਗਾਂ \'ਤੇ ਜਾਓ।"</string>
<string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"ਸਿਸਟਮ ਨੈਵੀਗੇਸ਼ਨ ਨੂੰ ਅੱਪਡੇਟ ਕਰਨ ਲਈ ਸੈਟਿੰਗਾਂ \'ਤੇ ਜਾਓ"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"ਸਟੈਂਡਬਾਈ"</string>
+ <string name="priority_onboarding_title" msgid="2893070698479227616">"ਗੱਲਬਾਤ ਨੂੰ ਤਰਜੀਹੀ ਗੱਲਬਾਤ ਵਜੋਂ ਸੈੱਟ ਕੀਤਾ ਗਿਆ"</string>
+ <string name="priority_onboarding_behavior" msgid="5342816047020432929">"ਤਰਜੀਹੀ ਗੱਲਾਂਬਾਤਾਂ ਇਹ ਹੋਣਗੀਆਂ:"</string>
<string name="priority_onboarding_show_at_top_text" msgid="1678400241025513541">"ਗੱਲਬਾਤ ਸੈਕਸ਼ਨ ਦੇ ਸਿਖਰ \'ਤੇ ਦਿਖਾਓ"</string>
<string name="priority_onboarding_show_avatar_text" msgid="5756291381124091508">"ਲਾਕ ਸਕ੍ਰੀਨ \'ਤੇ ਪ੍ਰੋਫਾਈਲ ਤਸਵੀਰ ਦਿਖਾਓ"</string>
<string name="priority_onboarding_appear_as_bubble_text" msgid="4227039772250263122">"ਐਪਾਂ ਦੇ ਸਿਖਰ \'ਤੇ ਫਲੋਟਿੰਗ ਬਬਲ ਵਜੋਂ ਦਿਸਦੀਆਂ ਹਨ"</string>
<string name="priority_onboarding_ignores_dnd_text" msgid="2918952762719600529">"\'ਪਰੇਸ਼ਾਨ ਨਾ ਕਰੋ\' ਸੈਟਿੰਗਾਂ ਵਿੱਚ ਵਿਘਨ ਪੈ ਸਕਦਾ ਹੈ"</string>
<string name="priority_onboarding_done_button_title" msgid="4569550984286506007">"ਸਮਝ ਲਿਆ"</string>
+ <string name="priority_onboarding_settings_button_title" msgid="6663601574303585927">"ਸੈਟਿੰਗਾਂ"</string>
<string name="magnification_overlay_title" msgid="6584179429612427958">"ਵੱਡਦਰਸ਼ੀਕਰਨ ਓਵਰਲੇ Window"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"ਵੱਡਦਰਸ਼ੀਕਰਨ Window"</string>
<string name="magnification_controls_title" msgid="8421106606708891519">"ਵੱਡਦਰਸ਼ੀਕਰਨ Window ਦੇ ਕੰਟਰੋਲ"</string>
@@ -1028,7 +1029,7 @@
<string name="quick_controls_subtitle" msgid="1667408093326318053">"ਆਪਣੇ ਕਨੈਕਟ ਕੀਤੇ ਡੀਵਾਈਸਾਂ ਲਈ ਕੰਟਰੋਲ ਸ਼ਾਮਲ ਕਰੋ"</string>
<string name="quick_controls_setup_title" msgid="8901436655997849822">"ਡੀਵਾਈਸ ਕੰਟਰੋਲਾਂ ਦਾ ਸੈੱਟਅੱਪ ਕਰੋ"</string>
<string name="quick_controls_setup_subtitle" msgid="1681506617879773824">"ਆਪਣੇ ਕੰਟਰੋਲਾਂ ਤੱਕ ਪਹੁੰਚ ਕਰਨ ਲਈ ਪਾਵਰ ਬਟਨ ਦਬਾ ਕੇ ਰੱਖੋ"</string>
- <string name="controls_providers_title" msgid="6879775889857085056">"ਕੰਟਰੋਲਾਂ ਨੂੰ ਸ਼ਾਮਲ ਕਰਨ ਲਈ ਐਪ ਚੁਣੋ"</string>
+ <string name="controls_providers_title" msgid="6879775889857085056">"ਕੰਟਰੋਲ ਸ਼ਾਮਲ ਕਰਨ ਲਈ ਐਪ ਚੁਣੋ"</string>
<plurals name="controls_number_of_favorites" formatted="false" msgid="1057347832073807380">
<item quantity="one"><xliff:g id="NUMBER_1">%s</xliff:g> ਕੰਟਰੋਲ ਸ਼ਾਮਲ ਕੀਤਾ ਗਿਆ।</item>
<item quantity="other"><xliff:g id="NUMBER_1">%s</xliff:g> ਕੰਟਰੋਲ ਸ਼ਾਮਲ ਕੀਤੇ ਗਏ।</item>
@@ -1062,9 +1063,13 @@
<string name="controls_structure_tooltip" msgid="4355922222944447867">"ਹੋਰ ਦੇਖਣ ਲਈ ਸਵਾਈਪ ਕਰੋ"</string>
<string name="controls_seeding_in_progress" msgid="3033855341410264148">"ਸਿਫ਼ਾਰਸ਼ਾਂ ਲੋਡ ਹੋ ਰਹੀਆਂ ਹਨ"</string>
<string name="controls_media_close_session" msgid="9023534788828414585">"ਇਸ ਮੀਡੀਆ ਸੈਸ਼ਨ ਨੂੰ ਬੰਦ ਕਰੋ"</string>
+ <string name="controls_media_resume" msgid="1933520684481586053">"ਮੁੜ-ਚਾਲੂ ਕਰੋ"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"ਅਕਿਰਿਆਸ਼ੀਲ, ਐਪ ਦੀ ਜਾਂਚ ਕਰੋ"</string>
<string name="controls_error_retryable" msgid="864025882878378470">"ਗੜਬੜ, ਮੁੜ ਕੋਸ਼ਿਸ਼ ਹੋ ਰਹੀ ਹੈ…"</string>
- <string name="controls_error_removed" msgid="6299213591234723805">"ਡੀਵਾਈਸ ਹਟਾਇਆ ਗਿਆ"</string>
+ <string name="controls_error_removed" msgid="6675638069846014366">"ਨਹੀਂ ਮਿਲਿਆ"</string>
+ <string name="controls_error_removed_title" msgid="1207794911208047818">"ਕੰਟਰੋਲ ਉਪਲਬਧ ਨਹੀਂ ਹੈ"</string>
+ <string name="controls_error_removed_message" msgid="2885911717034750542">"<xliff:g id="DEVICE">%1$s</xliff:g> ਤੱਕ ਪਹੁੰਚ ਨਹੀਂ ਕੀਤੀ ਜਾ ਸਕੀ। ਇਹ ਪੱਕਾ ਕਰਨ ਲਈ <xliff:g id="APPLICATION">%2$s</xliff:g> ਐਪ ਦੀ ਜਾਂਚ ਕਰੋ ਕਿ ਕੰਟਰੋਲ ਹਾਲੇ ਵੀ ਉਪਲਬਧ ਹੈ ਅਤੇ ਐਪ ਸੈਟਿੰਗ ਬਦਲੀ ਨਹੀਂ ਹੈ।"</string>
+ <string name="controls_open_app" msgid="483650971094300141">"ਐਪ ਖੋਲ੍ਹੋ"</string>
<string name="controls_error_generic" msgid="352500456918362905">"ਸਥਿਤੀ ਲੋਡ ਨਹੀਂ ਕੀਤੀ ਜਾ ਸਕਦੀ"</string>
<string name="controls_error_failed" msgid="960228639198558525">"ਗੜਬੜ, ਦੁਬਾਰਾ ਕੋਸ਼ਿਸ਼ ਕਰੋ"</string>
<string name="controls_in_progress" msgid="4421080500238215939">"ਜਾਰੀ ਹੈ"</string>
diff --git a/packages/SystemUI/res/values-pl/strings.xml b/packages/SystemUI/res/values-pl/strings.xml
index 59fa13cad8f1..e85b76f228ac 100644
--- a/packages/SystemUI/res/values-pl/strings.xml
+++ b/packages/SystemUI/res/values-pl/strings.xml
@@ -77,9 +77,6 @@
<string name="compat_mode_on" msgid="4963711187149440884">"Powiększ, aby wypełnić ekran"</string>
<string name="compat_mode_off" msgid="7682459748279487945">"Rozciągnij, aby wypełnić ekran"</string>
<string name="global_action_screenshot" msgid="2760267567509131654">"Zrzut ekranu"</string>
- <string name="global_action_lock_message" product="default" msgid="4466026255205186456">"Odblokuj telefon, by wyświetlić więcej opcji"</string>
- <string name="global_action_lock_message" product="tablet" msgid="7621167597240332986">"Odblokuj tablet, by wyświetlić więcej opcji"</string>
- <string name="global_action_lock_message" product="device" msgid="538790401275363781">"Odblokuj urządzenie, by wyświetlić więcej opcji"</string>
<string name="remote_input_image_insertion_text" msgid="4850791636452521123">"wysłano obraz"</string>
<string name="screenshot_saving_ticker" msgid="6519186952674544916">"Zapisywanie zrzutu ekranu..."</string>
<string name="screenshot_saving_title" msgid="2298349784913287333">"Zapisywanie zrzutu ekranu..."</string>
@@ -601,29 +598,21 @@
<string name="volume_odi_captions_hint_enable" msgid="2073091194012843195">"włącz"</string>
<string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"wyłącz"</string>
<string name="accessibility_output_chooser" msgid="7807898688967194183">"Przełącz urządzenie wyjściowe"</string>
- <!-- no translation found for screen_pinning_title (9058007390337841305) -->
- <skip />
+ <string name="screen_pinning_title" msgid="9058007390337841305">"Aplikacja jest przypięta"</string>
<string name="screen_pinning_description" msgid="8699395373875667743">"Ekran będzie widoczny, dopóki go nie odepniesz. Aby to zrobić, kliknij i przytrzymaj Wstecz oraz Przegląd."</string>
<string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"Ekran będzie widoczny, dopóki go nie odepniesz. Aby to zrobić, naciśnij i przytrzymaj Wstecz oraz Ekran główny."</string>
<string name="screen_pinning_description_gestural" msgid="7246323931831232068">"Ekran będzie widoczny, dopóki go nie odepniesz. Przesuń palcem w górę i przytrzymaj, by odpiąć."</string>
<string name="screen_pinning_description_accessible" msgid="7386449191953535332">"Ekran będzie widoczny, dopóki go nie odepniesz. Aby to zrobić, kliknij i przytrzymaj Przegląd."</string>
<string name="screen_pinning_description_recents_invisible_accessible" msgid="2857071808674481986">"Ekran będzie widoczny, dopóki go nie odepniesz. Aby to zrobić, naciśnij i przytrzymaj Ekran główny."</string>
- <!-- no translation found for screen_pinning_exposes_personal_data (8189852022981524789) -->
- <skip />
- <!-- no translation found for screen_pinning_can_open_other_apps (7529756813231421455) -->
- <skip />
- <!-- no translation found for screen_pinning_toast (8177286912533744328) -->
- <skip />
- <!-- no translation found for screen_pinning_toast_recents_invisible (6850978077443052594) -->
- <skip />
- <!-- no translation found for screen_pinning_toast_gesture_nav (170699893395336705) -->
- <skip />
+ <string name="screen_pinning_exposes_personal_data" msgid="8189852022981524789">"Dane osobowe mogą być dostępne (np. kontakty czy treść e-maili)."</string>
+ <string name="screen_pinning_can_open_other_apps" msgid="7529756813231421455">"Przypięta aplikacja może otwierać inne aplikacje."</string>
+ <string name="screen_pinning_toast" msgid="8177286912533744328">"Aby odpiąć tę aplikację, naciśnij i przytrzymaj przyciski Wstecz oraz Przegląd"</string>
+ <string name="screen_pinning_toast_recents_invisible" msgid="6850978077443052594">"Aby odpiąć tę aplikację, naciśnij i przytrzymaj przyciski Wstecz oraz Ekran główny"</string>
+ <string name="screen_pinning_toast_gesture_nav" msgid="170699893395336705">"Aby odpiąć tę aplikację, przesuń w górę i przytrzymaj"</string>
<string name="screen_pinning_positive" msgid="3285785989665266984">"OK"</string>
<string name="screen_pinning_negative" msgid="6882816864569211666">"Nie, dziękuję"</string>
- <!-- no translation found for screen_pinning_start (7483998671383371313) -->
- <skip />
- <!-- no translation found for screen_pinning_exit (4553787518387346893) -->
- <skip />
+ <string name="screen_pinning_start" msgid="7483998671383371313">"Aplikacja przypięta"</string>
+ <string name="screen_pinning_exit" msgid="4553787518387346893">"Aplikacja odpięta"</string>
<string name="quick_settings_reset_confirmation_title" msgid="463533331480997595">"Ukryć <xliff:g id="TILE_LABEL">%1$s</xliff:g>?"</string>
<string name="quick_settings_reset_confirmation_message" msgid="2320586180785674186">"Pojawi się ponownie, gdy następnym włączysz go w ustawieniach."</string>
<string name="quick_settings_reset_confirmation_button" msgid="3341477479055016776">"Ukryj"</string>
@@ -736,7 +725,7 @@
<string name="notification_channel_summary_priority" msgid="7952654515769021553">"Wyświetla się jako pływający dymek u góry sekcji rozmów, pokazuje zdjęcie profilowe na ekranie blokady"</string>
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"Ustawienia"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"Priorytet"</string>
- <string name="no_shortcut" msgid="7176375126961212514">"Aplikacja <xliff:g id="APP_NAME">%1$s</xliff:g> nie obsługuje ustawień rozmowy"</string>
+ <string name="no_shortcut" msgid="8257177117568230126">"Aplikacja <xliff:g id="APP_NAME">%1$s</xliff:g> nie obsługuje funkcji rozmów"</string>
<string name="bubble_overflow_empty_title" msgid="3120029421991510842">"Brak ostatnich dymków"</string>
<string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"Tutaj będą pojawiać się ostatnie i odrzucone dymki"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"Tych powiadomień nie można zmodyfikować."</string>
@@ -1023,7 +1012,8 @@
<string name="bubble_accessibility_action_move_top_right" msgid="6916868852433483569">"Przenieś w prawy górny róg"</string>
<string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"Przenieś w lewy dolny róg"</string>
<string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"Przenieś w prawy dolny róg"</string>
- <string name="bubble_dismiss_text" msgid="7071770411580452911">"Zamknij"</string>
+ <!-- no translation found for bubble_dismiss_text (1314082410868930066) -->
+ <skip />
<string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"Nie wyświetlaj rozmowy jako dymku"</string>
<string name="bubbles_user_education_title" msgid="5547017089271445797">"Czatuj, korzystając z dymków"</string>
<string name="bubbles_user_education_description" msgid="1160281719576715211">"Nowe rozmowy będą wyświetlane jako pływające ikony lub dymki. Kliknij, by otworzyć dymek. Przeciągnij, by go przenieść."</string>
@@ -1034,16 +1024,19 @@
<string name="notification_content_system_nav_changed" msgid="5077913144844684544">"Nawigacja w systemie została zaktualizowana. Aby wprowadzić zmiany, otwórz Ustawienia."</string>
<string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"Otwórz Ustawienia, by zaktualizować nawigację w systemie"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Tryb gotowości"</string>
+ <string name="priority_onboarding_title" msgid="2893070698479227616">"Rozmowę ustawiono jako priorytetową"</string>
+ <string name="priority_onboarding_behavior" msgid="5342816047020432929">"Rozmowy priorytetowe:"</string>
<string name="priority_onboarding_show_at_top_text" msgid="1678400241025513541">"Wyświetlają się u góry sekcji rozmów"</string>
<string name="priority_onboarding_show_avatar_text" msgid="5756291381124091508">"Pokazują zdjęcie profilowe na ekranie blokady"</string>
<string name="priority_onboarding_appear_as_bubble_text" msgid="4227039772250263122">"Wyświetlane jako pływający dymek nad aplikacjami"</string>
<string name="priority_onboarding_ignores_dnd_text" msgid="2918952762719600529">"Ignorują tryb Nie przeszkadzać"</string>
<string name="priority_onboarding_done_button_title" msgid="4569550984286506007">"OK"</string>
+ <string name="priority_onboarding_settings_button_title" msgid="6663601574303585927">"Ustawienia"</string>
<string name="magnification_overlay_title" msgid="6584179429612427958">"Okno nakładki powiększenia"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"Okno powiększenia"</string>
<string name="magnification_controls_title" msgid="8421106606708891519">"Elementy sterujące okna powiększenia"</string>
<string name="quick_controls_title" msgid="6839108006171302273">"Sterowanie urządzeniami"</string>
- <string name="quick_controls_subtitle" msgid="1667408093326318053">"Dodaj elementy sterujące do połączonych urządzeń"</string>
+ <string name="quick_controls_subtitle" msgid="1667408093326318053">"Dodaj elementy sterujące połączonymi urządzeniami"</string>
<string name="quick_controls_setup_title" msgid="8901436655997849822">"Konfigurowanie sterowania urządzeniami"</string>
<string name="quick_controls_setup_subtitle" msgid="1681506617879773824">"Przytrzymaj przycisk zasilania, aby uzyskać dostęp do elementów sterujących"</string>
<string name="controls_providers_title" msgid="6879775889857085056">"Wybierz aplikację, do której chcesz dodać elementy sterujące"</string>
@@ -1076,15 +1069,19 @@
<string name="controls_pin_wrong" msgid="6162694056042164211">"Nieprawidłowy kod PIN"</string>
<string name="controls_pin_verifying" msgid="3755045989392131746">"Sprawdzam…"</string>
<string name="controls_pin_instructions" msgid="6363309783822475238">"Wpisz kod PIN"</string>
- <string name="controls_pin_instructions_retry" msgid="1566667581012131046">"Spróbuj użyć innego kodu PIN"</string>
+ <string name="controls_pin_instructions_retry" msgid="1566667581012131046">"Wpisz inny kod PIN"</string>
<string name="controls_confirmation_confirming" msgid="2596071302617310665">"Potwierdzam…"</string>
<string name="controls_confirmation_message" msgid="7744104992609594859">"Potwierdź zmianę dotyczącą urządzenia <xliff:g id="DEVICE">%s</xliff:g>"</string>
<string name="controls_structure_tooltip" msgid="4355922222944447867">"Przesuń palcem, by zobaczyć więcej"</string>
<string name="controls_seeding_in_progress" msgid="3033855341410264148">"Wczytuję rekomendacje"</string>
<string name="controls_media_close_session" msgid="9023534788828414585">"Zamknij tę sesję multimediów"</string>
+ <string name="controls_media_resume" msgid="1933520684481586053">"Wznów"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"Nieaktywny, sprawdź aplikację"</string>
<string name="controls_error_retryable" msgid="864025882878378470">"Błąd, próbuję jeszcze raz…"</string>
- <string name="controls_error_removed" msgid="6299213591234723805">"Usunięto urządzenie"</string>
+ <string name="controls_error_removed" msgid="6675638069846014366">"Nie znaleziono"</string>
+ <string name="controls_error_removed_title" msgid="1207794911208047818">"Element jest niedostępny"</string>
+ <string name="controls_error_removed_message" msgid="2885911717034750542">"Nie udało się połączyć z urządzeniem: <xliff:g id="DEVICE">%1$s</xliff:g>. Sprawdź aplikację <xliff:g id="APPLICATION">%2$s</xliff:g>, aby upewnić się, że element sterujący jest wciąż dostępny i ustawienia aplikacji się nie zmieniły."</string>
+ <string name="controls_open_app" msgid="483650971094300141">"Otwórz aplikację"</string>
<string name="controls_error_generic" msgid="352500456918362905">"Nie udało się wczytać stanu"</string>
<string name="controls_error_failed" msgid="960228639198558525">"Błąd, spróbuj ponownie"</string>
<string name="controls_in_progress" msgid="4421080500238215939">"W toku"</string>
diff --git a/packages/SystemUI/res/values-pt-rBR/strings.xml b/packages/SystemUI/res/values-pt-rBR/strings.xml
index ef3770c4be73..2259c305022e 100644
--- a/packages/SystemUI/res/values-pt-rBR/strings.xml
+++ b/packages/SystemUI/res/values-pt-rBR/strings.xml
@@ -77,9 +77,6 @@
<string name="compat_mode_on" msgid="4963711187149440884">"Zoom p/ preencher a tela"</string>
<string name="compat_mode_off" msgid="7682459748279487945">"Ampliar p/ preencher tela"</string>
<string name="global_action_screenshot" msgid="2760267567509131654">"Capturar tela"</string>
- <string name="global_action_lock_message" product="default" msgid="4466026255205186456">"Desbloqueie seu smartphone para ver mais opções"</string>
- <string name="global_action_lock_message" product="tablet" msgid="7621167597240332986">"Desbloqueie seu tablet para ver mais opções"</string>
- <string name="global_action_lock_message" product="device" msgid="538790401275363781">"Desbloqueie seu dispositivo para ver mais opções"</string>
<string name="remote_input_image_insertion_text" msgid="4850791636452521123">"enviou uma imagem"</string>
<string name="screenshot_saving_ticker" msgid="6519186952674544916">"Salvando captura de tela..."</string>
<string name="screenshot_saving_title" msgid="2298349784913287333">"Salvando captura de tela..."</string>
@@ -722,7 +719,7 @@
<string name="notification_channel_summary_priority" msgid="7952654515769021553">"Aparece na parte superior de uma seção de conversa, em forma de balão, mostrando a foto do perfil na tela de bloqueio"</string>
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"Configurações"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"Prioridade"</string>
- <string name="no_shortcut" msgid="7176375126961212514">"<xliff:g id="APP_NAME">%1$s</xliff:g> não é compatível com configurações específicas de conversa"</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 conversão"</string>
<string name="bubble_overflow_empty_title" msgid="3120029421991510842">"Nenhum balão recente"</string>
<string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"Os balões recentes e dispensados aparecerão aqui"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"Não é possível modificar essas notificações."</string>
@@ -1005,7 +1002,8 @@
<string name="bubble_accessibility_action_move_top_right" msgid="6916868852433483569">"Mover para canto superior direito"</string>
<string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"Mover para canto inferior esquerdo"</string>
<string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"Mover para canto inferior direito"</string>
- <string name="bubble_dismiss_text" msgid="7071770411580452911">"Dispensar"</string>
+ <!-- no translation found for bubble_dismiss_text (1314082410868930066) -->
+ <skip />
<string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"Não criar balões de conversa"</string>
<string name="bubbles_user_education_title" msgid="5547017089271445797">"Converse usando balões"</string>
<string name="bubbles_user_education_description" msgid="1160281719576715211">"Novas conversas aparecerão como ícones flutuantes, ou balões. Toque para abrir o balão. Arraste para movê-lo."</string>
@@ -1016,16 +1014,19 @@
<string name="notification_content_system_nav_changed" msgid="5077913144844684544">"Navegação no sistema atualizada. Se quiser alterá-la, acesse as configurações."</string>
<string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"Acesse as configurações para atualizar a navegação no sistema"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Em espera"</string>
+ <string name="priority_onboarding_title" msgid="2893070698479227616">"A conversa foi definida como prioritária"</string>
+ <string name="priority_onboarding_behavior" msgid="5342816047020432929">"As conversas prioritárias:"</string>
<string name="priority_onboarding_show_at_top_text" msgid="1678400241025513541">"Aparecer na parte superior da seção de conversa"</string>
<string name="priority_onboarding_show_avatar_text" msgid="5756291381124091508">"Mostrar foto do perfil na tela de bloqueio"</string>
<string name="priority_onboarding_appear_as_bubble_text" msgid="4227039772250263122">"Aparecer como balões flutuantes sobre outros apps"</string>
<string name="priority_onboarding_ignores_dnd_text" msgid="2918952762719600529">"Interromper o \"Não perturbe\""</string>
<string name="priority_onboarding_done_button_title" msgid="4569550984286506007">"Ok"</string>
+ <string name="priority_onboarding_settings_button_title" msgid="6663601574303585927">"Configurações"</string>
<string name="magnification_overlay_title" msgid="6584179429612427958">"Janela de sobreposição de ampliação"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"Janela de ampliação"</string>
<string name="magnification_controls_title" msgid="8421106606708891519">"Controles da janela de ampliação"</string>
<string name="quick_controls_title" msgid="6839108006171302273">"Controles do dispositivo"</string>
- <string name="quick_controls_subtitle" msgid="1667408093326318053">"Adiciona controles para os dispositivos conectados"</string>
+ <string name="quick_controls_subtitle" msgid="1667408093326318053">"Adiciona controles aos dispositivos conectados"</string>
<string name="quick_controls_setup_title" msgid="8901436655997849822">"Configurar controles do dispositivo"</string>
<string name="quick_controls_setup_subtitle" msgid="1681506617879773824">"Toque no botão liga/desliga e mantenha-o pressionado para acessar seus controles"</string>
<string name="controls_providers_title" msgid="6879775889857085056">"Escolha um app para adicionar controles"</string>
@@ -1042,7 +1043,7 @@
<string name="accessibility_control_move" msgid="8980344493796647792">"Mover para a posição <xliff:g id="NUMBER">%d</xliff:g>"</string>
<string name="controls_favorite_default_title" msgid="967742178688938137">"Controles"</string>
<string name="controls_favorite_subtitle" msgid="6604402232298443956">"Escolha os controles para acessar pelo menu do botão liga/desliga"</string>
- <string name="controls_favorite_rearrange" msgid="5616952398043063519">"Mantenha a tela pressionada e arraste para reorganizar os controles"</string>
+ <string name="controls_favorite_rearrange" msgid="5616952398043063519">"Toque no controle, mantenha-o pressionado e arraste para reorganizar as posições."</string>
<string name="controls_favorite_removed" msgid="5276978408529217272">"Todos os controles foram removidos"</string>
<string name="controls_favorite_toast_no_changes" msgid="7094494210840877931">"As mudanças não foram salvas"</string>
<string name="controls_favorite_load_error" msgid="2533215155804455348">"Não foi possível carregar a lista de controles."</string>
@@ -1062,9 +1063,13 @@
<string name="controls_structure_tooltip" msgid="4355922222944447867">"Deslize para ver mais"</string>
<string name="controls_seeding_in_progress" msgid="3033855341410264148">"Carregando recomendações"</string>
<string name="controls_media_close_session" msgid="9023534788828414585">"Encerrar esta sessão de mídia"</string>
+ <string name="controls_media_resume" msgid="1933520684481586053">"Retomar"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"Inativo, verifique o app"</string>
<string name="controls_error_retryable" msgid="864025882878378470">"Erro. Tentando novamente…"</string>
- <string name="controls_error_removed" msgid="6299213591234723805">"Dispositivo removido"</string>
+ <string name="controls_error_removed" msgid="6675638069846014366">"Não encontrado"</string>
+ <string name="controls_error_removed_title" msgid="1207794911208047818">"O controle está indisponível"</string>
+ <string name="controls_error_removed_message" msgid="2885911717034750542">"Não foi possível acessar <xliff:g id="DEVICE">%1$s</xliff:g>. Verifique o app <xliff:g id="APPLICATION">%2$s</xliff:g> para garantir que o controle ainda esteja disponível e as configurações não tenham sido modificadas."</string>
+ <string name="controls_open_app" msgid="483650971094300141">"Abrir app"</string>
<string name="controls_error_generic" msgid="352500456918362905">"Falha ao carregar o status"</string>
<string name="controls_error_failed" msgid="960228639198558525">"Erro. Tente novamente"</string>
<string name="controls_in_progress" msgid="4421080500238215939">"Em andamento"</string>
diff --git a/packages/SystemUI/res/values-pt-rPT/strings.xml b/packages/SystemUI/res/values-pt-rPT/strings.xml
index e343c2f0bfcc..d90b8b2eeb13 100644
--- a/packages/SystemUI/res/values-pt-rPT/strings.xml
+++ b/packages/SystemUI/res/values-pt-rPT/strings.xml
@@ -77,9 +77,6 @@
<string name="compat_mode_on" msgid="4963711187149440884">"Zoom para preencher o ecrã"</string>
<string name="compat_mode_off" msgid="7682459748279487945">"Esticar p. caber em ec. int."</string>
<string name="global_action_screenshot" msgid="2760267567509131654">"Captura de ecrã"</string>
- <string name="global_action_lock_message" product="default" msgid="4466026255205186456">"Desbloqueie o telemóvel para obter mais opções."</string>
- <string name="global_action_lock_message" product="tablet" msgid="7621167597240332986">"Desbloqueie o tablet para obter mais opções."</string>
- <string name="global_action_lock_message" product="device" msgid="538790401275363781">"Desbloqueie o dispositivo para obter mais opções."</string>
<string name="remote_input_image_insertion_text" msgid="4850791636452521123">"enviou uma imagem"</string>
<string name="screenshot_saving_ticker" msgid="6519186952674544916">"A guardar captura de ecrã..."</string>
<string name="screenshot_saving_title" msgid="2298349784913287333">"A guardar captura de ecrã..."</string>
@@ -722,7 +719,7 @@
<string name="notification_channel_summary_priority" msgid="7952654515769021553">"Aparece na parte superior da secção de conversas, surge como um balão flutuante e apresenta a imagem do perfil no ecrã de bloqueio."</string>
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"Definições"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"Prioridade"</string>
- <string name="no_shortcut" msgid="7176375126961212514">"A app <xliff:g id="APP_NAME">%1$s</xliff:g> não suporta definições específicas de conversas."</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>
<string name="bubble_overflow_empty_title" msgid="3120029421991510842">"Nenhum balão recente"</string>
<string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"Os balões recentes e ignorados vão aparecer aqui."</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"Não é possível modificar estas notificações."</string>
@@ -1005,7 +1002,8 @@
<string name="bubble_accessibility_action_move_top_right" msgid="6916868852433483569">"Mover parte superior direita"</string>
<string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"Mover p/ parte infer. esquerda"</string>
<string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"Mover parte inferior direita"</string>
- <string name="bubble_dismiss_text" msgid="7071770411580452911">"Ignorar"</string>
+ <!-- no translation found for bubble_dismiss_text (1314082410868930066) -->
+ <skip />
<string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"Não apresentar a conversa em balões"</string>
<string name="bubbles_user_education_title" msgid="5547017089271445797">"Converse no chat através de balões"</string>
<string name="bubbles_user_education_description" msgid="1160281719576715211">"As novas conversas aparecem como ícones flutuantes ou balões. Toque para abrir o balão. Arraste para o mover."</string>
@@ -1016,11 +1014,14 @@
<string name="notification_content_system_nav_changed" msgid="5077913144844684544">"A navegação no sistema foi atualizada. Para efetuar alterações, aceda às Definições."</string>
<string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"Aceda às Definições para atualizar a navegação no sistema."</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Modo de espera"</string>
+ <string name="priority_onboarding_title" msgid="2893070698479227616">"Conversa definida como prioritária"</string>
+ <string name="priority_onboarding_behavior" msgid="5342816047020432929">"As conversas com prioridade irão:"</string>
<string name="priority_onboarding_show_at_top_text" msgid="1678400241025513541">"Aparecem na parte superior da secção de conversas."</string>
<string name="priority_onboarding_show_avatar_text" msgid="5756291381124091508">"Mostram a imagem do perfil no ecrã de bloqueio."</string>
<string name="priority_onboarding_appear_as_bubble_text" msgid="4227039772250263122">"Aparecem como balões flutuantes por cima de apps."</string>
<string name="priority_onboarding_ignores_dnd_text" msgid="2918952762719600529">"Interrompem o modo Não incomodar."</string>
<string name="priority_onboarding_done_button_title" msgid="4569550984286506007">"OK"</string>
+ <string name="priority_onboarding_settings_button_title" msgid="6663601574303585927">"Definições"</string>
<string name="magnification_overlay_title" msgid="6584179429612427958">"Janela de sobreposição da ampliação"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"Janela de ampliação"</string>
<string name="magnification_controls_title" msgid="8421106606708891519">"Controlos da janela de ampliação"</string>
@@ -1062,9 +1063,13 @@
<string name="controls_structure_tooltip" msgid="4355922222944447867">"Deslize rapidamente para ver mais."</string>
<string name="controls_seeding_in_progress" msgid="3033855341410264148">"A carregar recomendações…"</string>
<string name="controls_media_close_session" msgid="9023534788828414585">"Fechar esta sessão multimédia"</string>
+ <string name="controls_media_resume" msgid="1933520684481586053">"Retomar"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"Inativa. Consulte a app."</string>
<string name="controls_error_retryable" msgid="864025882878378470">"Erro. A tentar novamente…"</string>
- <string name="controls_error_removed" msgid="6299213591234723805">"Dispositivo removido."</string>
+ <string name="controls_error_removed" msgid="6675638069846014366">"Não encontrado."</string>
+ <string name="controls_error_removed_title" msgid="1207794911208047818">"O controlo está indisponível"</string>
+ <string name="controls_error_removed_message" msgid="2885911717034750542">"Não foi possível aceder a <xliff:g id="DEVICE">%1$s</xliff:g>. Verifique a app <xliff:g id="APPLICATION">%2$s</xliff:g> para se certificar de que o controlo ainda está disponível e que as definições da mesma não foram alteradas."</string>
+ <string name="controls_open_app" msgid="483650971094300141">"Abrir app"</string>
<string name="controls_error_generic" msgid="352500456918362905">"Impossível carregar o estado."</string>
<string name="controls_error_failed" msgid="960228639198558525">"Erro. Tente novamente."</string>
<string name="controls_in_progress" msgid="4421080500238215939">"Em curso"</string>
diff --git a/packages/SystemUI/res/values-pt/strings.xml b/packages/SystemUI/res/values-pt/strings.xml
index ef3770c4be73..2259c305022e 100644
--- a/packages/SystemUI/res/values-pt/strings.xml
+++ b/packages/SystemUI/res/values-pt/strings.xml
@@ -77,9 +77,6 @@
<string name="compat_mode_on" msgid="4963711187149440884">"Zoom p/ preencher a tela"</string>
<string name="compat_mode_off" msgid="7682459748279487945">"Ampliar p/ preencher tela"</string>
<string name="global_action_screenshot" msgid="2760267567509131654">"Capturar tela"</string>
- <string name="global_action_lock_message" product="default" msgid="4466026255205186456">"Desbloqueie seu smartphone para ver mais opções"</string>
- <string name="global_action_lock_message" product="tablet" msgid="7621167597240332986">"Desbloqueie seu tablet para ver mais opções"</string>
- <string name="global_action_lock_message" product="device" msgid="538790401275363781">"Desbloqueie seu dispositivo para ver mais opções"</string>
<string name="remote_input_image_insertion_text" msgid="4850791636452521123">"enviou uma imagem"</string>
<string name="screenshot_saving_ticker" msgid="6519186952674544916">"Salvando captura de tela..."</string>
<string name="screenshot_saving_title" msgid="2298349784913287333">"Salvando captura de tela..."</string>
@@ -722,7 +719,7 @@
<string name="notification_channel_summary_priority" msgid="7952654515769021553">"Aparece na parte superior de uma seção de conversa, em forma de balão, mostrando a foto do perfil na tela de bloqueio"</string>
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"Configurações"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"Prioridade"</string>
- <string name="no_shortcut" msgid="7176375126961212514">"<xliff:g id="APP_NAME">%1$s</xliff:g> não é compatível com configurações específicas de conversa"</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 conversão"</string>
<string name="bubble_overflow_empty_title" msgid="3120029421991510842">"Nenhum balão recente"</string>
<string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"Os balões recentes e dispensados aparecerão aqui"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"Não é possível modificar essas notificações."</string>
@@ -1005,7 +1002,8 @@
<string name="bubble_accessibility_action_move_top_right" msgid="6916868852433483569">"Mover para canto superior direito"</string>
<string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"Mover para canto inferior esquerdo"</string>
<string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"Mover para canto inferior direito"</string>
- <string name="bubble_dismiss_text" msgid="7071770411580452911">"Dispensar"</string>
+ <!-- no translation found for bubble_dismiss_text (1314082410868930066) -->
+ <skip />
<string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"Não criar balões de conversa"</string>
<string name="bubbles_user_education_title" msgid="5547017089271445797">"Converse usando balões"</string>
<string name="bubbles_user_education_description" msgid="1160281719576715211">"Novas conversas aparecerão como ícones flutuantes, ou balões. Toque para abrir o balão. Arraste para movê-lo."</string>
@@ -1016,16 +1014,19 @@
<string name="notification_content_system_nav_changed" msgid="5077913144844684544">"Navegação no sistema atualizada. Se quiser alterá-la, acesse as configurações."</string>
<string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"Acesse as configurações para atualizar a navegação no sistema"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Em espera"</string>
+ <string name="priority_onboarding_title" msgid="2893070698479227616">"A conversa foi definida como prioritária"</string>
+ <string name="priority_onboarding_behavior" msgid="5342816047020432929">"As conversas prioritárias:"</string>
<string name="priority_onboarding_show_at_top_text" msgid="1678400241025513541">"Aparecer na parte superior da seção de conversa"</string>
<string name="priority_onboarding_show_avatar_text" msgid="5756291381124091508">"Mostrar foto do perfil na tela de bloqueio"</string>
<string name="priority_onboarding_appear_as_bubble_text" msgid="4227039772250263122">"Aparecer como balões flutuantes sobre outros apps"</string>
<string name="priority_onboarding_ignores_dnd_text" msgid="2918952762719600529">"Interromper o \"Não perturbe\""</string>
<string name="priority_onboarding_done_button_title" msgid="4569550984286506007">"Ok"</string>
+ <string name="priority_onboarding_settings_button_title" msgid="6663601574303585927">"Configurações"</string>
<string name="magnification_overlay_title" msgid="6584179429612427958">"Janela de sobreposição de ampliação"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"Janela de ampliação"</string>
<string name="magnification_controls_title" msgid="8421106606708891519">"Controles da janela de ampliação"</string>
<string name="quick_controls_title" msgid="6839108006171302273">"Controles do dispositivo"</string>
- <string name="quick_controls_subtitle" msgid="1667408093326318053">"Adiciona controles para os dispositivos conectados"</string>
+ <string name="quick_controls_subtitle" msgid="1667408093326318053">"Adiciona controles aos dispositivos conectados"</string>
<string name="quick_controls_setup_title" msgid="8901436655997849822">"Configurar controles do dispositivo"</string>
<string name="quick_controls_setup_subtitle" msgid="1681506617879773824">"Toque no botão liga/desliga e mantenha-o pressionado para acessar seus controles"</string>
<string name="controls_providers_title" msgid="6879775889857085056">"Escolha um app para adicionar controles"</string>
@@ -1042,7 +1043,7 @@
<string name="accessibility_control_move" msgid="8980344493796647792">"Mover para a posição <xliff:g id="NUMBER">%d</xliff:g>"</string>
<string name="controls_favorite_default_title" msgid="967742178688938137">"Controles"</string>
<string name="controls_favorite_subtitle" msgid="6604402232298443956">"Escolha os controles para acessar pelo menu do botão liga/desliga"</string>
- <string name="controls_favorite_rearrange" msgid="5616952398043063519">"Mantenha a tela pressionada e arraste para reorganizar os controles"</string>
+ <string name="controls_favorite_rearrange" msgid="5616952398043063519">"Toque no controle, mantenha-o pressionado e arraste para reorganizar as posições."</string>
<string name="controls_favorite_removed" msgid="5276978408529217272">"Todos os controles foram removidos"</string>
<string name="controls_favorite_toast_no_changes" msgid="7094494210840877931">"As mudanças não foram salvas"</string>
<string name="controls_favorite_load_error" msgid="2533215155804455348">"Não foi possível carregar a lista de controles."</string>
@@ -1062,9 +1063,13 @@
<string name="controls_structure_tooltip" msgid="4355922222944447867">"Deslize para ver mais"</string>
<string name="controls_seeding_in_progress" msgid="3033855341410264148">"Carregando recomendações"</string>
<string name="controls_media_close_session" msgid="9023534788828414585">"Encerrar esta sessão de mídia"</string>
+ <string name="controls_media_resume" msgid="1933520684481586053">"Retomar"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"Inativo, verifique o app"</string>
<string name="controls_error_retryable" msgid="864025882878378470">"Erro. Tentando novamente…"</string>
- <string name="controls_error_removed" msgid="6299213591234723805">"Dispositivo removido"</string>
+ <string name="controls_error_removed" msgid="6675638069846014366">"Não encontrado"</string>
+ <string name="controls_error_removed_title" msgid="1207794911208047818">"O controle está indisponível"</string>
+ <string name="controls_error_removed_message" msgid="2885911717034750542">"Não foi possível acessar <xliff:g id="DEVICE">%1$s</xliff:g>. Verifique o app <xliff:g id="APPLICATION">%2$s</xliff:g> para garantir que o controle ainda esteja disponível e as configurações não tenham sido modificadas."</string>
+ <string name="controls_open_app" msgid="483650971094300141">"Abrir app"</string>
<string name="controls_error_generic" msgid="352500456918362905">"Falha ao carregar o status"</string>
<string name="controls_error_failed" msgid="960228639198558525">"Erro. Tente novamente"</string>
<string name="controls_in_progress" msgid="4421080500238215939">"Em andamento"</string>
diff --git a/packages/SystemUI/res/values-ro/strings.xml b/packages/SystemUI/res/values-ro/strings.xml
index ef37cfe52002..c90c04c666b1 100644
--- a/packages/SystemUI/res/values-ro/strings.xml
+++ b/packages/SystemUI/res/values-ro/strings.xml
@@ -77,9 +77,6 @@
<string name="compat_mode_on" msgid="4963711187149440884">"Zoom pt. a umple ecranul"</string>
<string name="compat_mode_off" msgid="7682459748279487945">"Înt. pt. a umple ecranul"</string>
<string name="global_action_screenshot" msgid="2760267567509131654">"Captură de ecran"</string>
- <string name="global_action_lock_message" product="default" msgid="4466026255205186456">"Deblocați telefonul pentru mai multe opțiuni"</string>
- <string name="global_action_lock_message" product="tablet" msgid="7621167597240332986">"Deblocați tableta pentru mai multe opțiuni"</string>
- <string name="global_action_lock_message" product="device" msgid="538790401275363781">"Deblocați dispozitivul pentru mai multe opțiuni"</string>
<string name="remote_input_image_insertion_text" msgid="4850791636452521123">"a trimis o imagine"</string>
<string name="screenshot_saving_ticker" msgid="6519186952674544916">"Se salv. captura de ecran..."</string>
<string name="screenshot_saving_title" msgid="2298349784913287333">"Se salvează captura de ecran..."</string>
@@ -598,29 +595,21 @@
<string name="volume_odi_captions_hint_enable" msgid="2073091194012843195">"activați"</string>
<string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"dezactivați"</string>
<string name="accessibility_output_chooser" msgid="7807898688967194183">"Comutați dispozitivul de ieșire"</string>
- <!-- no translation found for screen_pinning_title (9058007390337841305) -->
- <skip />
+ <string name="screen_pinning_title" msgid="9058007390337841305">"Aplicația este fixată"</string>
<string name="screen_pinning_description" msgid="8699395373875667743">"Astfel rămâne afișat până anulați fixarea. Atingeți lung opțiunile Înapoi și Recente pentru a anula fixarea."</string>
<string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"Astfel rămâne afișat până anulați fixarea. Atingeți lung opțiunile Înapoi și Acasă pentru a anula fixarea."</string>
<string name="screen_pinning_description_gestural" msgid="7246323931831232068">"Astfel rămâne afișat până anulați fixarea. Glisați în sus și țineți apăsat pentru a anula fixarea."</string>
<string name="screen_pinning_description_accessible" msgid="7386449191953535332">"Astfel rămâne afișat până anulați fixarea. Atingeți lung opțiunea Recente pentru a anula fixarea."</string>
<string name="screen_pinning_description_recents_invisible_accessible" msgid="2857071808674481986">"Astfel rămâne afișat până anulați fixarea. Atingeți lung opțiunea Acasă pentru a anula fixarea."</string>
- <!-- no translation found for screen_pinning_exposes_personal_data (8189852022981524789) -->
- <skip />
- <!-- no translation found for screen_pinning_can_open_other_apps (7529756813231421455) -->
- <skip />
- <!-- no translation found for screen_pinning_toast (8177286912533744328) -->
- <skip />
- <!-- no translation found for screen_pinning_toast_recents_invisible (6850978077443052594) -->
- <skip />
- <!-- no translation found for screen_pinning_toast_gesture_nav (170699893395336705) -->
- <skip />
+ <string name="screen_pinning_exposes_personal_data" msgid="8189852022981524789">"Pot fi accesate date cu caracter personal (cum ar fi agenda și conținutul e-mailurilor)."</string>
+ <string name="screen_pinning_can_open_other_apps" msgid="7529756813231421455">"Aplicațiile fixate pot deschide alte aplicații."</string>
+ <string name="screen_pinning_toast" msgid="8177286912533744328">"Pentru a anula fixarea acestei aplicații, atingeți lung butoanele Înapoi și Recente"</string>
+ <string name="screen_pinning_toast_recents_invisible" msgid="6850978077443052594">"Pentru a anula fixarea acestei aplicații, atingeți lung butoanele Înapoi și Acasă"</string>
+ <string name="screen_pinning_toast_gesture_nav" msgid="170699893395336705">"Pentru a anula fixarea acestei aplicații, glisați în sus și mențineți"</string>
<string name="screen_pinning_positive" msgid="3285785989665266984">"Am înțeles"</string>
<string name="screen_pinning_negative" msgid="6882816864569211666">"Nu, mulțumesc"</string>
- <!-- no translation found for screen_pinning_start (7483998671383371313) -->
- <skip />
- <!-- no translation found for screen_pinning_exit (4553787518387346893) -->
- <skip />
+ <string name="screen_pinning_start" msgid="7483998671383371313">"Aplicație fixată"</string>
+ <string name="screen_pinning_exit" msgid="4553787518387346893">"Aplicație nefixată"</string>
<string name="quick_settings_reset_confirmation_title" msgid="463533331480997595">"Ascundeți <xliff:g id="TILE_LABEL">%1$s</xliff:g>?"</string>
<string name="quick_settings_reset_confirmation_message" msgid="2320586180785674186">"Va reapărea la următoarea activare în setări."</string>
<string name="quick_settings_reset_confirmation_button" msgid="3341477479055016776">"Ascundeți"</string>
@@ -733,7 +722,7 @@
<string name="notification_channel_summary_priority" msgid="7952654515769021553">"Se afișează în partea de sus a secțiunii de conversație, apare ca un balon flotant, afișează fotografia de profil pe ecranul de blocare"</string>
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"Setări"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"Prioritate"</string>
- <string name="no_shortcut" msgid="7176375126961212514">"<xliff:g id="APP_NAME">%1$s</xliff:g> nu acceptă setările pentru conversații"</string>
+ <string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> nu acceptă funcții pentru conversații"</string>
<string name="bubble_overflow_empty_title" msgid="3120029421991510842">"Nu există baloane recente"</string>
<string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"Baloanele recente și baloanele respinse vor apărea aici"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"Aceste notificări nu pot fi modificate."</string>
@@ -1018,7 +1007,8 @@
<string name="bubble_accessibility_action_move_top_right" msgid="6916868852433483569">"Mutați în dreapta sus"</string>
<string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"Mutați în stânga jos"</string>
<string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"Mutați în dreapta jos"</string>
- <string name="bubble_dismiss_text" msgid="7071770411580452911">"Închideți"</string>
+ <!-- no translation found for bubble_dismiss_text (1314082410868930066) -->
+ <skip />
<string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"Nu afișați conversația în balon"</string>
<string name="bubbles_user_education_title" msgid="5547017089271445797">"Discutați pe chat folosind baloanele"</string>
<string name="bubbles_user_education_description" msgid="1160281719576715211">"Conversațiile noi apar ca pictograme flotante sau baloane. Atingeți pentru a deschide balonul. Trageți pentru a-l muta."</string>
@@ -1029,11 +1019,14 @@
<string name="notification_content_system_nav_changed" msgid="5077913144844684544">"Navigarea în sistem a fost actualizată. Pentru a face modificări, accesați Setările."</string>
<string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"Accesați Setările pentru a actualiza navigarea în sistem"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Standby"</string>
+ <string name="priority_onboarding_title" msgid="2893070698479227616">"Conversația a fost setată ca prioritară"</string>
+ <string name="priority_onboarding_behavior" msgid="5342816047020432929">"Conversațiile cu prioritate vor:"</string>
<string name="priority_onboarding_show_at_top_text" msgid="1678400241025513541">"Apar în partea de sus a secțiunii de conversație"</string>
<string name="priority_onboarding_show_avatar_text" msgid="5756291381124091508">"Afișează fotografia de profil pe ecranul de blocare"</string>
<string name="priority_onboarding_appear_as_bubble_text" msgid="4227039772250263122">"Apar ca un balon flotant deasupra aplicațiilor"</string>
<string name="priority_onboarding_ignores_dnd_text" msgid="2918952762719600529">"Întrerup modul Nu deranja"</string>
<string name="priority_onboarding_done_button_title" msgid="4569550984286506007">"OK"</string>
+ <string name="priority_onboarding_settings_button_title" msgid="6663601574303585927">"Setări"</string>
<string name="magnification_overlay_title" msgid="6584179429612427958">"Fereastra de suprapunere pentru mărire"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"Fereastra de mărire"</string>
<string name="magnification_controls_title" msgid="8421106606708891519">"Comenzi pentru fereastra de mărire"</string>
@@ -1076,9 +1069,13 @@
<string name="controls_structure_tooltip" msgid="4355922222944447867">"Glisați pentru a vedea mai multe"</string>
<string name="controls_seeding_in_progress" msgid="3033855341410264148">"Se încarcă recomandările"</string>
<string name="controls_media_close_session" msgid="9023534788828414585">"Închideți această sesiune media"</string>
+ <string name="controls_media_resume" msgid="1933520684481586053">"Reia"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"Inactiv, verificați aplicația"</string>
<string name="controls_error_retryable" msgid="864025882878378470">"Eroare, se încearcă din nou…"</string>
- <string name="controls_error_removed" msgid="6299213591234723805">"Dispozitivul a fost eliminat"</string>
+ <string name="controls_error_removed" msgid="6675638069846014366">"Nu s-a găsit"</string>
+ <string name="controls_error_removed_title" msgid="1207794911208047818">"Comanda este indisponibilă"</string>
+ <string name="controls_error_removed_message" msgid="2885911717034750542">"Nu s-a putut accesa <xliff:g id="DEVICE">%1$s</xliff:g>. Accesați aplicația <xliff:g id="APPLICATION">%2$s</xliff:g> pentru a vă asigura de disponibilitatea comenzii și că setările aplicației nu s-au schimbat."</string>
+ <string name="controls_open_app" msgid="483650971094300141">"Deschideți aplicația"</string>
<string name="controls_error_generic" msgid="352500456918362905">"Starea nu se poate încărca"</string>
<string name="controls_error_failed" msgid="960228639198558525">"Eroare, încercați din nou"</string>
<string name="controls_in_progress" msgid="4421080500238215939">"În curs"</string>
diff --git a/packages/SystemUI/res/values-ru/strings.xml b/packages/SystemUI/res/values-ru/strings.xml
index 6adc37939b8a..35f4b745830a 100644
--- a/packages/SystemUI/res/values-ru/strings.xml
+++ b/packages/SystemUI/res/values-ru/strings.xml
@@ -77,9 +77,6 @@
<string name="compat_mode_on" msgid="4963711187149440884">"Подогнать по размерам экрана"</string>
<string name="compat_mode_off" msgid="7682459748279487945">"Растянуть на весь экран"</string>
<string name="global_action_screenshot" msgid="2760267567509131654">"Скриншот"</string>
- <string name="global_action_lock_message" product="default" msgid="4466026255205186456">"Чтобы посмотреть дополнительные параметры, разблокируйте телефон."</string>
- <string name="global_action_lock_message" product="tablet" msgid="7621167597240332986">"Чтобы посмотреть дополнительные параметры, разблокируйте планшет."</string>
- <string name="global_action_lock_message" product="device" msgid="538790401275363781">"Чтобы посмотреть дополнительные параметры, разблокируйте устройство."</string>
<string name="remote_input_image_insertion_text" msgid="4850791636452521123">"отправлено изображение"</string>
<string name="screenshot_saving_ticker" msgid="6519186952674544916">"Сохранение..."</string>
<string name="screenshot_saving_title" msgid="2298349784913287333">"Сохранение..."</string>
@@ -728,7 +725,7 @@
<string name="notification_channel_summary_priority" msgid="7952654515769021553">"Появляется в верхней части списка разговоров и как всплывающий чат, а также показывает фото профиля на заблокированном экране"</string>
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"Настройки"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"Приоритет"</string>
- <string name="no_shortcut" msgid="7176375126961212514">"Приложение \"<xliff:g id="APP_NAME">%1$s</xliff:g>\" не поддерживает настройки разговора."</string>
+ <string name="no_shortcut" msgid="8257177117568230126">"Приложение \"<xliff:g id="APP_NAME">%1$s</xliff:g>\" не поддерживает функции разговоров."</string>
<string name="bubble_overflow_empty_title" msgid="3120029421991510842">"Нет недавних всплывающих чатов"</string>
<string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"Здесь будут появляться недавние и закрытые всплывающие чаты."</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"Эти уведомления нельзя изменить."</string>
@@ -1015,7 +1012,8 @@
<string name="bubble_accessibility_action_move_top_right" msgid="6916868852433483569">"Перенести в правый верхний угол"</string>
<string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"Перенести в левый нижний угол"</string>
<string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"Перенести в правый нижний угол"</string>
- <string name="bubble_dismiss_text" msgid="7071770411580452911">"Закрыть"</string>
+ <!-- no translation found for bubble_dismiss_text (1314082410868930066) -->
+ <skip />
<string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"Не показывать всплывающие чаты для разговоров"</string>
<string name="bubbles_user_education_title" msgid="5547017089271445797">"Всплывающие чаты для разговоров"</string>
<string name="bubbles_user_education_description" msgid="1160281719576715211">"Новые разговоры будут появляться в виде плавающих значков, или всплывающих чатов. Чтобы открыть чат, нажмите на него, а чтобы переместить – перетащите."</string>
@@ -1026,11 +1024,14 @@
<string name="notification_content_system_nav_changed" msgid="5077913144844684544">"Параметры навигации в системе обновлены. Чтобы изменить их, перейдите в настройки."</string>
<string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"Чтобы обновить параметры навигации в системе, перейдите в настройки."</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Переход в режим ожидания"</string>
+ <string name="priority_onboarding_title" msgid="2893070698479227616">"Разговор помечен как важный"</string>
+ <string name="priority_onboarding_behavior" msgid="5342816047020432929">"Важные разговоры:"</string>
<string name="priority_onboarding_show_at_top_text" msgid="1678400241025513541">"Показывать в верхней части списка разговоров"</string>
<string name="priority_onboarding_show_avatar_text" msgid="5756291381124091508">"Показывать фото профиля на заблокированном экране"</string>
<string name="priority_onboarding_appear_as_bubble_text" msgid="4227039772250263122">"Показывать как всплывающий чат над приложениями"</string>
<string name="priority_onboarding_ignores_dnd_text" msgid="2918952762719600529">"Показывать в режиме \"Не беспокоить\""</string>
<string name="priority_onboarding_done_button_title" msgid="4569550984286506007">"ОК"</string>
+ <string name="priority_onboarding_settings_button_title" msgid="6663601574303585927">"Настройки"</string>
<string name="magnification_overlay_title" msgid="6584179429612427958">"Наложение окна увеличения"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"Окно увеличения"</string>
<string name="magnification_controls_title" msgid="8421106606708891519">"Настройки окна увеличения"</string>
@@ -1074,13 +1075,17 @@
<string name="controls_structure_tooltip" msgid="4355922222944447867">"Проведите по экрану, чтобы увидеть больше"</string>
<string name="controls_seeding_in_progress" msgid="3033855341410264148">"Загрузка рекомендаций…"</string>
<string name="controls_media_close_session" msgid="9023534788828414585">"Закрыть этот мультимедийный сеанс"</string>
+ <string name="controls_media_resume" msgid="1933520684481586053">"Возобновить"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"Нет ответа. Проверьте приложение."</string>
<string name="controls_error_retryable" msgid="864025882878378470">"Ошибка. Повторная попытка…"</string>
- <string name="controls_error_removed" msgid="6299213591234723805">"Устройство удалено."</string>
+ <string name="controls_error_removed" msgid="6675638069846014366">"Не найдено."</string>
+ <string name="controls_error_removed_title" msgid="1207794911208047818">"Управление недоступно"</string>
+ <string name="controls_error_removed_message" msgid="2885911717034750542">"Нет доступа к устройству (<xliff:g id="DEVICE">%1$s</xliff:g>). Проверьте, доступно ли управление в приложении \"<xliff:g id="APPLICATION">%2$s</xliff:g>\" и не изменились ли настройки этого приложения."</string>
+ <string name="controls_open_app" msgid="483650971094300141">"Открыть приложение"</string>
<string name="controls_error_generic" msgid="352500456918362905">"Не удалось загрузить статус."</string>
<string name="controls_error_failed" msgid="960228639198558525">"Ошибка. Повторите попытку."</string>
<string name="controls_in_progress" msgid="4421080500238215939">"Выполняется"</string>
<string name="controls_added_tooltip" msgid="4842812921719153085">"Удерживайте кнопку питания, чтобы увидеть новые элементы управления"</string>
- <string name="controls_menu_add" msgid="4447246119229920050">"Добавить элементы управления"</string>
- <string name="controls_menu_edit" msgid="890623986951347062">"Изменить элементы управления"</string>
+ <string name="controls_menu_add" msgid="4447246119229920050">"Добавить эл-ты управления"</string>
+ <string name="controls_menu_edit" msgid="890623986951347062">"Изменить эл-ты управления"</string>
</resources>
diff --git a/packages/SystemUI/res/values-si/strings.xml b/packages/SystemUI/res/values-si/strings.xml
index 2ace6ed664eb..be88cbafe59b 100644
--- a/packages/SystemUI/res/values-si/strings.xml
+++ b/packages/SystemUI/res/values-si/strings.xml
@@ -77,9 +77,6 @@
<string name="compat_mode_on" msgid="4963711187149440884">"තිරය පිරවීමට විශාලනය කරන්න"</string>
<string name="compat_mode_off" msgid="7682459748279487945">"තිරය පිරවීමට අදින්න"</string>
<string name="global_action_screenshot" msgid="2760267567509131654">"තිර රුව"</string>
- <string name="global_action_lock_message" product="default" msgid="4466026255205186456">"තව විකල්ප සඳහා ඔබේ දුරකථනය අගුලු හරින්න"</string>
- <string name="global_action_lock_message" product="tablet" msgid="7621167597240332986">"තව විකල්ප සඳහා ඔබේ ටැබ්ලට් පරිගණකය අගුලු හරින්න"</string>
- <string name="global_action_lock_message" product="device" msgid="538790401275363781">"තව විකල්ප සඳහා ඔබේ උපාංගය අගුලු හරින්න"</string>
<string name="remote_input_image_insertion_text" msgid="4850791636452521123">"රූපයක් එවන ලදී"</string>
<string name="screenshot_saving_ticker" msgid="6519186952674544916">"තිර රුව සුරකිමින්…"</string>
<string name="screenshot_saving_title" msgid="2298349784913287333">"තිර රුව සුරැකෙමින් පවතී…"</string>
@@ -722,7 +719,7 @@
<string name="notification_channel_summary_priority" msgid="7952654515769021553">"සංවාද කොටසේ ඉහළම පෙන්වයි, බුබුළක් ලෙස දිස් වේ, අගුලු තිරයේ පැතිකඩ පින්තූරය සංදර්ශනය වේ"</string>
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"සැකසීම්"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"ප්‍රමුඛතාව"</string>
- <string name="no_shortcut" msgid="7176375126961212514">"<xliff:g id="APP_NAME">%1$s</xliff:g> සංවාදය නිශ්චිත සැකසීම්වලට සහාය නොදක්වයි"</string>
+ <string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> සංවාද විශේෂාංගවලට සහාය නොදක්වයි"</string>
<string name="bubble_overflow_empty_title" msgid="3120029421991510842">"මෑත බුබුලු නැත"</string>
<string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"මෑත බුබුලු සහ ඉවත ලූ බුබුලු මෙහි දිස් වනු ඇත"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"මෙම දැනුම්දීම් වෙනස් කළ නොහැක."</string>
@@ -1005,7 +1002,8 @@
<string name="bubble_accessibility_action_move_top_right" msgid="6916868852433483569">"ඉහළ දකුණට ගෙන යන්න"</string>
<string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"පහළ වමට ගෙන යන්න"</string>
<string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"පහළ දකුණට ගෙන යන්න"</string>
- <string name="bubble_dismiss_text" msgid="7071770411580452911">"ඉවතලන්න"</string>
+ <!-- no translation found for bubble_dismiss_text (1314082410868930066) -->
+ <skip />
<string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"සංවාදය බුබුලු නොදමන්න"</string>
<string name="bubbles_user_education_title" msgid="5547017089271445797">"බුබුලු භාවිතයෙන් කතාබහ කරන්න"</string>
<string name="bubbles_user_education_description" msgid="1160281719576715211">"නව සංවාද පාවෙන අයිකන හෝ බුබුලු ලෙස දිස් වේ. බුබුල විවෘත කිරීමට තට්ටු කරන්න. එය ගෙන යාමට අදින්න."</string>
@@ -1016,11 +1014,14 @@
<string name="notification_content_system_nav_changed" msgid="5077913144844684544">"පද්ධති සංචලනය යාවත්කාලීන කළා. වෙනස්කම් සිදු කිරීමට, සැකසීම් වෙත යන්න."</string>
<string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"පද්ධති සංචලනය යාවත්කාලීන කිරීමට සැකසීම් වෙත යන්න"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"පොරොත්තු"</string>
+ <string name="priority_onboarding_title" msgid="2893070698479227616">"සංවාදය ප්‍රමුඛතාව වෙත සකසන ලදී"</string>
+ <string name="priority_onboarding_behavior" msgid="5342816047020432929">"ප්‍රමුඛතා සංවාද:"</string>
<string name="priority_onboarding_show_at_top_text" msgid="1678400241025513541">"සංවාද කොටසේ ඉහළ දී පෙන්වන්න"</string>
<string name="priority_onboarding_show_avatar_text" msgid="5756291381124091508">"පැතිකඩ පින්තූරය අගුලු තිරය මත පෙන්වන්න"</string>
<string name="priority_onboarding_appear_as_bubble_text" msgid="4227039772250263122">"යෙදුම්වල ඉහළම පාවෙන බුබුලක් ලෙස දිස් වේ"</string>
<string name="priority_onboarding_ignores_dnd_text" msgid="2918952762719600529">"බාධා නොකරන්න හට බාධා කරන්න"</string>
<string name="priority_onboarding_done_button_title" msgid="4569550984286506007">"තේරුණා"</string>
+ <string name="priority_onboarding_settings_button_title" msgid="6663601574303585927">"සැකසීම්"</string>
<string name="magnification_overlay_title" msgid="6584179429612427958">"විශාලන උඩැතිරි කවුළුව"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"විශාලන කවුළුව"</string>
<string name="magnification_controls_title" msgid="8421106606708891519">"විශාලනය කිරීමේ කවුළු පාලන"</string>
@@ -1062,9 +1063,13 @@
<string name="controls_structure_tooltip" msgid="4355922222944447867">"තව බැලීමට ස්වයිප් කරන්න"</string>
<string name="controls_seeding_in_progress" msgid="3033855341410264148">"නිර්දේශ පූරණය කරමින්"</string>
<string name="controls_media_close_session" msgid="9023534788828414585">"මෙම මාධ්‍ය සැසිය වසන්න"</string>
+ <string name="controls_media_resume" msgid="1933520684481586053">"නැවත පටන් ගන්න"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"අක්‍රියයි, යෙදුම පරීක්ෂා කරන්න"</string>
<string name="controls_error_retryable" msgid="864025882878378470">"දෝෂයකි, නැවත උත්සාහ කරමින්…"</string>
- <string name="controls_error_removed" msgid="6299213591234723805">"උපාංගය ඉවත් කර ඇත"</string>
+ <string name="controls_error_removed" msgid="6675638069846014366">"හමු නොවිණි"</string>
+ <string name="controls_error_removed_title" msgid="1207794911208047818">"පාලනය ලබා ගත නොහැකිය"</string>
+ <string name="controls_error_removed_message" msgid="2885911717034750542">"<xliff:g id="DEVICE">%1$s</xliff:g> වෙත ප්‍රවේශ විය නොහැකි විය. පාලනය තිබෙන බව සහ යෙදුම් සැකසීම් වෙනස් වී ඇති බව සහතික කර ගැනීමට <xliff:g id="APPLICATION">%2$s</xliff:g> යෙදුම පරීක්ෂා කරන්න."</string>
+ <string name="controls_open_app" msgid="483650971094300141">"යෙදුම විවෘත කරන්න"</string>
<string name="controls_error_generic" msgid="352500456918362905">"තත්ත්වය පූරණය කළ නොහැකිය"</string>
<string name="controls_error_failed" msgid="960228639198558525">"දෝෂයකි, නැවත උත්සාහ කරන්න"</string>
<string name="controls_in_progress" msgid="4421080500238215939">"ප්‍රගතියේ පවතී"</string>
diff --git a/packages/SystemUI/res/values-sk/strings.xml b/packages/SystemUI/res/values-sk/strings.xml
index c5b615a04b40..e0ba13dbfd98 100644
--- a/packages/SystemUI/res/values-sk/strings.xml
+++ b/packages/SystemUI/res/values-sk/strings.xml
@@ -77,9 +77,6 @@
<string name="compat_mode_on" msgid="4963711187149440884">"Priblížiť na celú obrazovku"</string>
<string name="compat_mode_off" msgid="7682459748279487945">"Na celú obrazovku"</string>
<string name="global_action_screenshot" msgid="2760267567509131654">"Snímka obrazovky"</string>
- <string name="global_action_lock_message" product="default" msgid="4466026255205186456">"Odomknite svoj telefón pre ďalšie možnosti"</string>
- <string name="global_action_lock_message" product="tablet" msgid="7621167597240332986">"Odomknite svoj tablet pre ďalšie možnosti"</string>
- <string name="global_action_lock_message" product="device" msgid="538790401275363781">"Odomknite svoje zariadenie pre ďalšie možnosti"</string>
<string name="remote_input_image_insertion_text" msgid="4850791636452521123">"odoslal(a) obrázok"</string>
<string name="screenshot_saving_ticker" msgid="6519186952674544916">"Prebieha ukladanie snímky obrazovky..."</string>
<string name="screenshot_saving_title" msgid="2298349784913287333">"Prebieha ukladanie snímky obrazovky..."</string>
@@ -721,14 +718,14 @@
<string name="notification_alert_title" msgid="3656229781017543655">"Predvolené"</string>
<string name="notification_bubble_title" msgid="8330481035191903164">"Bublina"</string>
<string name="notification_channel_summary_low" msgid="4860617986908931158">"Žiadny zvuk ani vibrácie"</string>
- <string name="notification_conversation_summary_low" msgid="1734433426085468009">"Žiadny zvuk ani vibrácie a zobrazuje sa v dolnej sekcii konverzácie"</string>
- <string name="notification_channel_summary_default" msgid="3282930979307248890">"Môže zvoniť alebo vibrovať podľa nastavení telefónu"</string>
+ <string name="notification_conversation_summary_low" msgid="1734433426085468009">"Žiadny zvuk ani vibrácie a zobrazuje sa nižšie v sekcii konverzácií"</string>
+ <string name="notification_channel_summary_default" msgid="3282930979307248890">"Zvoní či vibruje podľa nastavení telefónu"</string>
<string name="notification_channel_summary_default_with_bubbles" msgid="1782419896613644568">"Môže zvoniť alebo vibrovať podľa nastavení telefónu. Predvolene sa zobrazia konverzácie z bubliny <xliff:g id="APP_NAME">%1$s</xliff:g>."</string>
<string name="notification_channel_summary_bubble" msgid="7235935211580860537">"Upúta vás plávajúcim odkazom na tento obsah."</string>
- <string name="notification_channel_summary_priority" msgid="7952654515769021553">"Nájdete ju v hornej sekcii konverzácie ako plávajúcu bublinu a zobrazuje profilovú fotku na uzamknutej obrazovke"</string>
+ <string name="notification_channel_summary_priority" msgid="7952654515769021553">"Nájdete ju hore v sekcii konverzácií ako plávajúcu bublinu, zobrazuje profilovú fotku na uzamknutej obrazovke"</string>
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"Nastavenia"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"Priorita"</string>
- <string name="no_shortcut" msgid="7176375126961212514">"<xliff:g id="APP_NAME">%1$s</xliff:g> nepodporuje nastavenia konkrétnych konverzácií"</string>
+ <string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> nepodporuje funkcie konverzácie"</string>
<string name="bubble_overflow_empty_title" msgid="3120029421991510842">"Žiadne nedávne bubliny"</string>
<string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"Tu sa budú zobrazovať nedávne a zavreté bubliny"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"Tieto upozornenia sa nedajú upraviť."</string>
@@ -1015,7 +1012,8 @@
<string name="bubble_accessibility_action_move_top_right" msgid="6916868852433483569">"Presunúť doprava nahor"</string>
<string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"Presunúť doľava nadol"</string>
<string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"Presunúť doprava nadol"</string>
- <string name="bubble_dismiss_text" msgid="7071770411580452911">"Zavrieť"</string>
+ <!-- no translation found for bubble_dismiss_text (1314082410868930066) -->
+ <skip />
<string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"Nezobrazovať konverzáciu ako bublinu"</string>
<string name="bubbles_user_education_title" msgid="5547017089271445797">"Čet pomocou bublín"</string>
<string name="bubbles_user_education_description" msgid="1160281719576715211">"Nové konverzácie sa zobrazujú ako plávajúce ikony či bubliny. Bublinu otvoríte klepnutím. Premiestnite ju presunutím."</string>
@@ -1026,19 +1024,22 @@
<string name="notification_content_system_nav_changed" msgid="5077913144844684544">"Navigácia v systéme bola aktualizovaná. Ak chcete vykonať zmeny, prejdite do Nastavení."</string>
<string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"Prejdite do Nastavení a aktualizujte navigáciu v systéme"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Pohotovostný režim"</string>
- <string name="priority_onboarding_show_at_top_text" msgid="1678400241025513541">"Zobrazovať v hornej sekcii konverzácie"</string>
+ <string name="priority_onboarding_title" msgid="2893070698479227616">"Konverzácia je nastavená ako prioritná"</string>
+ <string name="priority_onboarding_behavior" msgid="5342816047020432929">"Správanie prioritných konverzácií:"</string>
+ <string name="priority_onboarding_show_at_top_text" msgid="1678400241025513541">"Zobrazovať hore v sekcii konverzácií"</string>
<string name="priority_onboarding_show_avatar_text" msgid="5756291381124091508">"Zobrazovať profilovú fotku na uzamknutej obrazovke"</string>
<string name="priority_onboarding_appear_as_bubble_text" msgid="4227039772250263122">"Zobrazovať ako plávajúce bubliny nad aplikáciami"</string>
<string name="priority_onboarding_ignores_dnd_text" msgid="2918952762719600529">"Prerušovať režim bez vyrušení"</string>
<string name="priority_onboarding_done_button_title" msgid="4569550984286506007">"Dobre"</string>
+ <string name="priority_onboarding_settings_button_title" msgid="6663601574303585927">"Nastavenia"</string>
<string name="magnification_overlay_title" msgid="6584179429612427958">"Okno prekrytia priblíženia"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"Okno priblíženia"</string>
<string name="magnification_controls_title" msgid="8421106606708891519">"Ovládacie prvky okna priblíženia"</string>
<string name="quick_controls_title" msgid="6839108006171302273">"Ovládanie zariadení"</string>
- <string name="quick_controls_subtitle" msgid="1667408093326318053">"Pridajte ovládacie prvky pre svoje pripojené zariadenia"</string>
+ <string name="quick_controls_subtitle" msgid="1667408093326318053">"Pridajte si ovládače pripojených zariadení"</string>
<string name="quick_controls_setup_title" msgid="8901436655997849822">"Nastavenie ovládania zariadení"</string>
<string name="quick_controls_setup_subtitle" msgid="1681506617879773824">"Pridržaním vypínača získate prístup k ovládacím prvkom"</string>
- <string name="controls_providers_title" msgid="6879775889857085056">"Výberom aplikácie pridajte ovládacie prvky"</string>
+ <string name="controls_providers_title" msgid="6879775889857085056">"Vyberte aplikáciu, ktorej ovládače si chcete pridať"</string>
<plurals name="controls_number_of_favorites" formatted="false" msgid="1057347832073807380">
<item quantity="few">Boli pridané <xliff:g id="NUMBER_1">%s</xliff:g> ovládacie prvky.</item>
<item quantity="many"><xliff:g id="NUMBER_1">%s</xliff:g> controls added.</item>
@@ -1053,9 +1054,9 @@
<string name="accessibility_control_change_unfavorite" msgid="6997408061750740327">"odstránite z obľúbených"</string>
<string name="accessibility_control_move" msgid="8980344493796647792">"Presunúť na pozíciu <xliff:g id="NUMBER">%d</xliff:g>"</string>
<string name="controls_favorite_default_title" msgid="967742178688938137">"Ovládacie prvky"</string>
- <string name="controls_favorite_subtitle" msgid="6604402232298443956">"Vyberte si ovládacie prvky, ku ktorým chcete mať prístup v ponuke vypínača"</string>
- <string name="controls_favorite_rearrange" msgid="5616952398043063519">"Ovládacie prvky môžete usporiadať pridržaním a presunutím"</string>
- <string name="controls_favorite_removed" msgid="5276978408529217272">"Všetky ovládacie prvky boli odstránené"</string>
+ <string name="controls_favorite_subtitle" msgid="6604402232298443956">"Vyberte si ovládače, ktoré budú prístupné v ponuke vypínača"</string>
+ <string name="controls_favorite_rearrange" msgid="5616952398043063519">"Polohu každého ovládača môžete zmeniť jeho pridržaním a presunutím"</string>
+ <string name="controls_favorite_removed" msgid="5276978408529217272">"Všetky ovládače boli odstránené"</string>
<string name="controls_favorite_toast_no_changes" msgid="7094494210840877931">"Zmeny neboli uložené"</string>
<string name="controls_favorite_load_error" msgid="2533215155804455348">"Zoznam všetkých ovl. prvkov sa nepodarilo načítať."</string>
<string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Iné"</string>
@@ -1063,24 +1064,28 @@
<string name="controls_dialog_ok" msgid="2770230012857881822">"Pridať"</string>
<string name="controls_dialog_message" msgid="342066938390663844">"Navrhuje <xliff:g id="APP">%s</xliff:g>"</string>
<string name="controls_dialog_confirmation" msgid="586517302736263447">"Ovládanie bolo aktualizované"</string>
- <string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"Kód PIN obsahuje písmená alebo symboly"</string>
- <string name="controls_pin_verify" msgid="3452778292918877662">"Overiť <xliff:g id="DEVICE">%s</xliff:g>"</string>
+ <string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"PIN obsahuje písmená či symboly"</string>
+ <string name="controls_pin_verify" msgid="3452778292918877662">"<xliff:g id="DEVICE">%s</xliff:g>, overenie"</string>
<string name="controls_pin_wrong" msgid="6162694056042164211">"Nesprávny PIN"</string>
<string name="controls_pin_verifying" msgid="3755045989392131746">"Overuje sa…"</string>
<string name="controls_pin_instructions" msgid="6363309783822475238">"Zadajte PIN"</string>
- <string name="controls_pin_instructions_retry" msgid="1566667581012131046">"Vyskúšajte iný kód PIN"</string>
+ <string name="controls_pin_instructions_retry" msgid="1566667581012131046">"Skúste iný PIN"</string>
<string name="controls_confirmation_confirming" msgid="2596071302617310665">"Potvrdzuje sa…"</string>
<string name="controls_confirmation_message" msgid="7744104992609594859">"Potvrdenie zmeny zariadenia <xliff:g id="DEVICE">%s</xliff:g>"</string>
<string name="controls_structure_tooltip" msgid="4355922222944447867">"Potiahnutím zobrazíte ďalšie položky"</string>
<string name="controls_seeding_in_progress" msgid="3033855341410264148">"Načítavajú sa odporúčania"</string>
<string name="controls_media_close_session" msgid="9023534788828414585">"Zavrieť túto reláciu média"</string>
+ <string name="controls_media_resume" msgid="1933520684481586053">"Pokračovať"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"Neaktívne, preverte aplikáciu"</string>
<string name="controls_error_retryable" msgid="864025882878378470">"Chyba, skúša sa znova…"</string>
- <string name="controls_error_removed" msgid="6299213591234723805">"Zariadenie je odstránené"</string>
+ <string name="controls_error_removed" msgid="6675638069846014366">"Nenájdené"</string>
+ <string name="controls_error_removed_title" msgid="1207794911208047818">"Ovládanie nie je k dispozícii"</string>
+ <string name="controls_error_removed_message" msgid="2885911717034750542">"Nepodarilo sa získať prístup k zariadeniu <xliff:g id="DEVICE">%1$s</xliff:g>. V aplikácii <xliff:g id="APPLICATION">%2$s</xliff:g> skontrolujte, či je ovládanie stále k dispozícii a či sa nezmenili nastavenia."</string>
+ <string name="controls_open_app" msgid="483650971094300141">"Otvoriť aplikáciu"</string>
<string name="controls_error_generic" msgid="352500456918362905">"Stav sa nepodarilo načítať"</string>
<string name="controls_error_failed" msgid="960228639198558525">"Chyba, skúste to znova"</string>
<string name="controls_in_progress" msgid="4421080500238215939">"Prebieha"</string>
<string name="controls_added_tooltip" msgid="4842812921719153085">"Pridržaním vypínača zobrazíte nové ovládacie prvky"</string>
- <string name="controls_menu_add" msgid="4447246119229920050">"Pridať ovládacie prvky"</string>
- <string name="controls_menu_edit" msgid="890623986951347062">"Upraviť ovládacie prvky"</string>
+ <string name="controls_menu_add" msgid="4447246119229920050">"Pridať ovládače"</string>
+ <string name="controls_menu_edit" msgid="890623986951347062">"Upraviť ovládače"</string>
</resources>
diff --git a/packages/SystemUI/res/values-sl/strings.xml b/packages/SystemUI/res/values-sl/strings.xml
index a3995ac4db24..7066e8dc1612 100644
--- a/packages/SystemUI/res/values-sl/strings.xml
+++ b/packages/SystemUI/res/values-sl/strings.xml
@@ -77,9 +77,6 @@
<string name="compat_mode_on" msgid="4963711187149440884">"Povečava čez cel zaslon"</string>
<string name="compat_mode_off" msgid="7682459748279487945">"Raztegnitev čez zaslon"</string>
<string name="global_action_screenshot" msgid="2760267567509131654">"Posnetek zaslona"</string>
- <string name="global_action_lock_message" product="default" msgid="4466026255205186456">"Za več možnosti odklenite telefon"</string>
- <string name="global_action_lock_message" product="tablet" msgid="7621167597240332986">"Za več možnosti odklenite tablični računalnik"</string>
- <string name="global_action_lock_message" product="device" msgid="538790401275363781">"Za več možnosti odklenite napravo"</string>
<string name="remote_input_image_insertion_text" msgid="4850791636452521123">"je poslal(-a) sliko"</string>
<string name="screenshot_saving_ticker" msgid="6519186952674544916">"Shranjev. posnetka zaslona ..."</string>
<string name="screenshot_saving_title" msgid="2298349784913287333">"Shranjevanje posnetka zaslona ..."</string>
@@ -601,29 +598,21 @@
<string name="volume_odi_captions_hint_enable" msgid="2073091194012843195">"omogoči"</string>
<string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"onemogoči"</string>
<string name="accessibility_output_chooser" msgid="7807898688967194183">"Izbira druge izhodne naprave"</string>
- <!-- no translation found for screen_pinning_title (9058007390337841305) -->
- <skip />
+ <string name="screen_pinning_title" msgid="9058007390337841305">"Aplikacija je pripeta"</string>
<string name="screen_pinning_description" msgid="8699395373875667743">"S tem ostane zaslon viden, dokler ga ne odpnete. Če ga želite odpeti, hkrati pridržite gumba za nazaj in pregled."</string>
<string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"S tem ostane zaslon viden, dokler ga ne odpnete. Če ga želite odpeti, hkrati pridržite gumba za nazaj in za začetni zaslon."</string>
<string name="screen_pinning_description_gestural" msgid="7246323931831232068">"S tem ostane zaslon viden, dokler ga ne odpnete. Če ga želite odpeti, povlecite navzgor in pridržite."</string>
<string name="screen_pinning_description_accessible" msgid="7386449191953535332">"S tem ostane zaslon viden, dokler ga ne odpnete. Če ga želite odpeti, pridržite gumb za pregled."</string>
<string name="screen_pinning_description_recents_invisible_accessible" msgid="2857071808674481986">"S tem ostane zaslon viden, dokler ga ne odpnete. Če ga želite odpeti, pridržite gumb za začetni zaslon."</string>
- <!-- no translation found for screen_pinning_exposes_personal_data (8189852022981524789) -->
- <skip />
- <!-- no translation found for screen_pinning_can_open_other_apps (7529756813231421455) -->
- <skip />
- <!-- no translation found for screen_pinning_toast (8177286912533744328) -->
- <skip />
- <!-- no translation found for screen_pinning_toast_recents_invisible (6850978077443052594) -->
- <skip />
- <!-- no translation found for screen_pinning_toast_gesture_nav (170699893395336705) -->
- <skip />
+ <string name="screen_pinning_exposes_personal_data" msgid="8189852022981524789">"Dostopni so lahko osebni podatki (na primer stiki in vsebina e-poštnih sporočil)."</string>
+ <string name="screen_pinning_can_open_other_apps" msgid="7529756813231421455">"Pripeta aplikacija lahko odpre druge aplikacije."</string>
+ <string name="screen_pinning_toast" msgid="8177286912533744328">"Če želite odpeti to aplikacijo, hkrati pridržite gumba za nazaj in za pregled."</string>
+ <string name="screen_pinning_toast_recents_invisible" msgid="6850978077443052594">"Če želite odpeti to aplikacijo, hkrati pridržite gumba za nazaj in za začetni zaslon."</string>
+ <string name="screen_pinning_toast_gesture_nav" msgid="170699893395336705">"Če želite odpeti to aplikacijo, povlecite navzgor in pridržite."</string>
<string name="screen_pinning_positive" msgid="3285785989665266984">"Razumem"</string>
<string name="screen_pinning_negative" msgid="6882816864569211666">"Ne, hvala"</string>
- <!-- no translation found for screen_pinning_start (7483998671383371313) -->
- <skip />
- <!-- no translation found for screen_pinning_exit (4553787518387346893) -->
- <skip />
+ <string name="screen_pinning_start" msgid="7483998671383371313">"Aplikacija je pripeta"</string>
+ <string name="screen_pinning_exit" msgid="4553787518387346893">"Aplikacija je odpeta"</string>
<string name="quick_settings_reset_confirmation_title" msgid="463533331480997595">"Želite skriti <xliff:g id="TILE_LABEL">%1$s</xliff:g>?"</string>
<string name="quick_settings_reset_confirmation_message" msgid="2320586180785674186">"Znova se bo pojavila, ko jo naslednjič vklopite v nastavitvah."</string>
<string name="quick_settings_reset_confirmation_button" msgid="3341477479055016776">"Skrij"</string>
@@ -736,7 +725,7 @@
<string name="notification_channel_summary_priority" msgid="7952654515769021553">"Prikaz na vrhu razdelka s pogovorom in v plavajočem oblačku, prikaz profilne slike na zaklenjenem zaslonu"</string>
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"Nastavitve"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"Prednost"</string>
- <string name="no_shortcut" msgid="7176375126961212514">"Aplikacija <xliff:g id="APP_NAME">%1$s</xliff:g> ne podpira posebnih nastavitev za pogovore"</string>
+ <string name="no_shortcut" msgid="8257177117568230126">"Aplikacija <xliff:g id="APP_NAME">%1$s</xliff:g> ne podpira pogovornih funkcij"</string>
<string name="bubble_overflow_empty_title" msgid="3120029421991510842">"Ni nedavnih oblačkov"</string>
<string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"Tukaj bodo prikazani tako nedavni kot tudi opuščeni oblački"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"Za ta obvestila ni mogoče spremeniti nastavitev."</string>
@@ -1023,7 +1012,8 @@
<string name="bubble_accessibility_action_move_top_right" msgid="6916868852433483569">"Premakni zgoraj desno"</string>
<string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"Premakni spodaj levo"</string>
<string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"Premakni spodaj desno"</string>
- <string name="bubble_dismiss_text" msgid="7071770411580452911">"Opusti"</string>
+ <!-- no translation found for bubble_dismiss_text (1314082410868930066) -->
+ <skip />
<string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"Pogovora ne prikaži v oblačku"</string>
<string name="bubbles_user_education_title" msgid="5547017089271445797">"Klepet z oblački"</string>
<string name="bubbles_user_education_description" msgid="1160281719576715211">"Novi pogovori so prikazani kot lebdeče ikone ali oblački. Če želite odpreti oblaček, se ga dotaknite. Če ga želite premakniti, ga povlecite."</string>
@@ -1034,11 +1024,14 @@
<string name="notification_content_system_nav_changed" msgid="5077913144844684544">"Krmarjenje po sistemu je posodobljeno. Če želite opraviti spremembe, odprite nastavitve."</string>
<string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"Če želite posodobiti krmarjenje po sistemu, odprite nastavitve"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Stanje pripravljenosti"</string>
+ <string name="priority_onboarding_title" msgid="2893070698479227616">"Pogovor je nastavljen kot prednosten"</string>
+ <string name="priority_onboarding_behavior" msgid="5342816047020432929">"Prednostni pogovori bodo:"</string>
<string name="priority_onboarding_show_at_top_text" msgid="1678400241025513541">"Prikazano na vrhu razdelka s pogovorom"</string>
<string name="priority_onboarding_show_avatar_text" msgid="5756291381124091508">"Prikaz profilne slike na zaklenjenem zaslonu"</string>
<string name="priority_onboarding_appear_as_bubble_text" msgid="4227039772250263122">"Prikazano kot lebdeč oblaček čez druge aplikacije"</string>
<string name="priority_onboarding_ignores_dnd_text" msgid="2918952762719600529">"Preglasi način »ne moti«"</string>
<string name="priority_onboarding_done_button_title" msgid="4569550984286506007">"V redu"</string>
+ <string name="priority_onboarding_settings_button_title" msgid="6663601574303585927">"Nastavitve"</string>
<string name="magnification_overlay_title" msgid="6584179429612427958">"Prekrivno povečevalno okno"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"Povečevalno okno"</string>
<string name="magnification_controls_title" msgid="8421106606708891519">"Kontrolniki povečevalnega okna"</string>
@@ -1082,9 +1075,13 @@
<string name="controls_structure_tooltip" msgid="4355922222944447867">"Če si želite ogledati več, povlecite"</string>
<string name="controls_seeding_in_progress" msgid="3033855341410264148">"Nalaganje priporočil"</string>
<string name="controls_media_close_session" msgid="9023534788828414585">"Zapri to sejo predstavnosti"</string>
+ <string name="controls_media_resume" msgid="1933520684481586053">"Nadaljuj"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"Neaktivno, poglejte aplikacijo"</string>
<string name="controls_error_retryable" msgid="864025882878378470">"Napaka, vnovični poskus …"</string>
- <string name="controls_error_removed" msgid="6299213591234723805">"Naprava je bila odstranjena"</string>
+ <string name="controls_error_removed" msgid="6675638069846014366">"Ni mogoče najti"</string>
+ <string name="controls_error_removed_title" msgid="1207794911208047818">"Kontrolnik ni na voljo"</string>
+ <string name="controls_error_removed_message" msgid="2885911717034750542">"Ni bilo mogoče dostopiti do: <xliff:g id="DEVICE">%1$s</xliff:g>. Preverite aplikacijo <xliff:g id="APPLICATION">%2$s</xliff:g> in se prepričajte, da je kontrolnik še vedno na voljo ter da se nastavitve aplikacije niso spremenile."</string>
+ <string name="controls_open_app" msgid="483650971094300141">"Odpri aplikacijo"</string>
<string name="controls_error_generic" msgid="352500456918362905">"Stanja ni mogoče naložiti"</string>
<string name="controls_error_failed" msgid="960228639198558525">"Napaka, poskusite znova"</string>
<string name="controls_in_progress" msgid="4421080500238215939">"V teku"</string>
diff --git a/packages/SystemUI/res/values-sq/strings.xml b/packages/SystemUI/res/values-sq/strings.xml
index 87c39d6f1447..a23a85bf97fa 100644
--- a/packages/SystemUI/res/values-sq/strings.xml
+++ b/packages/SystemUI/res/values-sq/strings.xml
@@ -77,9 +77,6 @@
<string name="compat_mode_on" msgid="4963711187149440884">"Zmadho për të mbushur ekranin"</string>
<string name="compat_mode_off" msgid="7682459748279487945">"Shtrije për të mbushur ekranin"</string>
<string name="global_action_screenshot" msgid="2760267567509131654">"Pamja e ekranit"</string>
- <string name="global_action_lock_message" product="default" msgid="4466026255205186456">"Shkyçe telefonin për më shumë opsione"</string>
- <string name="global_action_lock_message" product="tablet" msgid="7621167597240332986">"Shkyçe tabletin për më shumë opsione"</string>
- <string name="global_action_lock_message" product="device" msgid="538790401275363781">"Shkyçe pajisjen për më shumë opsione"</string>
<string name="remote_input_image_insertion_text" msgid="4850791636452521123">"dërgoi një imazh"</string>
<string name="screenshot_saving_ticker" msgid="6519186952674544916">"Po ruan pamjen e ekranit..."</string>
<string name="screenshot_saving_title" msgid="2298349784913287333">"Po ruan pamjen e ekranit…"</string>
@@ -722,7 +719,7 @@
<string name="notification_channel_summary_priority" msgid="7952654515769021553">"Shfaqet në krye të seksionit të bisedës dhe shfaqet si flluskë pluskuese, shfaq fotografinë e profilit në ekranin e kyçjes"</string>
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"Cilësimet"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"Përparësia"</string>
- <string name="no_shortcut" msgid="7176375126961212514">"<xliff:g id="APP_NAME">%1$s</xliff:g> nuk i mbështet cilësimet specifike të bisedës"</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>
<string name="bubble_overflow_empty_title" msgid="3120029421991510842">"Nuk ka flluska të fundit"</string>
<string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"Flluskat e fundit dhe flluskat e hequra do të shfaqen këtu"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"Këto njoftime nuk mund të modifikohen."</string>
@@ -1005,7 +1002,8 @@
<string name="bubble_accessibility_action_move_top_right" msgid="6916868852433483569">"Lëviz lart djathtas"</string>
<string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"Zhvendos poshtë majtas"</string>
<string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"Lëvize poshtë djathtas"</string>
- <string name="bubble_dismiss_text" msgid="7071770411580452911">"Hiq"</string>
+ <!-- no translation found for bubble_dismiss_text (1314082410868930066) -->
+ <skip />
<string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"Mos e vendos bisedën në flluskë"</string>
<string name="bubbles_user_education_title" msgid="5547017089271445797">"Bisedo duke përdorur flluskat"</string>
<string name="bubbles_user_education_description" msgid="1160281719576715211">"Bisedat e reja shfaqen si ikona pluskuese ose flluska. Trokit për të hapur flluskën. Zvarrit për ta zhvendosur."</string>
@@ -1016,11 +1014,14 @@
<string name="notification_content_system_nav_changed" msgid="5077913144844684544">"Navigimi i sistemit u përditësua. Për të bërë ndryshime, shko te \"Cilësimet\"."</string>
<string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"Shko te \"Cilësimet\" për të përditësuar navigimin e sistemit"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Në gatishmëri"</string>
+ <string name="priority_onboarding_title" msgid="2893070698479227616">"Biseda u caktua me përparësi"</string>
+ <string name="priority_onboarding_behavior" msgid="5342816047020432929">"Bisedat me përparësi do të:"</string>
<string name="priority_onboarding_show_at_top_text" msgid="1678400241025513541">"Shfaq në krye të seksionit të bisedës"</string>
<string name="priority_onboarding_show_avatar_text" msgid="5756291381124091508">"Shfaq figurën e profilit në ekranin e kyçjes"</string>
<string name="priority_onboarding_appear_as_bubble_text" msgid="4227039772250263122">"Shfaq si flluskë pluskuese mbi aplikacione"</string>
<string name="priority_onboarding_ignores_dnd_text" msgid="2918952762719600529">"Ndërprit \"Mos shqetëso\""</string>
<string name="priority_onboarding_done_button_title" msgid="4569550984286506007">"E kuptova"</string>
+ <string name="priority_onboarding_settings_button_title" msgid="6663601574303585927">"Cilësimet"</string>
<string name="magnification_overlay_title" msgid="6584179429612427958">"Dritarja e mbivendosjes së zmadhimit"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"Dritarja e zmadhimit"</string>
<string name="magnification_controls_title" msgid="8421106606708891519">"Kontrollet e dritares së zmadhimit"</string>
@@ -1062,9 +1063,13 @@
<string name="controls_structure_tooltip" msgid="4355922222944447867">"Rrëshqit shpejt për të shikuar më shumë"</string>
<string name="controls_seeding_in_progress" msgid="3033855341410264148">"Po ngarkon rekomandimet"</string>
<string name="controls_media_close_session" msgid="9023534788828414585">"Mbyll këtë sesion të medias"</string>
+ <string name="controls_media_resume" msgid="1933520684481586053">"Vazhdo"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"Joaktive, kontrollo aplikacionin"</string>
<string name="controls_error_retryable" msgid="864025882878378470">"Gabim, po provohet përsëri"</string>
- <string name="controls_error_removed" msgid="6299213591234723805">"Pajisja u hoq"</string>
+ <string name="controls_error_removed" msgid="6675638069846014366">"Nuk u gjet"</string>
+ <string name="controls_error_removed_title" msgid="1207794911208047818">"Kontrolli është i padisponueshëm"</string>
+ <string name="controls_error_removed_message" msgid="2885911717034750542">"Nuk mundi të qasej te <xliff:g id="DEVICE">%1$s</xliff:g>. Kontrollo aplikacionin <xliff:g id="APPLICATION">%2$s</xliff:g> për t\'u siguruar që kontrolli të jetë ende i disponueshëm dhe që cilësimet e aplikacionit të mos kenë ndryshuar."</string>
+ <string name="controls_open_app" msgid="483650971094300141">"Hap aplikacionin"</string>
<string name="controls_error_generic" msgid="352500456918362905">"Statusi nuk mund të ngarkohet"</string>
<string name="controls_error_failed" msgid="960228639198558525">"Gabim, provo sërish"</string>
<string name="controls_in_progress" msgid="4421080500238215939">"Në vazhdim"</string>
diff --git a/packages/SystemUI/res/values-sr/strings.xml b/packages/SystemUI/res/values-sr/strings.xml
index ad4161017c17..fde6413e4b97 100644
--- a/packages/SystemUI/res/values-sr/strings.xml
+++ b/packages/SystemUI/res/values-sr/strings.xml
@@ -77,9 +77,6 @@
<string name="compat_mode_on" msgid="4963711187149440884">"Зумирај на целом екрану"</string>
<string name="compat_mode_off" msgid="7682459748279487945">"Развуци на цео екран"</string>
<string name="global_action_screenshot" msgid="2760267567509131654">"Снимак екрана"</string>
- <string name="global_action_lock_message" product="default" msgid="4466026255205186456">"Откључајте телефон за још опција"</string>
- <string name="global_action_lock_message" product="tablet" msgid="7621167597240332986">"Откључајте таблет за још опција"</string>
- <string name="global_action_lock_message" product="device" msgid="538790401275363781">"Откључајте уређај за још опција"</string>
<string name="remote_input_image_insertion_text" msgid="4850791636452521123">"је послао/ла слику"</string>
<string name="screenshot_saving_ticker" msgid="6519186952674544916">"Чување снимка екрана..."</string>
<string name="screenshot_saving_title" msgid="2298349784913287333">"Чување снимка екрана..."</string>
@@ -725,7 +722,7 @@
<string name="notification_channel_summary_priority" msgid="7952654515769021553">"Приказује се у врху одељка за конверзације као плутајући облачић, приказује слику профила на закључаном екрану"</string>
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"Подешавања"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"Приоритет"</string>
- <string name="no_shortcut" msgid="7176375126961212514">"<xliff:g id="APP_NAME">%1$s</xliff:g> не подржава подешавања за конверзације"</string>
+ <string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> не подржава функције конверзације"</string>
<string name="bubble_overflow_empty_title" msgid="3120029421991510842">"Нема недавних облачића"</string>
<string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"Овде се приказују недавни и одбачени облачићи"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"Ова обавештења не могу да се мењају."</string>
@@ -1010,9 +1007,10 @@
<string name="bubble_accessibility_action_move_top_right" msgid="6916868852433483569">"Премести горе десно"</string>
<string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"Премести доле лево"</string>
<string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"Премести доле десно"</string>
- <string name="bubble_dismiss_text" msgid="7071770411580452911">"Одбаци"</string>
+ <!-- no translation found for bubble_dismiss_text (1314082410868930066) -->
+ <skip />
<string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"Не користи облачиће за конверзацију"</string>
- <string name="bubbles_user_education_title" msgid="5547017089271445797">"Ћаскајте помоћу облачића"</string>
+ <string name="bubbles_user_education_title" msgid="5547017089271445797">"Ћаскајте у облачићима"</string>
<string name="bubbles_user_education_description" msgid="1160281719576715211">"Нове конверзације се приказују као плутајуће иконе или облачићи. Додирните да бисте отворили облачић. Превуците да бисте га преместили."</string>
<string name="bubbles_user_education_manage_title" msgid="2848511858160342320">"Контролишите облачиће у било ком тренутку"</string>
<string name="bubbles_user_education_manage" msgid="1391639189507036423">"Додирните Управљајте да бисте искључили облачиће из ове апликације"</string>
@@ -1021,11 +1019,14 @@
<string name="notification_content_system_nav_changed" msgid="5077913144844684544">"Навигација система је ажурирана. Да бисте унели измене, идите у Подешавања."</string>
<string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"Идите у Подешавања да бисте ажурирали навигацију система"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Стање приправности"</string>
+ <string name="priority_onboarding_title" msgid="2893070698479227616">"Конверзација је подешена на приоритетну"</string>
+ <string name="priority_onboarding_behavior" msgid="5342816047020432929">"Приоритетне конверзације ће:"</string>
<string name="priority_onboarding_show_at_top_text" msgid="1678400241025513541">"Приказује се у врху одељка за конверзације"</string>
<string name="priority_onboarding_show_avatar_text" msgid="5756291381124091508">"Приказује слику профила на закључаном екрану"</string>
<string name="priority_onboarding_appear_as_bubble_text" msgid="4227039772250263122">"Приказују се плутајући облачићи преко апликација"</string>
<string name="priority_onboarding_ignores_dnd_text" msgid="2918952762719600529">"Омета подешавање Не узнемиравај"</string>
<string name="priority_onboarding_done_button_title" msgid="4569550984286506007">"Важи"</string>
+ <string name="priority_onboarding_settings_button_title" msgid="6663601574303585927">"Подешавања"</string>
<string name="magnification_overlay_title" msgid="6584179429612427958">"Преклопни прозор за увећање"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"Прозор за увећање"</string>
<string name="magnification_controls_title" msgid="8421106606708891519">"Контроле прозора за увећање"</string>
@@ -1062,19 +1063,23 @@
<string name="controls_pin_wrong" msgid="6162694056042164211">"Погрешан PIN"</string>
<string name="controls_pin_verifying" msgid="3755045989392131746">"Верификује се…"</string>
<string name="controls_pin_instructions" msgid="6363309783822475238">"Унесите PIN"</string>
- <string name="controls_pin_instructions_retry" msgid="1566667581012131046">"Пробајте помоћу другог PIN-а"</string>
+ <string name="controls_pin_instructions_retry" msgid="1566667581012131046">"Пробајте други PIN"</string>
<string name="controls_confirmation_confirming" msgid="2596071302617310665">"Потврђује се…"</string>
<string name="controls_confirmation_message" msgid="7744104992609594859">"Потврдите промену за: <xliff:g id="DEVICE">%s</xliff:g>"</string>
<string name="controls_structure_tooltip" msgid="4355922222944447867">"Превуците да бисте видели још"</string>
<string name="controls_seeding_in_progress" msgid="3033855341410264148">"Учитавају се препоруке"</string>
<string name="controls_media_close_session" msgid="9023534788828414585">"Затворите ову сесију медија"</string>
+ <string name="controls_media_resume" msgid="1933520684481586053">"Настави"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"Неактивно. Видите апликацију"</string>
<string name="controls_error_retryable" msgid="864025882878378470">"Грешка, покушава се поново…"</string>
- <string name="controls_error_removed" msgid="6299213591234723805">"Уређај је уклоњен"</string>
+ <string name="controls_error_removed" msgid="6675638069846014366">"Није пронађено"</string>
+ <string name="controls_error_removed_title" msgid="1207794911208047818">"Контрола није доступна"</string>
+ <string name="controls_error_removed_message" msgid="2885911717034750542">"Приступање уређају <xliff:g id="DEVICE">%1$s</xliff:g> није успело. Погледајте апликацију <xliff:g id="APPLICATION">%2$s</xliff:g> да бисте се уверили да је контрола још увек доступна и да се подешавања апликације нису променила."</string>
+ <string name="controls_open_app" msgid="483650971094300141">"Отвори апликацију"</string>
<string name="controls_error_generic" msgid="352500456918362905">"Учитавање статуса није успело"</string>
<string name="controls_error_failed" msgid="960228639198558525">"Грешка. Пробајте поново"</string>
<string name="controls_in_progress" msgid="4421080500238215939">"У току"</string>
<string name="controls_added_tooltip" msgid="4842812921719153085">"Задржите дугме за укључивање да бисте видели нове контроле"</string>
<string name="controls_menu_add" msgid="4447246119229920050">"Додај контроле"</string>
- <string name="controls_menu_edit" msgid="890623986951347062">"Измените контроле"</string>
+ <string name="controls_menu_edit" msgid="890623986951347062">"Измени контроле"</string>
</resources>
diff --git a/packages/SystemUI/res/values-sv/strings.xml b/packages/SystemUI/res/values-sv/strings.xml
index 35fff9fd3f89..af3839bc8e8b 100644
--- a/packages/SystemUI/res/values-sv/strings.xml
+++ b/packages/SystemUI/res/values-sv/strings.xml
@@ -77,9 +77,6 @@
<string name="compat_mode_on" msgid="4963711187149440884">"Zooma för att fylla skärm"</string>
<string name="compat_mode_off" msgid="7682459748279487945">"Dra för att fylla skärmen"</string>
<string name="global_action_screenshot" msgid="2760267567509131654">"Skärmdump"</string>
- <string name="global_action_lock_message" product="default" msgid="4466026255205186456">"Lås upp telefonen för fler alternativ"</string>
- <string name="global_action_lock_message" product="tablet" msgid="7621167597240332986">"Lås upp surfplattan för fler alternativ"</string>
- <string name="global_action_lock_message" product="device" msgid="538790401275363781">"Lås upp enheten för fler alternativ"</string>
<string name="remote_input_image_insertion_text" msgid="4850791636452521123">"har skickat en bild"</string>
<string name="screenshot_saving_ticker" msgid="6519186952674544916">"Skärmdumpen sparas ..."</string>
<string name="screenshot_saving_title" msgid="2298349784913287333">"Skärmdumpen sparas ..."</string>
@@ -722,7 +719,7 @@
<string name="notification_channel_summary_priority" msgid="7952654515769021553">"Visas högst upp bland konversationerna som en flytande bubbla, visar profilbilden på låsskärmen"</string>
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"Inställningar"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"Prioritet"</string>
- <string name="no_shortcut" msgid="7176375126961212514">"<xliff:g id="APP_NAME">%1$s</xliff:g> har inte stöd för konversationsspecifika inställningar"</string>
+ <string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> har inte stöd för konversationsfunktioner"</string>
<string name="bubble_overflow_empty_title" msgid="3120029421991510842">"Inga nya bubblor"</string>
<string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"De senaste bubblorna och ignorerade bubblor visas här"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"Det går inte att ändra de här aviseringarna."</string>
@@ -1005,7 +1002,8 @@
<string name="bubble_accessibility_action_move_top_right" msgid="6916868852433483569">"Flytta högst upp till höger"</string>
<string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"Flytta längst ned till vänster"</string>
<string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"Flytta längst ned till höger"</string>
- <string name="bubble_dismiss_text" msgid="7071770411580452911">"Stäng"</string>
+ <!-- no translation found for bubble_dismiss_text (1314082410868930066) -->
+ <skip />
<string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"Visa inte konversationen i bubblor"</string>
<string name="bubbles_user_education_title" msgid="5547017089271445797">"Chatta med bubblor"</string>
<string name="bubbles_user_education_description" msgid="1160281719576715211">"Nya konversationer visas som flytande ikoner, så kallade bubblor. Tryck på bubblan om du vill öppna den. Dra den om du vill flytta den."</string>
@@ -1016,11 +1014,14 @@
<string name="notification_content_system_nav_changed" msgid="5077913144844684544">"Systemnavigeringen har uppdaterats. Öppna inställningarna om du vill ändra något."</string>
<string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"Öppna inställningarna och uppdatera systemnavigeringen"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Viloläge"</string>
+ <string name="priority_onboarding_title" msgid="2893070698479227616">"Konversationen har angetts som prioriterad"</string>
+ <string name="priority_onboarding_behavior" msgid="5342816047020432929">"Följande gäller för prioriterade konversationer:"</string>
<string name="priority_onboarding_show_at_top_text" msgid="1678400241025513541">"Visa högst upp bland konversationerna"</string>
<string name="priority_onboarding_show_avatar_text" msgid="5756291381124091508">"Visa profilbild på låsskärmen"</string>
<string name="priority_onboarding_appear_as_bubble_text" msgid="4227039772250263122">"Visa som en flytande bubbla ovanpå appar"</string>
<string name="priority_onboarding_ignores_dnd_text" msgid="2918952762719600529">"Avbryt Stör ej"</string>
<string name="priority_onboarding_done_button_title" msgid="4569550984286506007">"OK"</string>
+ <string name="priority_onboarding_settings_button_title" msgid="6663601574303585927">"Inställningar"</string>
<string name="magnification_overlay_title" msgid="6584179429612427958">"Överlagrat förstoringsfönster"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"Förstoringsfönster"</string>
<string name="magnification_controls_title" msgid="8421106606708891519">"Inställningar för förstoringsfönster"</string>
@@ -1062,9 +1063,13 @@
<string name="controls_structure_tooltip" msgid="4355922222944447867">"Svep om du vill se mer"</string>
<string name="controls_seeding_in_progress" msgid="3033855341410264148">"Rekommendationer läses in"</string>
<string name="controls_media_close_session" msgid="9023534788828414585">"Stäng den här sessionen"</string>
+ <string name="controls_media_resume" msgid="1933520684481586053">"Återuppta"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"Inaktiv, kolla appen"</string>
<string name="controls_error_retryable" msgid="864025882878378470">"Fel, försöker igen …"</string>
- <string name="controls_error_removed" msgid="6299213591234723805">"Enheten har tagits bort"</string>
+ <string name="controls_error_removed" msgid="6675638069846014366">"Hittades inte"</string>
+ <string name="controls_error_removed_title" msgid="1207794911208047818">"Styrning är inte tillgänglig"</string>
+ <string name="controls_error_removed_message" msgid="2885911717034750542">"Det gick inte att komma åt <xliff:g id="DEVICE">%1$s</xliff:g>. Kontrollera att enheten fortfarande är tillgänglig för styrning och att appinställningarna inte har ändrats i <xliff:g id="APPLICATION">%2$s</xliff:g>-appen."</string>
+ <string name="controls_open_app" msgid="483650971094300141">"Öppna appen"</string>
<string name="controls_error_generic" msgid="352500456918362905">"Ingen status lästes in"</string>
<string name="controls_error_failed" msgid="960228639198558525">"Fel, försök igen"</string>
<string name="controls_in_progress" msgid="4421080500238215939">"Pågår"</string>
diff --git a/packages/SystemUI/res/values-sw/strings.xml b/packages/SystemUI/res/values-sw/strings.xml
index 47e208358168..f5ec81bf8fec 100644
--- a/packages/SystemUI/res/values-sw/strings.xml
+++ b/packages/SystemUI/res/values-sw/strings.xml
@@ -77,9 +77,6 @@
<string name="compat_mode_on" msgid="4963711187149440884">"Kuza ili kujaza skrini"</string>
<string name="compat_mode_off" msgid="7682459748279487945">"Tanua ili kujaza skrini"</string>
<string name="global_action_screenshot" msgid="2760267567509131654">"Picha ya skrini"</string>
- <string name="global_action_lock_message" product="default" msgid="4466026255205186456">"Fungua simu yako ili upate chaguo zaidi"</string>
- <string name="global_action_lock_message" product="tablet" msgid="7621167597240332986">"Fungua kompyuta yako kibao ili upate chaguo zaidi"</string>
- <string name="global_action_lock_message" product="device" msgid="538790401275363781">"Fungua kifaa chako ili upate chaguo zaidi"</string>
<string name="remote_input_image_insertion_text" msgid="4850791636452521123">"imetuma picha"</string>
<string name="screenshot_saving_ticker" msgid="6519186952674544916">"Inahifadhi picha ya skrini..."</string>
<string name="screenshot_saving_title" msgid="2298349784913287333">"Inahifadhi picha ya skrini..."</string>
@@ -595,29 +592,21 @@
<string name="volume_odi_captions_hint_enable" msgid="2073091194012843195">"washa"</string>
<string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"zima"</string>
<string name="accessibility_output_chooser" msgid="7807898688967194183">"Badilisha kifaa cha kutoa sauti"</string>
- <!-- no translation found for screen_pinning_title (9058007390337841305) -->
- <skip />
+ <string name="screen_pinning_title" msgid="9058007390337841305">"Programu imebandikwa"</string>
<string name="screen_pinning_description" msgid="8699395373875667743">"Hali hii huifanya ionekane hadi utakapoibandua. Gusa na ushikilie kipengele cha Nyuma na Muhtasari ili ubandue."</string>
<string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"Hali hii huifanya ionekane hadi utakapoibandua. Gusa na ushikilie kitufe cha kurudisha Nyuma na cha Mwanzo kwa pamoja ili ubandue."</string>
<string name="screen_pinning_description_gestural" msgid="7246323931831232068">"Hali hii huifanya ionekane hadi utakapoibandua. Telezesha kidole juu na ushikilie ili uibandue."</string>
<string name="screen_pinning_description_accessible" msgid="7386449191953535332">"Hali hii huifanya ionekane hadi utakapoibandua. Gusa na ushikilie kipengele cha Muhtasari ili ubandue."</string>
<string name="screen_pinning_description_recents_invisible_accessible" msgid="2857071808674481986">"Hali hii huifanya ionekane hadi utakapoibandua. Gusa na ushikilie kitufe cha Mwanzo ili ubandue."</string>
- <!-- no translation found for screen_pinning_exposes_personal_data (8189852022981524789) -->
- <skip />
- <!-- no translation found for screen_pinning_can_open_other_apps (7529756813231421455) -->
- <skip />
- <!-- no translation found for screen_pinning_toast (8177286912533744328) -->
- <skip />
- <!-- no translation found for screen_pinning_toast_recents_invisible (6850978077443052594) -->
- <skip />
- <!-- no translation found for screen_pinning_toast_gesture_nav (170699893395336705) -->
- <skip />
+ <string name="screen_pinning_exposes_personal_data" msgid="8189852022981524789">"Data binafsi inaweza kufikiwa (kama vile maudhui ya barua pepe na anwani)."</string>
+ <string name="screen_pinning_can_open_other_apps" msgid="7529756813231421455">"Programu iliyobandikwa inaweza kufungua programu zingine."</string>
+ <string name="screen_pinning_toast" msgid="8177286912533744328">"Ili ubandue programu hii, gusa na ushikilie vitufe vya Nyuma na Muhtasari"</string>
+ <string name="screen_pinning_toast_recents_invisible" msgid="6850978077443052594">"Ili ubandue programu hii, gusa na ushikilie vitufe vya Nyuma na Ukurasa wa Mwanzo"</string>
+ <string name="screen_pinning_toast_gesture_nav" msgid="170699893395336705">"Ili ubandue programu hii, telezesha kidole juu na ushikilie"</string>
<string name="screen_pinning_positive" msgid="3285785989665266984">"Nimeelewa"</string>
<string name="screen_pinning_negative" msgid="6882816864569211666">"Hapana"</string>
- <!-- no translation found for screen_pinning_start (7483998671383371313) -->
- <skip />
- <!-- no translation found for screen_pinning_exit (4553787518387346893) -->
- <skip />
+ <string name="screen_pinning_start" msgid="7483998671383371313">"Programu imebandikwa"</string>
+ <string name="screen_pinning_exit" msgid="4553787518387346893">"Programu imebanduliwa"</string>
<string name="quick_settings_reset_confirmation_title" msgid="463533331480997595">"Ungependa kuficha <xliff:g id="TILE_LABEL">%1$s</xliff:g>?"</string>
<string name="quick_settings_reset_confirmation_message" msgid="2320586180785674186">"Itaonekana tena wakati mwingine utakapoiwasha katika mipangilio."</string>
<string name="quick_settings_reset_confirmation_button" msgid="3341477479055016776">"Ficha"</string>
@@ -730,7 +719,7 @@
<string name="notification_channel_summary_priority" msgid="7952654515769021553">"Huonyeshwa kwenye sehemu ya juu ya mazungumzo, huonekana kama kiputo, huonyesha picha ya wasifu kwenye skrini iliyofungwa"</string>
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"Mipangilio"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"Kipaumbele"</string>
- <string name="no_shortcut" msgid="7176375126961212514">"<xliff:g id="APP_NAME">%1$s</xliff:g> haitumii mipangilio mahususi ya mazungumzo"</string>
+ <string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> haitumii vipengele vya mazungumzo"</string>
<string name="bubble_overflow_empty_title" msgid="3120029421991510842">"Hakuna viputo vya hivi majuzi"</string>
<string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"Viputo vya hivi karibuni na vile vilivyoondolewa vitaonekana hapa"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"Arifa hizi haziwezi kubadilishwa."</string>
@@ -1013,7 +1002,8 @@
<string name="bubble_accessibility_action_move_top_right" msgid="6916868852433483569">"Sogeza juu kulia"</string>
<string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"Sogeza chini kushoto"</string>
<string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"Sogeza chini kulia"</string>
- <string name="bubble_dismiss_text" msgid="7071770411580452911">"Ondoa"</string>
+ <!-- no translation found for bubble_dismiss_text (1314082410868930066) -->
+ <skip />
<string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"Usiweke viputo kwenye mazungumzo"</string>
<string name="bubbles_user_education_title" msgid="5547017089271445797">"Piga gumzo ukitumia viputo"</string>
<string name="bubbles_user_education_description" msgid="1160281719576715211">"Mazungumzo mapya huonekena kama aikoni au viputo vinavyoelea. Gusa ili ufungue kiputo. Buruta ili ukisogeze."</string>
@@ -1024,16 +1014,19 @@
<string name="notification_content_system_nav_changed" msgid="5077913144844684544">"Umesasisha usogezaji kwenye mfumo. Ili ubadilishe, nenda kwenye Mipangilio."</string>
<string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"Nenda kwenye mipangilio ili usasishe usogezaji kwenye mfumo"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Hali tuli"</string>
+ <string name="priority_onboarding_title" msgid="2893070698479227616">"Mazungumzo yamepewa kipaumbele"</string>
+ <string name="priority_onboarding_behavior" msgid="5342816047020432929">"Mazungumzo yaliyopewa kipaumbele:"</string>
<string name="priority_onboarding_show_at_top_text" msgid="1678400241025513541">"Onyesha kwenye sehemu ya juu ya mazungumzo"</string>
<string name="priority_onboarding_show_avatar_text" msgid="5756291381124091508">"Onyesha picha ya wasifu kwenye skrini iliyofungwa"</string>
<string name="priority_onboarding_appear_as_bubble_text" msgid="4227039772250263122">"Yataonekana kama kiputo kinachoelea juu ya programu"</string>
<string name="priority_onboarding_ignores_dnd_text" msgid="2918952762719600529">"Katiza kipengele cha Usinisumbue"</string>
<string name="priority_onboarding_done_button_title" msgid="4569550984286506007">"Nimeelewa"</string>
+ <string name="priority_onboarding_settings_button_title" msgid="6663601574303585927">"Mipangilio"</string>
<string name="magnification_overlay_title" msgid="6584179429612427958">"Dirisha la Kuwekelea Linalokuza"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"Dirisha la Ukuzaji"</string>
<string name="magnification_controls_title" msgid="8421106606708891519">"Vidhibiti vya Dirisha la Ukuzaji"</string>
<string name="quick_controls_title" msgid="6839108006171302273">"Vidhibiti vya vifaa"</string>
- <string name="quick_controls_subtitle" msgid="1667408093326318053">"Weka vidhibiti vya vifaa vyako vilivyounganishwa"</string>
+ <string name="quick_controls_subtitle" msgid="1667408093326318053">"Weka vidhibiti vya vifaa ulivyounganisha"</string>
<string name="quick_controls_setup_title" msgid="8901436655997849822">"Weka mipangilio ya vidhibiti vya vifaa"</string>
<string name="quick_controls_setup_subtitle" msgid="1681506617879773824">"Shikilia Kitufe cha kuwasha/kuzima ili ufikie vidhibiti vyako"</string>
<string name="controls_providers_title" msgid="6879775889857085056">"Chagua programu ili uweke vidhibiti"</string>
@@ -1050,7 +1043,7 @@
<string name="accessibility_control_move" msgid="8980344493796647792">"Sogeza kwenye nafasi ya <xliff:g id="NUMBER">%d</xliff:g>"</string>
<string name="controls_favorite_default_title" msgid="967742178688938137">"Vidhibiti"</string>
<string name="controls_favorite_subtitle" msgid="6604402232298443956">"Chagua vidhibiti vya kufikia ukitumia menyu ya kuwasha/kuzima"</string>
- <string name="controls_favorite_rearrange" msgid="5616952398043063519">"Shikilia na uburute ili upange upya vidhibiti"</string>
+ <string name="controls_favorite_rearrange" msgid="5616952398043063519">"Shikilia na uburute ili upange vidhibiti upya"</string>
<string name="controls_favorite_removed" msgid="5276978408529217272">"Umeondoa vidhibiti vyote"</string>
<string name="controls_favorite_toast_no_changes" msgid="7094494210840877931">"Mabadiliko hayajahifadhiwa"</string>
<string name="controls_favorite_load_error" msgid="2533215155804455348">"Imeshindwa kupakia orodha ya vidhibiti vyote."</string>
@@ -1070,9 +1063,13 @@
<string name="controls_structure_tooltip" msgid="4355922222944447867">"Telezesha kidole ili uone zaidi"</string>
<string name="controls_seeding_in_progress" msgid="3033855341410264148">"Inapakia mapendekezo"</string>
<string name="controls_media_close_session" msgid="9023534788828414585">"Funga kipindi hiki cha maudhui"</string>
+ <string name="controls_media_resume" msgid="1933520684481586053">"Endelea"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"Haitumiki, angalia programu"</string>
<string name="controls_error_retryable" msgid="864025882878378470">"Hitilafu, inajaribu tena…"</string>
- <string name="controls_error_removed" msgid="6299213591234723805">"Kifaa kimeondolewa"</string>
+ <string name="controls_error_removed" msgid="6675638069846014366">"Hakipatikani"</string>
+ <string name="controls_error_removed_title" msgid="1207794911208047818">"Kidhibiti hakipatikani"</string>
+ <string name="controls_error_removed_message" msgid="2885911717034750542">"Imeshindwa kufikia <xliff:g id="DEVICE">%1$s</xliff:g>. Angalia programu ya <xliff:g id="APPLICATION">%2$s</xliff:g> ili uhakikishe kuwa bado kidhibiti kipo na kuwa mipangilio ya programu haijabadilika."</string>
+ <string name="controls_open_app" msgid="483650971094300141">"Fungua programu"</string>
<string name="controls_error_generic" msgid="352500456918362905">"Imeshindwa kupakia hali"</string>
<string name="controls_error_failed" msgid="960228639198558525">"Hitilafu, jaribu tena"</string>
<string name="controls_in_progress" msgid="4421080500238215939">"Inaendelea"</string>
diff --git a/packages/SystemUI/res/values-sw320dp/dimens.xml b/packages/SystemUI/res/values-sw320dp/dimens.xml
deleted file mode 100644
index c110113e91f4..000000000000
--- a/packages/SystemUI/res/values-sw320dp/dimens.xml
+++ /dev/null
@@ -1,36 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- ~ 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
- -->
-<resources>
- <!-- Global actions grid -->
- <dimen name="global_actions_grid_vertical_padding">3dp</dimen>
- <dimen name="global_actions_grid_horizontal_padding">3dp</dimen>
-
- <dimen name="global_actions_grid_item_side_margin">5dp</dimen>
- <dimen name="global_actions_grid_item_vertical_margin">4dp</dimen>
- <dimen name="global_actions_grid_item_width">64dp</dimen>
- <dimen name="global_actions_grid_item_height">64dp</dimen>
-
- <dimen name="global_actions_grid_item_icon_width">20dp</dimen>
- <dimen name="global_actions_grid_item_icon_height">20dp</dimen>
- <dimen name="global_actions_grid_item_icon_top_margin">12dp</dimen>
- <dimen name="global_actions_grid_item_icon_side_margin">22dp</dimen>
- <dimen name="global_actions_grid_item_icon_bottom_margin">4dp</dimen>
-
- <!-- Home Controls -->
- <dimen name="global_actions_side_margin">10dp</dimen>
-</resources>
-
diff --git a/packages/SystemUI/res/values-sw372dp/dimens.xml b/packages/SystemUI/res/values-sw372dp/dimens.xml
index e64662ec7bea..d3fff0c059f9 100644
--- a/packages/SystemUI/res/values-sw372dp/dimens.xml
+++ b/packages/SystemUI/res/values-sw372dp/dimens.xml
@@ -17,5 +17,4 @@
-->
<resources>
<dimen name="nav_content_padding">8dp</dimen>
- <dimen name="qs_header_tile_margin_horizontal">13dp</dimen>
</resources>
diff --git a/packages/SystemUI/res/values-ta/strings.xml b/packages/SystemUI/res/values-ta/strings.xml
index 32c6792d7354..4a32ecf8d229 100644
--- a/packages/SystemUI/res/values-ta/strings.xml
+++ b/packages/SystemUI/res/values-ta/strings.xml
@@ -77,9 +77,6 @@
<string name="compat_mode_on" msgid="4963711187149440884">"திரையை நிரப்ப அளவை மாற்று"</string>
<string name="compat_mode_off" msgid="7682459748279487945">"திரையை நிரப்ப இழு"</string>
<string name="global_action_screenshot" msgid="2760267567509131654">"ஸ்கிரீன்ஷாட்"</string>
- <string name="global_action_lock_message" product="default" msgid="4466026255205186456">"மேலும் விருப்பங்களுக்கு மொபைலை அன்லாக் செய்யவும்"</string>
- <string name="global_action_lock_message" product="tablet" msgid="7621167597240332986">"மேலும் விருப்பங்களுக்கு டேப்லெட்டை அன்லாக் செய்யவும்"</string>
- <string name="global_action_lock_message" product="device" msgid="538790401275363781">"மேலும் விருப்பங்களுக்குச் சாதனத்தை அன்லாக் செய்யவும்"</string>
<string name="remote_input_image_insertion_text" msgid="4850791636452521123">"படம் அனுப்பப்பட்டது"</string>
<string name="screenshot_saving_ticker" msgid="6519186952674544916">"ஸ்க்ரீன் ஷாட்டைச் சேமிக்கிறது…"</string>
<string name="screenshot_saving_title" msgid="2298349784913287333">"ஸ்க்ரீன் ஷாட்டைச் சேமிக்கிறது…"</string>
@@ -595,29 +592,21 @@
<string name="volume_odi_captions_hint_enable" msgid="2073091194012843195">"இயக்கும்"</string>
<string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"முடக்கும்"</string>
<string name="accessibility_output_chooser" msgid="7807898688967194183">"வெளியீட்டுச் சாதனத்தை மாற்றுதல்"</string>
- <!-- no translation found for screen_pinning_title (9058007390337841305) -->
- <skip />
+ <string name="screen_pinning_title" msgid="9058007390337841305">"ஆப்ஸ் பின் செய்யப்பட்டது"</string>
<string name="screen_pinning_description" msgid="8699395373875667743">"பொருத்தியதை அகற்றும் வரை இதைக் காட்சியில் வைக்கும். அகற்ற, முந்தையது மற்றும் மேலோட்டப் பார்வையைத் தொட்டுப் பிடிக்கவும்."</string>
<string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"இதற்கான பின்னை அகற்றும் வரை, இந்தப் பயன்முறை செயல்பாட்டிலேயே இருக்கும். அகற்றுவதற்கு, முந்தையது மற்றும் முகப்புப் பொத்தான்களைத் தொட்டுப் பிடிக்கவும்."</string>
<string name="screen_pinning_description_gestural" msgid="7246323931831232068">"பின் செய்திருப்பதை அகற்றும் வரை இதைச் செயல்பாட்டில் வைத்திருக்கும். அதை அகற்றுவதற்கு மேல்நோக்கி ஸ்வைப் செய்து பிடித்திருக்கவும்."</string>
<string name="screen_pinning_description_accessible" msgid="7386449191953535332">"பொருத்தியதை அகற்றும் வரை இதைக் காட்சியில் வைக்கும். அகற்ற, மேலோட்டப் பார்வையைத் தொட்டுப் பிடிக்கவும்."</string>
<string name="screen_pinning_description_recents_invisible_accessible" msgid="2857071808674481986">"இதற்கான பின்னை அகற்றும் வரை, இந்தப் பயன்முறை செயல்பாட்டிலேயே இருக்கும். அகற்றுவதற்கு, முகப்புப் பொத்தானைத் தொட்டுப் பிடிக்கவும்."</string>
- <!-- no translation found for screen_pinning_exposes_personal_data (8189852022981524789) -->
- <skip />
- <!-- no translation found for screen_pinning_can_open_other_apps (7529756813231421455) -->
- <skip />
- <!-- no translation found for screen_pinning_toast (8177286912533744328) -->
- <skip />
- <!-- no translation found for screen_pinning_toast_recents_invisible (6850978077443052594) -->
- <skip />
- <!-- no translation found for screen_pinning_toast_gesture_nav (170699893395336705) -->
- <skip />
+ <string name="screen_pinning_exposes_personal_data" msgid="8189852022981524789">"தனிப்பட்ட தரவு அணுகப்படக்கூடும் (தொடர்புகள், மின்னஞ்சலின் உள்ளடக்கம் போன்றவை)."</string>
+ <string name="screen_pinning_can_open_other_apps" msgid="7529756813231421455">"பின் செய்யப்பட்டிருக்கும் ஆப்ஸ் பிற ஆப்ஸைத் திறக்கக்கூடும்."</string>
+ <string name="screen_pinning_toast" msgid="8177286912533744328">"இந்த ஆப்ஸைப் பின்னிலிருந்து அகற்ற, \'பின்செல்\' மற்றும் \'மேலோட்டப் பார்வை\' பட்டன்களைத் தொட்டுப் பிடித்திருக்கவும்"</string>
+ <string name="screen_pinning_toast_recents_invisible" msgid="6850978077443052594">"இந்த ஆப்ஸைப் பின்னிலிருந்து அகற்ற, \'பின்செல்\' மற்றும் \'முகப்பு\' பட்டன்களைத் தொட்டுப் பிடித்திருக்கவும்"</string>
+ <string name="screen_pinning_toast_gesture_nav" msgid="170699893395336705">"இந்த ஆப்ஸைப் பின்னிலிருந்து அகற்ற, மேல்நோக்கி ஸ்வைப் செய்தவாறு பிடித்திருக்கவும்"</string>
<string name="screen_pinning_positive" msgid="3285785989665266984">"புரிந்தது"</string>
<string name="screen_pinning_negative" msgid="6882816864569211666">"வேண்டாம்"</string>
- <!-- no translation found for screen_pinning_start (7483998671383371313) -->
- <skip />
- <!-- no translation found for screen_pinning_exit (4553787518387346893) -->
- <skip />
+ <string name="screen_pinning_start" msgid="7483998671383371313">"ஆப்ஸ் பின் செய்யப்பட்டது"</string>
+ <string name="screen_pinning_exit" msgid="4553787518387346893">"ஆப்ஸ் பின்னிலிருந்து அகற்றப்பட்டது"</string>
<string name="quick_settings_reset_confirmation_title" msgid="463533331480997595">"<xliff:g id="TILE_LABEL">%1$s</xliff:g>ஐ மறைக்கவா?"</string>
<string name="quick_settings_reset_confirmation_message" msgid="2320586180785674186">"அடுத்த முறை அமைப்புகளில் மீண்டும் இயக்கும்போது, இது மீண்டும் தோன்றும்."</string>
<string name="quick_settings_reset_confirmation_button" msgid="3341477479055016776">"மறை"</string>
@@ -730,7 +719,7 @@
<string name="notification_channel_summary_priority" msgid="7952654515769021553">"உரையாடல் பிரிவின் மேற்பகுதியில் மிதக்கும் குமிழாகத் தோன்றும். பூட்டுத் திரையின் மேல் சுயவிவரப் படத்தைக் காட்டும்"</string>
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"அமைப்புகள்"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"முன்னுரிமை"</string>
- <string name="no_shortcut" msgid="7176375126961212514">"உரையாடல் சார்ந்த குறிப்பிட்ட அமைப்புகளை <xliff:g id="APP_NAME">%1$s</xliff:g> ஆதரிக்காது"</string>
+ <string name="no_shortcut" msgid="8257177117568230126">"உரையாடல் அம்சங்களை <xliff:g id="APP_NAME">%1$s</xliff:g> ஆதரிக்காது"</string>
<string name="bubble_overflow_empty_title" msgid="3120029421991510842">"சமீபத்திய குமிழ்கள் இல்லை"</string>
<string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"சமீபத்திய குமிழ்களும் நிராகரிக்கப்பட்ட குமிழ்களும் இங்கே தோன்றும்"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"இந்த அறிவிப்புகளை மாற்ற இயலாது."</string>
@@ -1013,7 +1002,8 @@
<string name="bubble_accessibility_action_move_top_right" msgid="6916868852433483569">"மேலே வலப்புறமாக நகர்த்து"</string>
<string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"கீழே இடப்புறமாக நகர்த்து"</string>
<string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"கீழே வலதுபுறமாக நகர்த்து"</string>
- <string name="bubble_dismiss_text" msgid="7071770411580452911">"மூடுக"</string>
+ <!-- no translation found for bubble_dismiss_text (1314082410868930066) -->
+ <skip />
<string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"உரையாடலைக் குமிழாக்காதே"</string>
<string name="bubbles_user_education_title" msgid="5547017089271445797">"குமிழ்களைப் பயன்படுத்தி அரட்டையடியுங்கள்"</string>
<string name="bubbles_user_education_description" msgid="1160281719576715211">"புதிய உரையாடல்கள் மிதக்கும் ஐகான்களாகவோ குமிழ்களாகவோ தோன்றும். குமிழைத் திறக்க தட்டவும். நகர்த்த இழுக்கவும்."</string>
@@ -1024,11 +1014,14 @@
<string name="notification_content_system_nav_changed" msgid="5077913144844684544">"சிஸ்டம் நேவிகேஷன் மாற்றப்பட்டது. மாற்றங்களைச் செய்ய ‘அமைப்புகளுக்குச்’ செல்லவும்."</string>
<string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"சிஸ்டம் நேவிகேஷனை மாற்ற ’அமைப்புகளுக்குச்’ செல்லவும்"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"இயக்க நேரம்"</string>
+ <string name="priority_onboarding_title" msgid="2893070698479227616">"முன்னுரிமை அளிக்கப்பட்ட உரையாடலாக அமைக்கப்பட்டது"</string>
+ <string name="priority_onboarding_behavior" msgid="5342816047020432929">"முன்னுரிமை அளிக்கப்பட்ட உரையாடல்கள் இவ்வாறு இருக்கும்:"</string>
<string name="priority_onboarding_show_at_top_text" msgid="1678400241025513541">"உரையாடல் பிரிவின் மேல் காட்டும்"</string>
<string name="priority_onboarding_show_avatar_text" msgid="5756291381124091508">"பூட்டுத் திரையின் மேல் சுயவிவரப் படத்தைக் காட்டும்"</string>
<string name="priority_onboarding_appear_as_bubble_text" msgid="4227039772250263122">"ஆப்ஸின் மேல் மிதக்கும் குமிழாகத் தோன்றும்"</string>
<string name="priority_onboarding_ignores_dnd_text" msgid="2918952762719600529">"\'தொந்தரவு செய்ய வேண்டாம்\' அம்சத்தைக் குறுக்கிடும்"</string>
<string name="priority_onboarding_done_button_title" msgid="4569550984286506007">"சரி"</string>
+ <string name="priority_onboarding_settings_button_title" msgid="6663601574303585927">"அமைப்புகள்"</string>
<string name="magnification_overlay_title" msgid="6584179429612427958">"Magnification Overlay Window"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"பெரிதாக்கல் சாளரம்"</string>
<string name="magnification_controls_title" msgid="8421106606708891519">"பெரிதாக்கல் சாளரக் கட்டுப்பாடுகள்"</string>
@@ -1070,9 +1063,13 @@
<string name="controls_structure_tooltip" msgid="4355922222944447867">"மேலும் பார்க்க ஸ்வைப் செய்யவும்"</string>
<string name="controls_seeding_in_progress" msgid="3033855341410264148">"பரிந்துரைகளை ஏற்றுகிறது"</string>
<string name="controls_media_close_session" msgid="9023534788828414585">"இந்த மீடியா அமர்வை மூடுக"</string>
+ <string name="controls_media_resume" msgid="1933520684481586053">"தொடர்க"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"செயலில் இல்லை , சரிபார்க்கவும்"</string>
<string name="controls_error_retryable" msgid="864025882878378470">"பிழை, மீண்டும் முயல்கிறது…"</string>
- <string name="controls_error_removed" msgid="6299213591234723805">"சாதனம் அகற்றப்பட்டது"</string>
+ <string name="controls_error_removed" msgid="6675638069846014366">"இல்லை"</string>
+ <string name="controls_error_removed_title" msgid="1207794911208047818">"கட்டுப்பாடு இல்லை"</string>
+ <string name="controls_error_removed_message" msgid="2885911717034750542">"<xliff:g id="DEVICE">%1$s</xliff:g> சாதனத்தை அணுக இயலவில்லை. இப்போதும் கட்டுப்பாடு உள்ளது என்பதையும் ஆப்ஸ் அமைப்புகள் மாறவில்லை என்பதையும் உறுதிப்படுத்த <xliff:g id="APPLICATION">%2$s</xliff:g> ஆப்ஸைப் பார்க்கவும்."</string>
+ <string name="controls_open_app" msgid="483650971094300141">"ஆப்ஸைத் திற"</string>
<string name="controls_error_generic" msgid="352500456918362905">"நிலையைக் காட்ட முடியவில்லை"</string>
<string name="controls_error_failed" msgid="960228639198558525">"பிழை, மீண்டும் முயலவும்"</string>
<string name="controls_in_progress" msgid="4421080500238215939">"செயல்பாட்டிலுள்ளது"</string>
diff --git a/packages/SystemUI/res/values-te/strings.xml b/packages/SystemUI/res/values-te/strings.xml
index 75f308affe0a..73754a20cccc 100644
--- a/packages/SystemUI/res/values-te/strings.xml
+++ b/packages/SystemUI/res/values-te/strings.xml
@@ -77,9 +77,6 @@
<string name="compat_mode_on" msgid="4963711187149440884">"స్క్రీన్‌కు నింపేలా జూమ్ చేయండి"</string>
<string name="compat_mode_off" msgid="7682459748279487945">"స్క్రీన్‌కు నింపేలా విస్తరించండి"</string>
<string name="global_action_screenshot" msgid="2760267567509131654">"స్క్రీన్‌షాట్"</string>
- <string name="global_action_lock_message" product="default" msgid="4466026255205186456">"మరిన్ని ఆప్షన్‌ల కోసం మీ ఫోన్‌ను అన్‌లాక్ చేయండి"</string>
- <string name="global_action_lock_message" product="tablet" msgid="7621167597240332986">"మరిన్ని ఆప్షన్‌ల కోసం మీ టాబ్లెట్‌ను అన్‌లాక్ చేయండి"</string>
- <string name="global_action_lock_message" product="device" msgid="538790401275363781">"మరిన్ని ఆప్షన్‌ల కోసం మీ పరికరాన్ని అన్‌లాక్ చేయండి"</string>
<string name="remote_input_image_insertion_text" msgid="4850791636452521123">"ఇమేజ్‌ను పంపారు"</string>
<string name="screenshot_saving_ticker" msgid="6519186952674544916">"స్క్రీన్‌షాట్‌ను సేవ్ చేస్తోంది…"</string>
<string name="screenshot_saving_title" msgid="2298349784913287333">"స్క్రీన్‌షాట్‌ను సేవ్ చేస్తోంది…"</string>
@@ -595,29 +592,21 @@
<string name="volume_odi_captions_hint_enable" msgid="2073091194012843195">"ప్రారంభించు"</string>
<string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"నిలిపివేయండి"</string>
<string name="accessibility_output_chooser" msgid="7807898688967194183">"పరికరం అవుట్‌పుట్‌ని మార్చండి"</string>
- <!-- no translation found for screen_pinning_title (9058007390337841305) -->
- <skip />
+ <string name="screen_pinning_title" msgid="9058007390337841305">"యాప్ పిన్ చేయబడి ఉంది"</string>
<string name="screen_pinning_description" msgid="8699395373875667743">"దీని వలన మీరు అన్‌పిన్ చేసే వరకు ఇది వీక్షణలో ఉంచబడుతుంది. అన్‌పిన్ చేయడానికి వెనుకకు మరియు స్థూలదృష్టి తాకి &amp; అలాగే పట్టుకోండి."</string>
<string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"దీని వలన మీరు అన్‌పిన్ చేసే వరకు ఇది వీక్షణలో ఉంచబడుతుంది. అన్‌పిన్ చేయడానికి వెనుకకు మరియు హోమ్‌ని తాకి &amp; అలాగే పట్టుకోండి."</string>
<string name="screen_pinning_description_gestural" msgid="7246323931831232068">"మీరు అన్‌పిన్ చేసే వరకు ఇది వీక్షణలో ఉంచబడుతుంది. అన్‌పిన్ చేయడానికి, పైకి స్వైప్ చేసి &amp; పట్టుకోండి."</string>
<string name="screen_pinning_description_accessible" msgid="7386449191953535332">"దీని వలన మీరు అన్‌పిన్ చేసే వరకు ఇది వీక్షణలో ఉంచబడుతుంది. అన్‌పిన్ చేయడానికి స్థూలదృష్టిని తాకి &amp; అలాగే పట్టుకోండి."</string>
<string name="screen_pinning_description_recents_invisible_accessible" msgid="2857071808674481986">"దీని వలన మీరు అన్‌పిన్ చేసే వరకు ఇది వీక్షణలో ఉంచబడుతుంది. అన్‌పిన్ చేయడానికి హోమ్‌ని తాకి &amp; అలాగే పట్టుకోండి."</string>
- <!-- no translation found for screen_pinning_exposes_personal_data (8189852022981524789) -->
- <skip />
- <!-- no translation found for screen_pinning_can_open_other_apps (7529756813231421455) -->
- <skip />
- <!-- no translation found for screen_pinning_toast (8177286912533744328) -->
- <skip />
- <!-- no translation found for screen_pinning_toast_recents_invisible (6850978077443052594) -->
- <skip />
- <!-- no translation found for screen_pinning_toast_gesture_nav (170699893395336705) -->
- <skip />
+ <string name="screen_pinning_exposes_personal_data" msgid="8189852022981524789">"వ్యక్తిగత డేటా (కాంటాక్ట్‌లు, ఇంకా ఇమెయిల్ కంటెంట్ లాంటివి) యాక్సెస్ చేయబడవచ్చు."</string>
+ <string name="screen_pinning_can_open_other_apps" msgid="7529756813231421455">"పిన్ చేయబడిన యాప్ ఇతర యాప్‌లను తెరవవచ్చు."</string>
+ <string name="screen_pinning_toast" msgid="8177286912533744328">"ఈ యాప్‌ను అన్‌పిన్ చేయడానికి, \'వెనుకకు\', \'ఓవర్‌వ్యూ\' బటన్‌లను తాకి &amp; అలాగే పట్టుకోండి"</string>
+ <string name="screen_pinning_toast_recents_invisible" msgid="6850978077443052594">"ఈ యాప్‌ను అన్‌పిన్ చేయడానికి, వెనుకకు, హోమ్ బటన్‌లను తాకి &amp; అలాగే పట్టుకోండి"</string>
+ <string name="screen_pinning_toast_gesture_nav" msgid="170699893395336705">"ఈ యాప్‌ను అన్‌పిన్ చేయడానికి, పైకి స్వైప్ చేసి &amp; అలాగే పట్టుకోండి"</string>
<string name="screen_pinning_positive" msgid="3285785989665266984">"అర్థమైంది"</string>
<string name="screen_pinning_negative" msgid="6882816864569211666">"వద్దు, ధన్యవాదాలు"</string>
- <!-- no translation found for screen_pinning_start (7483998671383371313) -->
- <skip />
- <!-- no translation found for screen_pinning_exit (4553787518387346893) -->
- <skip />
+ <string name="screen_pinning_start" msgid="7483998671383371313">"యాప్ పిన్ చేయబడింది"</string>
+ <string name="screen_pinning_exit" msgid="4553787518387346893">"యాప్ అన్‌పిన్ చేయబడింది"</string>
<string name="quick_settings_reset_confirmation_title" msgid="463533331480997595">"<xliff:g id="TILE_LABEL">%1$s</xliff:g>ని దాచాలా?"</string>
<string name="quick_settings_reset_confirmation_message" msgid="2320586180785674186">"మీరు సెట్టింగ్‌ల్లో దీన్ని ఆన్ చేసిన తదుపరిసారి ఇది కనిపిస్తుంది."</string>
<string name="quick_settings_reset_confirmation_button" msgid="3341477479055016776">"దాచు"</string>
@@ -730,7 +719,7 @@
<string name="notification_channel_summary_priority" msgid="7952654515769021553">"సంభాషణ విభాగం ఎగువన ఉంటుంది, తేలుతున్న బబుల్‌లాగా కనిపిస్తుంది, లాక్ స్క్రీన్‌పై ప్రొఫైల్ ఫోటోను ప్రదర్శిస్తుంది"</string>
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"సెట్టింగ్‌లు"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"ప్రాధాన్యత"</string>
- <string name="no_shortcut" msgid="7176375126961212514">"\'సంభాషణ నిర్దిష్ట సెట్టింగ్\'‌లకు <xliff:g id="APP_NAME">%1$s</xliff:g> సపోర్ట్ చేయదు"</string>
+ <string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> సంభాషణ ఫీచర్‌లను సపోర్ట్ చేయదు"</string>
<string name="bubble_overflow_empty_title" msgid="3120029421991510842">"ఇటీవలి బబుల్స్ ఏవీ లేవు"</string>
<string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"ఇటీవలి బబుల్స్, తీసివేసిన బబుల్స్ ఇక్కడ కనిపిస్తాయి"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"ఈ నోటిఫికేషన్‌లను సవరించడం వీలుపడదు."</string>
@@ -1013,7 +1002,8 @@
<string name="bubble_accessibility_action_move_top_right" msgid="6916868852433483569">"ఎగువ కుడివైపునకు జరుపు"</string>
<string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"దిగువ ఎడమవైపునకు తరలించు"</string>
<string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"దిగవు కుడివైపునకు జరుపు"</string>
- <string name="bubble_dismiss_text" msgid="7071770411580452911">"విస్మరించు"</string>
+ <!-- no translation found for bubble_dismiss_text (1314082410868930066) -->
+ <skip />
<string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"సంభాషణను బబుల్ చేయవద్దు"</string>
<string name="bubbles_user_education_title" msgid="5547017089271445797">"బబుల్స్‌ను ఉపయోగించి చాట్ చేయండి"</string>
<string name="bubbles_user_education_description" msgid="1160281719576715211">"కొత్త సంభాషణలు తేలియాడే చిహ్నాలుగా లేదా బబుల్స్ లాగా కనిపిస్తాయి. బబుల్‌ని తెరవడానికి నొక్కండి. తరలించడానికి లాగండి."</string>
@@ -1024,11 +1014,14 @@
<string name="notification_content_system_nav_changed" msgid="5077913144844684544">"సిస్టమ్ నావిగేషన్ అప్‌డేట్ చేయబడింది. మార్పులు చేయడానికి, సెట్టింగ్‌లకు వెళ్లండి."</string>
<string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"సిస్టమ్ నావిగేషన్‌ను అప్‌డేట్ చేయడానికి సెట్టింగ్‌లకు వెళ్లండి"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"స్టాండ్‌బై"</string>
+ <string name="priority_onboarding_title" msgid="2893070698479227616">"సంభాషణ ప్రధానమైనదిగా సెట్ చేయబడింది"</string>
+ <string name="priority_onboarding_behavior" msgid="5342816047020432929">"ప్రధాన సంభాషణలు ఇక్కడ కనిపిస్తాయి:"</string>
<string name="priority_onboarding_show_at_top_text" msgid="1678400241025513541">"సంభాషణ విభాగంలో ఎగువున చూపబడుతుంది"</string>
<string name="priority_onboarding_show_avatar_text" msgid="5756291381124091508">"లాక్ స్క్రీన్ మీద ప్రొఫైల్ ఫోటో చూపబడుతుంది"</string>
<string name="priority_onboarding_appear_as_bubble_text" msgid="4227039772250263122">"యాప్‌ల పైన తేలియాడే బబుల్‌లాగా కనిపిస్తాయి"</string>
<string name="priority_onboarding_ignores_dnd_text" msgid="2918952762719600529">"\'అంతరాయం కలిగించవద్దు\' మోడ్‌కు అంతరాయం"</string>
<string name="priority_onboarding_done_button_title" msgid="4569550984286506007">"అర్థమైంది"</string>
+ <string name="priority_onboarding_settings_button_title" msgid="6663601574303585927">"సెట్టింగ్‌లు"</string>
<string name="magnification_overlay_title" msgid="6584179429612427958">"మాగ్నిఫికేషన్ ఓవర్‌లే విండో"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"మాగ్నిఫికేషన్ విండో"</string>
<string name="magnification_controls_title" msgid="8421106606708891519">"మాగ్నిఫికేషన్ నియంత్రణల విండో"</string>
@@ -1050,7 +1043,7 @@
<string name="accessibility_control_move" msgid="8980344493796647792">"<xliff:g id="NUMBER">%d</xliff:g> పొజిషన్‌కు తరలించండి"</string>
<string name="controls_favorite_default_title" msgid="967742178688938137">"నియంత్రణలు"</string>
<string name="controls_favorite_subtitle" msgid="6604402232298443956">"పవర్ మెనూ నుండి యాక్సెస్ చేయడానికి నియంత్రణలను ఎంచుకోండి"</string>
- <string name="controls_favorite_rearrange" msgid="5616952398043063519">"నియంత్రణల క్రమం మార్చడానికి పట్టుకుని&amp;amp, లాగండి"</string>
+ <string name="controls_favorite_rearrange" msgid="5616952398043063519">"నియంత్రణల క్రమం మార్చడానికి దేనినైనా పట్టుకుని, లాగి వదిలేయండి"</string>
<string name="controls_favorite_removed" msgid="5276978408529217272">"అన్ని నియంత్రణలు తీసివేయబడ్డాయి"</string>
<string name="controls_favorite_toast_no_changes" msgid="7094494210840877931">"మార్పులు సేవ్ చేయబడలేదు"</string>
<string name="controls_favorite_load_error" msgid="2533215155804455348">"అన్ని నియంత్రణలు గల జాబితాను లోడ్ చేయలేకపోయాము."</string>
@@ -1070,9 +1063,13 @@
<string name="controls_structure_tooltip" msgid="4355922222944447867">"మరిన్నింటిని చూడటం కోసం స్వైప్ చేయండి"</string>
<string name="controls_seeding_in_progress" msgid="3033855341410264148">"సిఫార్సులు లోడ్ అవుతున్నాయి"</string>
<string name="controls_media_close_session" msgid="9023534788828414585">"ఈ మీడియా సెషన్‌ని మూసివేయండి"</string>
+ <string name="controls_media_resume" msgid="1933520684481586053">"కొనసాగించండి"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"ఇన్‌యాక్టివ్, యాప్ చెక్ చేయండి"</string>
<string name="controls_error_retryable" msgid="864025882878378470">"లోపం, మళ్లీ ప్రయత్నిస్తోంది..."</string>
- <string name="controls_error_removed" msgid="6299213591234723805">"పరికరం తీసివేయబడింది"</string>
+ <string name="controls_error_removed" msgid="6675638069846014366">"కనుగొనబడలేదు"</string>
+ <string name="controls_error_removed_title" msgid="1207794911208047818">"కంట్రోల్ అందుబాటులో లేదు"</string>
+ <string name="controls_error_removed_message" msgid="2885911717034750542">"<xliff:g id="DEVICE">%1$s</xliff:g>ను యాక్సెస్ చేయడం సాధ్యపడలేదు. <xliff:g id="APPLICATION">%2$s</xliff:g> యాప్‌ను తనిఖీ చేసి, కంట్రోల్ ఇప్పటికీ అందుబాటులో ఉందని, యాప్ సెట్టింగ్‌లు మారలేదని నిర్ధారించుకోండి."</string>
+ <string name="controls_open_app" msgid="483650971094300141">"యాప్‌ను తెరువు"</string>
<string name="controls_error_generic" msgid="352500456918362905">"స్థితిని లోడ్ చేయడం సాధ్యపడదు"</string>
<string name="controls_error_failed" msgid="960228639198558525">"ఎర్రర్, మళ్లీ ప్రయత్నించండి"</string>
<string name="controls_in_progress" msgid="4421080500238215939">"పురోగతిలో ఉంది"</string>
diff --git a/packages/SystemUI/res/values-th/strings.xml b/packages/SystemUI/res/values-th/strings.xml
index 37ac4dcd54ed..d61533d0be01 100644
--- a/packages/SystemUI/res/values-th/strings.xml
+++ b/packages/SystemUI/res/values-th/strings.xml
@@ -77,9 +77,6 @@
<string name="compat_mode_on" msgid="4963711187149440884">"ขยายจนเต็มหน้าจอ"</string>
<string name="compat_mode_off" msgid="7682459748279487945">"ยืดจนเต็มหน้าจอ"</string>
<string name="global_action_screenshot" msgid="2760267567509131654">"ภาพหน้าจอ"</string>
- <string name="global_action_lock_message" product="default" msgid="4466026255205186456">"ปลดล็อกโทรศัพท์เพื่อดูตัวเลือกเพิ่มเติม"</string>
- <string name="global_action_lock_message" product="tablet" msgid="7621167597240332986">"ปลดล็อกแท็บเล็ตเพื่อดูตัวเลือกเพิ่มเติม"</string>
- <string name="global_action_lock_message" product="device" msgid="538790401275363781">"ปลดล็อกอุปกรณ์เพื่อดูตัวเลือกเพิ่มเติม"</string>
<string name="remote_input_image_insertion_text" msgid="4850791636452521123">"ส่งรูปภาพ"</string>
<string name="screenshot_saving_ticker" msgid="6519186952674544916">"กำลังบันทึกภาพหน้าจอ..."</string>
<string name="screenshot_saving_title" msgid="2298349784913287333">"กำลังบันทึกภาพหน้าจอ..."</string>
@@ -595,29 +592,21 @@
<string name="volume_odi_captions_hint_enable" msgid="2073091194012843195">"เปิดใช้"</string>
<string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"ปิดใช้"</string>
<string name="accessibility_output_chooser" msgid="7807898688967194183">"เปลี่ยนอุปกรณ์เอาต์พุต"</string>
- <!-- no translation found for screen_pinning_title (9058007390337841305) -->
- <skip />
+ <string name="screen_pinning_title" msgid="9058007390337841305">"ตรึงแอปอยู่"</string>
<string name="screen_pinning_description" msgid="8699395373875667743">"การดำเนินการนี้จะแสดงหน้าจอนี้ไว้เสมอจนกว่าคุณจะเลิกตรึง แตะ \"กลับ\" และ \"ภาพรวม\" ค้างไว้เพื่อเลิกตรึง"</string>
<string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"การดำเนินการนี้จะแสดงหน้าจอนี้ไว้เสมอจนกว่าคุณจะเลิกตรึง แตะ \"กลับ\" และ \"หน้าแรก\" ค้างไว้เพื่อเลิกตรึง"</string>
<string name="screen_pinning_description_gestural" msgid="7246323931831232068">"วิธีนี้ช่วยให้เห็นหน้าจอตลอดจนกว่าจะเลิกตรึง เลื่อนขึ้นค้างไว้เพื่อเลิกตรึง"</string>
<string name="screen_pinning_description_accessible" msgid="7386449191953535332">"การดำเนินการนี้จะแสดงหน้าจอนี้ไว้เสมอจนกว่าคุณจะเลิกตรึง แตะ \"ภาพรวม\" ค้างไว้เพื่อเลิกตรึง"</string>
<string name="screen_pinning_description_recents_invisible_accessible" msgid="2857071808674481986">"การดำเนินการนี้จะแสดงหน้าจอนี้ไว้เสมอจนกว่าคุณจะเลิกตรึง แตะ \"หน้าแรก\" ค้างไว้เพื่อเลิกตรึง"</string>
- <!-- no translation found for screen_pinning_exposes_personal_data (8189852022981524789) -->
- <skip />
- <!-- no translation found for screen_pinning_can_open_other_apps (7529756813231421455) -->
- <skip />
- <!-- no translation found for screen_pinning_toast (8177286912533744328) -->
- <skip />
- <!-- no translation found for screen_pinning_toast_recents_invisible (6850978077443052594) -->
- <skip />
- <!-- no translation found for screen_pinning_toast_gesture_nav (170699893395336705) -->
- <skip />
+ <string name="screen_pinning_exposes_personal_data" msgid="8189852022981524789">"อาจมีการเข้าถึงข้อมูลส่วนตัว (เช่น รายชื่อติดต่อและเนื้อหาในอีเมล)"</string>
+ <string name="screen_pinning_can_open_other_apps" msgid="7529756813231421455">"แอปที่ตรึงไว้อาจเปิดแอปอื่นๆ"</string>
+ <string name="screen_pinning_toast" msgid="8177286912533744328">"หากต้องการเลิกตรึงแอปนี้ ให้แตะปุ่ม \"กลับ\" และ \"ภาพรวม\" ค้างไว้"</string>
+ <string name="screen_pinning_toast_recents_invisible" msgid="6850978077443052594">"หากต้องการเลิกตรึงแอปนี้ ให้แตะปุ่ม \"กลับ\" และ \"หน้าแรก\" ค้างไว้"</string>
+ <string name="screen_pinning_toast_gesture_nav" msgid="170699893395336705">"หากต้องการเลิกตรึงแอปนี้ ให้เลื่อนขึ้นค้างไว้"</string>
<string name="screen_pinning_positive" msgid="3285785989665266984">"รับทราบ"</string>
<string name="screen_pinning_negative" msgid="6882816864569211666">"ไม่เป็นไร ขอบคุณ"</string>
- <!-- no translation found for screen_pinning_start (7483998671383371313) -->
- <skip />
- <!-- no translation found for screen_pinning_exit (4553787518387346893) -->
- <skip />
+ <string name="screen_pinning_start" msgid="7483998671383371313">"ตรึงแอปแล้ว"</string>
+ <string name="screen_pinning_exit" msgid="4553787518387346893">"เลิกตรึงแอปแล้ว"</string>
<string name="quick_settings_reset_confirmation_title" msgid="463533331480997595">"ซ่อน <xliff:g id="TILE_LABEL">%1$s</xliff:g> ไหม"</string>
<string name="quick_settings_reset_confirmation_message" msgid="2320586180785674186">"จะปรากฏอีกครั้งเมื่อคุณเปิดใช้ในการตั้งค่าครั้งถัดไป"</string>
<string name="quick_settings_reset_confirmation_button" msgid="3341477479055016776">"ซ่อน"</string>
@@ -730,7 +719,7 @@
<string name="notification_channel_summary_priority" msgid="7952654515769021553">"แสดงที่ด้านบนของส่วนการสนทนา ปรากฏเป็นบับเบิลแบบลอย แสดงรูปโปรไฟล์บนหน้าจอล็อก"</string>
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"การตั้งค่า"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"ลำดับความสำคัญ"</string>
- <string name="no_shortcut" msgid="7176375126961212514">"<xliff:g id="APP_NAME">%1$s</xliff:g> ไม่รองรับการตั้งค่าเฉพาะสำหรับการสนทนา"</string>
+ <string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> ไม่รองรับฟีเจอร์การสนทนา"</string>
<string name="bubble_overflow_empty_title" msgid="3120029421991510842">"ไม่มีบับเบิลเมื่อเร็วๆ นี้"</string>
<string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"บับเบิลที่แสดงและที่ปิดไปเมื่อเร็วๆ นี้จะปรากฏที่นี่"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"แก้ไขการแจ้งเตือนเหล่านี้ไม่ได้"</string>
@@ -1013,7 +1002,8 @@
<string name="bubble_accessibility_action_move_top_right" msgid="6916868852433483569">"ย้ายไปด้านขวาบน"</string>
<string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"ย้ายไปด้านซ้ายล่าง"</string>
<string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"ย้ายไปด้านขาวล่าง"</string>
- <string name="bubble_dismiss_text" msgid="7071770411580452911">"ปิด"</string>
+ <!-- no translation found for bubble_dismiss_text (1314082410868930066) -->
+ <skip />
<string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"ไม่ต้องแสดงการสนทนาเป็นบับเบิล"</string>
<string name="bubbles_user_education_title" msgid="5547017089271445797">"แชทโดยใช้บับเบิล"</string>
<string name="bubbles_user_education_description" msgid="1160281719576715211">"การสนทนาใหม่ๆ จะปรากฏเป็นไอคอนแบบลอยหรือบับเบิล แตะเพื่อเปิดบับเบิล ลากเพื่อย้ายที่"</string>
@@ -1024,11 +1014,14 @@
<string name="notification_content_system_nav_changed" msgid="5077913144844684544">"อัปเดตการไปยังส่วนต่างๆ ของระบบแล้ว หากต้องการเปลี่ยนแปลง ให้ไปที่การตั้งค่า"</string>
<string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"ไปที่การตั้งค่าเพื่ออัปเดตการไปยังส่วนต่างๆ ของระบบ"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"สแตนด์บาย"</string>
+ <string name="priority_onboarding_title" msgid="2893070698479227616">"ตั้งค่าเป็นการสนทนาสำคัญแล้ว"</string>
+ <string name="priority_onboarding_behavior" msgid="5342816047020432929">"การสนทนาสำคัญจะ:"</string>
<string name="priority_onboarding_show_at_top_text" msgid="1678400241025513541">"แสดงที่ด้านบนของส่วนการสนทนา"</string>
<string name="priority_onboarding_show_avatar_text" msgid="5756291381124091508">"แสดงรูปโปรไฟล์บนหน้าจอล็อก"</string>
<string name="priority_onboarding_appear_as_bubble_text" msgid="4227039772250263122">"แสดงเป็นบับเบิลที่ลอยอยู่เหนือแอป"</string>
<string name="priority_onboarding_ignores_dnd_text" msgid="2918952762719600529">"แสดงในโหมดห้ามรบกวน"</string>
<string name="priority_onboarding_done_button_title" msgid="4569550984286506007">"รับทราบ"</string>
+ <string name="priority_onboarding_settings_button_title" msgid="6663601574303585927">"การตั้งค่า"</string>
<string name="magnification_overlay_title" msgid="6584179429612427958">"หน้าต่างการขยายที่วางซ้อน"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"หน้าต่างการขยาย"</string>
<string name="magnification_controls_title" msgid="8421106606708891519">"การควบคุมหน้าต่างการขยาย"</string>
@@ -1050,7 +1043,7 @@
<string name="accessibility_control_move" msgid="8980344493796647792">"ย้ายไปที่ตำแหน่ง <xliff:g id="NUMBER">%d</xliff:g>"</string>
<string name="controls_favorite_default_title" msgid="967742178688938137">"การควบคุม"</string>
<string name="controls_favorite_subtitle" msgid="6604402232298443956">"เลือกตัวควบคุมที่ต้องการให้เข้าถึงได้จากเมนูเปิด/ปิด"</string>
- <string name="controls_favorite_rearrange" msgid="5616952398043063519">"กดตัวควบคุมค้างไว้แล้วลากเพื่อจัดเรียงใหม่"</string>
+ <string name="controls_favorite_rearrange" msgid="5616952398043063519">"แตะตัวควบคุมค้างไว้แล้วลากเพื่อจัดเรียงใหม่"</string>
<string name="controls_favorite_removed" msgid="5276978408529217272">"นำตัวควบคุมทั้งหมดออกแล้ว"</string>
<string name="controls_favorite_toast_no_changes" msgid="7094494210840877931">"ยังไม่ได้บันทึกการเปลี่ยนแปลง"</string>
<string name="controls_favorite_load_error" msgid="2533215155804455348">"โหลดรายการตัวควบคุมทั้งหมดไม่ได้"</string>
@@ -1070,9 +1063,13 @@
<string name="controls_structure_tooltip" msgid="4355922222944447867">"เลื่อนเพื่อดูเพิ่มเติม"</string>
<string name="controls_seeding_in_progress" msgid="3033855341410264148">"กำลังโหลดคำแนะนำ"</string>
<string name="controls_media_close_session" msgid="9023534788828414585">"ปิดเซสชันสื่อนี้"</string>
+ <string name="controls_media_resume" msgid="1933520684481586053">"เล่นต่อ"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"ไม่มีการใช้งาน โปรดตรวจสอบแอป"</string>
<string name="controls_error_retryable" msgid="864025882878378470">"มีข้อผิดพลาด กำลังลองอีกครั้ง…"</string>
- <string name="controls_error_removed" msgid="6299213591234723805">"นำอุปกรณ์ออกแล้ว"</string>
+ <string name="controls_error_removed" msgid="6675638069846014366">"ไม่พบ"</string>
+ <string name="controls_error_removed_title" msgid="1207794911208047818">"ใช้การควบคุมไม่ได้"</string>
+ <string name="controls_error_removed_message" msgid="2885911717034750542">"เข้าถึง <xliff:g id="DEVICE">%1$s</xliff:g> ไม่ได้ ตรวจสอบแอป <xliff:g id="APPLICATION">%2$s</xliff:g> ให้แน่ใจว่ายังใช้การควบคุมได้และการตั้งค่าของแอปไม่เปลี่ยนแปลง"</string>
+ <string name="controls_open_app" msgid="483650971094300141">"เปิดแอป"</string>
<string name="controls_error_generic" msgid="352500456918362905">"โหลดสถานะไม่ได้"</string>
<string name="controls_error_failed" msgid="960228639198558525">"พบข้อผิดพลาด โปรดลองอีกครั้ง"</string>
<string name="controls_in_progress" msgid="4421080500238215939">"กำลังดำเนินการ"</string>
diff --git a/packages/SystemUI/res/values-tl/strings.xml b/packages/SystemUI/res/values-tl/strings.xml
index 09199dda93ae..041214f2111e 100644
--- a/packages/SystemUI/res/values-tl/strings.xml
+++ b/packages/SystemUI/res/values-tl/strings.xml
@@ -77,9 +77,6 @@
<string name="compat_mode_on" msgid="4963711187149440884">"I-zoom upang punan screen"</string>
<string name="compat_mode_off" msgid="7682459748279487945">"I-stretch upang mapuno screen"</string>
<string name="global_action_screenshot" msgid="2760267567509131654">"Screenshot"</string>
- <string name="global_action_lock_message" product="default" msgid="4466026255205186456">"I-unlock ang iyong telepono para sa higit pang opsyon"</string>
- <string name="global_action_lock_message" product="tablet" msgid="7621167597240332986">"I-unlock ang iyong tablet para sa higit pang opsyon"</string>
- <string name="global_action_lock_message" product="device" msgid="538790401275363781">"I-unlock ang iyong device para sa higit pang opsyon"</string>
<string name="remote_input_image_insertion_text" msgid="4850791636452521123">"nagpadala ng larawan"</string>
<string name="screenshot_saving_ticker" msgid="6519186952674544916">"Sine-save ang screenshot…"</string>
<string name="screenshot_saving_title" msgid="2298349784913287333">"Sine-save ang screenshot…"</string>
@@ -595,29 +592,21 @@
<string name="volume_odi_captions_hint_enable" msgid="2073091194012843195">"i-enable"</string>
<string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"i-disable"</string>
<string name="accessibility_output_chooser" msgid="7807898688967194183">"Lumipat ng output device"</string>
- <!-- no translation found for screen_pinning_title (9058007390337841305) -->
- <skip />
+ <string name="screen_pinning_title" msgid="9058007390337841305">"Naka-pin ang app"</string>
<string name="screen_pinning_description" msgid="8699395373875667743">"Pinapanatili nitong nakikita ito hanggang sa mag-unpin ka. Pindutin nang matagal ang Bumalik at Overview upang mag-unpin."</string>
<string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"Pinapanatili nitong nakikita ito hanggang sa mag-unpin ka. Pindutin nang matagal ang Bumalik at Home upang mag-unpin."</string>
<string name="screen_pinning_description_gestural" msgid="7246323931831232068">"Pinapanatili nitong nakikita ito hanggang sa mag-unpin ka. Mag-swipe pataas at i-hold para i-unpin."</string>
<string name="screen_pinning_description_accessible" msgid="7386449191953535332">"Pinapanatili nitong nakikita ito hanggang sa mag-unpin ka. Pindutin nang matagal ang Overview upang mag-unpin."</string>
<string name="screen_pinning_description_recents_invisible_accessible" msgid="2857071808674481986">"Pinapanatili nitong nakikita ito hanggang sa mag-unpin ka. Pindutin nang matagal ang Home upang mag-unpin."</string>
- <!-- no translation found for screen_pinning_exposes_personal_data (8189852022981524789) -->
- <skip />
- <!-- no translation found for screen_pinning_can_open_other_apps (7529756813231421455) -->
- <skip />
- <!-- no translation found for screen_pinning_toast (8177286912533744328) -->
- <skip />
- <!-- no translation found for screen_pinning_toast_recents_invisible (6850978077443052594) -->
- <skip />
- <!-- no translation found for screen_pinning_toast_gesture_nav (170699893395336705) -->
- <skip />
+ <string name="screen_pinning_exposes_personal_data" msgid="8189852022981524789">"Puwedeng ma-access ang personal na data (tulad ng mga contact at content ng email)."</string>
+ <string name="screen_pinning_can_open_other_apps" msgid="7529756813231421455">"Puwedeng magbukas ng ibang app ang naka-pin na app."</string>
+ <string name="screen_pinning_toast" msgid="8177286912533744328">"Para i-unpin ang app na ito, pindutin nang matagal ang mga button na Bumalik at Overview"</string>
+ <string name="screen_pinning_toast_recents_invisible" msgid="6850978077443052594">"Para i-unpin ang app na ito, pindutin nang matagal ang mga button na Bumalik at Home"</string>
+ <string name="screen_pinning_toast_gesture_nav" msgid="170699893395336705">"Para i-unpin ang app na ito, mag-swipe pataas at pumindot nang matagal"</string>
<string name="screen_pinning_positive" msgid="3285785989665266984">"Nakuha ko"</string>
<string name="screen_pinning_negative" msgid="6882816864569211666">"Hindi, salamat na lang"</string>
- <!-- no translation found for screen_pinning_start (7483998671383371313) -->
- <skip />
- <!-- no translation found for screen_pinning_exit (4553787518387346893) -->
- <skip />
+ <string name="screen_pinning_start" msgid="7483998671383371313">"Na-pin ang app"</string>
+ <string name="screen_pinning_exit" msgid="4553787518387346893">"Na-unpin ang app"</string>
<string name="quick_settings_reset_confirmation_title" msgid="463533331480997595">"Itago ang <xliff:g id="TILE_LABEL">%1$s</xliff:g>?"</string>
<string name="quick_settings_reset_confirmation_message" msgid="2320586180785674186">"Lalabas itong muli sa susunod na pagkakataon na i-on mo ito sa mga setting."</string>
<string name="quick_settings_reset_confirmation_button" msgid="3341477479055016776">"Itago"</string>
@@ -730,7 +719,7 @@
<string name="notification_channel_summary_priority" msgid="7952654515769021553">"Makikita sa itaas ng seksyon ng pag-uusap, lumalabas bilang floating bubble, ipinapakita sa lock screen ang larawan sa profile"</string>
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"Mga Setting"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"Priyoridad"</string>
- <string name="no_shortcut" msgid="7176375126961212514">"Hindi sinusuportahan ng <xliff:g id="APP_NAME">%1$s</xliff:g> ang mga setting na partikular sa pag-uusap"</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>
<string name="bubble_overflow_empty_title" msgid="3120029421991510842">"Walang kamakailang bubble"</string>
<string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"Lalabas dito ang mga kamakailang bubble at na-dismiss na bubble"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"Hindi puwedeng baguhin ang mga notification na ito."</string>
@@ -1013,7 +1002,8 @@
<string name="bubble_accessibility_action_move_top_right" msgid="6916868852433483569">"Ilipat sa kanan sa itaas"</string>
<string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"Ilipat sa kaliwa sa ibaba"</string>
<string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"Ilipat sa kanan sa ibaba"</string>
- <string name="bubble_dismiss_text" msgid="7071770411580452911">"I-dismiss"</string>
+ <!-- no translation found for bubble_dismiss_text (1314082410868930066) -->
+ <skip />
<string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"Huwag ipakita sa bubble ang mga pag-uusap"</string>
<string name="bubbles_user_education_title" msgid="5547017089271445797">"Makipag-chat gamit ang mga bubble"</string>
<string name="bubbles_user_education_description" msgid="1160281719576715211">"Lumalabas bilang mga nakalutang na icon o bubble ang mga bagong pag-uusap. I-tap para buksan ang bubble. I-drag para ilipat ito."</string>
@@ -1024,11 +1014,14 @@
<string name="notification_content_system_nav_changed" msgid="5077913144844684544">"Na-update na ang pag-navigate ng system. Para gumawa ng mga pagbabago, pumunta sa Mga Setting."</string>
<string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"Pumunta sa Mga Setting para i-update ang pag-navigate sa system"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Naka-standby"</string>
+ <string name="priority_onboarding_title" msgid="2893070698479227616">"Ginawang priyoridad ang pag-uusap"</string>
+ <string name="priority_onboarding_behavior" msgid="5342816047020432929">"Ang mga priyoridad na pag-uusap ay:"</string>
<string name="priority_onboarding_show_at_top_text" msgid="1678400241025513541">"Ipakita sa itaas ng seksyon ng pag-uusap"</string>
<string name="priority_onboarding_show_avatar_text" msgid="5756291381124091508">"Ipakita ang larawan sa profile sa lock screen"</string>
<string name="priority_onboarding_appear_as_bubble_text" msgid="4227039772250263122">"Ipakitang floating bubble sa ibabaw ng mga app"</string>
<string name="priority_onboarding_ignores_dnd_text" msgid="2918952762719600529">"Ihinto ang Huwag Istorbohin"</string>
<string name="priority_onboarding_done_button_title" msgid="4569550984286506007">"OK"</string>
+ <string name="priority_onboarding_settings_button_title" msgid="6663601574303585927">"Mga Setting"</string>
<string name="magnification_overlay_title" msgid="6584179429612427958">"Window ng Overlay sa Pag-magnify"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"Window ng Pag-magnify"</string>
<string name="magnification_controls_title" msgid="8421106606708891519">"Mga Kontrol sa Pag-magnify ng Window"</string>
@@ -1070,9 +1063,13 @@
<string name="controls_structure_tooltip" msgid="4355922222944447867">"Mag-swipe para tumingin ng higit pa"</string>
<string name="controls_seeding_in_progress" msgid="3033855341410264148">"Nilo-load ang rekomendasyon"</string>
<string name="controls_media_close_session" msgid="9023534788828414585">"Isara ang session ng media na ito"</string>
+ <string name="controls_media_resume" msgid="1933520684481586053">"Ituloy"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"Hindi aktibo, tingnan ang app"</string>
<string name="controls_error_retryable" msgid="864025882878378470">"Nagka-error, sinusubukan ulit…"</string>
- <string name="controls_error_removed" msgid="6299213591234723805">"Inalis ang device"</string>
+ <string name="controls_error_removed" msgid="6675638069846014366">"Hindi nahanap"</string>
+ <string name="controls_error_removed_title" msgid="1207794911208047818">"Hindi available ang kontrol"</string>
+ <string name="controls_error_removed_message" msgid="2885911717034750542">"Hindi ma-access ang <xliff:g id="DEVICE">%1$s</xliff:g>. Tingnan ang <xliff:g id="APPLICATION">%2$s</xliff:g> app para matiyak na available pa rin ang kontrol at hindi nabago ang mga setting ng app."</string>
+ <string name="controls_open_app" msgid="483650971094300141">"Buksan ang app"</string>
<string name="controls_error_generic" msgid="352500456918362905">"Hindi ma-load ang status"</string>
<string name="controls_error_failed" msgid="960228639198558525">"Nagka-error, subukan ulit"</string>
<string name="controls_in_progress" msgid="4421080500238215939">"Isinasagawa"</string>
diff --git a/packages/SystemUI/res/values-tr/strings.xml b/packages/SystemUI/res/values-tr/strings.xml
index 63f336b61a1b..e4892cf934a3 100644
--- a/packages/SystemUI/res/values-tr/strings.xml
+++ b/packages/SystemUI/res/values-tr/strings.xml
@@ -77,9 +77,6 @@
<string name="compat_mode_on" msgid="4963711187149440884">"Yakınlaştır (ekranı kaplasın)"</string>
<string name="compat_mode_off" msgid="7682459748279487945">"Genişlet (ekran kapansın)"</string>
<string name="global_action_screenshot" msgid="2760267567509131654">"Ekran görüntüsü"</string>
- <string name="global_action_lock_message" product="default" msgid="4466026255205186456">"Diğer seçenekler için telefonunuzun kilidini açın"</string>
- <string name="global_action_lock_message" product="tablet" msgid="7621167597240332986">"Diğer seçenekler için tabletinizin kilidini açın"</string>
- <string name="global_action_lock_message" product="device" msgid="538790401275363781">"Diğer seçenekler için cihazınızın kilidini açın"</string>
<string name="remote_input_image_insertion_text" msgid="4850791636452521123">"bir resim gönderildi"</string>
<string name="screenshot_saving_ticker" msgid="6519186952674544916">"Ekran görüntüsü kaydediliyor..."</string>
<string name="screenshot_saving_title" msgid="2298349784913287333">"Ekran görüntüsü kaydediliyor..."</string>
@@ -595,29 +592,21 @@
<string name="volume_odi_captions_hint_enable" msgid="2073091194012843195">"etkinleştir"</string>
<string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"devre dışı bırak"</string>
<string name="accessibility_output_chooser" msgid="7807898688967194183">"Çıkış cihazını değiştir"</string>
- <!-- no translation found for screen_pinning_title (9058007390337841305) -->
- <skip />
+ <string name="screen_pinning_title" msgid="9058007390337841305">"Uygulama sabitlenmiştir"</string>
<string name="screen_pinning_description" msgid="8699395373875667743">"Bu işlem, siz sabitlemeyi kaldırana kadar ekranı görünür durumda tutar. Sabitlemeyi kaldırmak için Geri\'ye ve Genel Bakış\'a dokunup basılı tutun."</string>
<string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"Bu işlem, siz sabitlemeyi kaldırana kadar ekranı görünür durumda tutar. Sabitlemeyi kaldırmak için Geri\'ye ve Ana sayfaya dokunup basılı tutun."</string>
<string name="screen_pinning_description_gestural" msgid="7246323931831232068">"Bu, sabitleme kaldırılana kadar öğenin görünmesini sağlar. Sabitlemeyi kaldırmak için yukarı kaydırıp basılı tutun."</string>
<string name="screen_pinning_description_accessible" msgid="7386449191953535332">"Bu işlem, siz sabitlemeyi kaldırana kadar ekranı görünür durumda tutar. Sabitlemeyi kaldırmak için Genel bakış\'a dokunup basılı tutun."</string>
<string name="screen_pinning_description_recents_invisible_accessible" msgid="2857071808674481986">"Bu işlem, siz sabitlemeyi kaldırana kadar ekranı görünür durumda tutar. Sabitlemeyi kaldırmak için Ana sayfaya dokunup basılı tutun."</string>
- <!-- no translation found for screen_pinning_exposes_personal_data (8189852022981524789) -->
- <skip />
- <!-- no translation found for screen_pinning_can_open_other_apps (7529756813231421455) -->
- <skip />
- <!-- no translation found for screen_pinning_toast (8177286912533744328) -->
- <skip />
- <!-- no translation found for screen_pinning_toast_recents_invisible (6850978077443052594) -->
- <skip />
- <!-- no translation found for screen_pinning_toast_gesture_nav (170699893395336705) -->
- <skip />
+ <string name="screen_pinning_exposes_personal_data" msgid="8189852022981524789">"Kişisel verilere erişilebilir (ör. kişiler ve e-posta içerikleri)."</string>
+ <string name="screen_pinning_can_open_other_apps" msgid="7529756813231421455">"Sabitlenmiş uygulama diğer uygulamaları açabilir."</string>
+ <string name="screen_pinning_toast" msgid="8177286912533744328">"Bu uygulamanın sabitlemesini kaldırmak için Geri ve Genel Bakış düğmelerine dokunup basılı tutun"</string>
+ <string name="screen_pinning_toast_recents_invisible" msgid="6850978077443052594">"Bu ekranın sabitlemesini kaldırmak için Geri ve Ana sayfa düğmelerine dokunup basılı tutun"</string>
+ <string name="screen_pinning_toast_gesture_nav" msgid="170699893395336705">"Bu ekranın sabitlemesini kaldırmak için hızlıca yukarı kaydırıp tutun"</string>
<string name="screen_pinning_positive" msgid="3285785989665266984">"Anladım"</string>
<string name="screen_pinning_negative" msgid="6882816864569211666">"Hayır, teşekkürler"</string>
- <!-- no translation found for screen_pinning_start (7483998671383371313) -->
- <skip />
- <!-- no translation found for screen_pinning_exit (4553787518387346893) -->
- <skip />
+ <string name="screen_pinning_start" msgid="7483998671383371313">"Uygulama sabitlendi"</string>
+ <string name="screen_pinning_exit" msgid="4553787518387346893">"Uygulamanın sabitlemesi kaldırıldı"</string>
<string name="quick_settings_reset_confirmation_title" msgid="463533331480997595">"<xliff:g id="TILE_LABEL">%1$s</xliff:g> gizlensin mi?"</string>
<string name="quick_settings_reset_confirmation_message" msgid="2320586180785674186">"Ayarlardan etkinleştirdiğiniz bir sonraki sefer tekrar görünür."</string>
<string name="quick_settings_reset_confirmation_button" msgid="3341477479055016776">"Gizle"</string>
@@ -730,7 +719,7 @@
<string name="notification_channel_summary_priority" msgid="7952654515769021553">"Görüşme bölümünün üstünde gösterilir, kayan baloncuk olarak görünür, kilit ekranında profil resmini görüntüler"</string>
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"Ayarlar"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"Öncelik"</string>
- <string name="no_shortcut" msgid="7176375126961212514">"<xliff:g id="APP_NAME">%1$s</xliff:g>, görüşmeye özgü ayarları desteklemiyor"</string>
+ <string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g>, sohbet özelliklerini desteklemiyor"</string>
<string name="bubble_overflow_empty_title" msgid="3120029421991510842">"Son kapatılan baloncuk yok"</string>
<string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"Son baloncuklar ve kapattığınız baloncuklar burada görünür"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"Bu bildirimler değiştirilemez."</string>
@@ -1013,7 +1002,8 @@
<string name="bubble_accessibility_action_move_top_right" msgid="6916868852433483569">"Sağ üste taşı"</string>
<string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"Sol alta taşı"</string>
<string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"Sağ alta taşı"</string>
- <string name="bubble_dismiss_text" msgid="7071770411580452911">"Kapat"</string>
+ <!-- no translation found for bubble_dismiss_text (1314082410868930066) -->
+ <skip />
<string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"Görüşmeyi baloncuk olarak görüntüleme"</string>
<string name="bubbles_user_education_title" msgid="5547017089271445797">"Baloncukları kullanarak sohbet edin"</string>
<string name="bubbles_user_education_description" msgid="1160281719576715211">"Yeni görüşmeler kayan simgeler veya baloncuk olarak görünür. Açmak için baloncuğa dokunun. Baloncuğu taşımak için sürükleyin."</string>
@@ -1024,11 +1014,14 @@
<string name="notification_content_system_nav_changed" msgid="5077913144844684544">"Sistemde gezinme yöntemi güncellendi. Değişiklik yapmak için Ayarlar\'a gidin."</string>
<string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"Sistemde gezinme yöntemini güncellemek için Ayarlar\'a gidin"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Beklemeye alınıyor"</string>
+ <string name="priority_onboarding_title" msgid="2893070698479227616">"Görüşme öncelikli olarak ayarlandı"</string>
+ <string name="priority_onboarding_behavior" msgid="5342816047020432929">"Öncelikli görüşmeler:"</string>
<string name="priority_onboarding_show_at_top_text" msgid="1678400241025513541">"Görüşme bölümünün üstünde gösterilir"</string>
<string name="priority_onboarding_show_avatar_text" msgid="5756291381124091508">"Kilit ekranında profil resmi gösterilir"</string>
<string name="priority_onboarding_appear_as_bubble_text" msgid="4227039772250263122">"Uygulamaların üzerinde kayan balon olarak görünür"</string>
<string name="priority_onboarding_ignores_dnd_text" msgid="2918952762719600529">"Rahatsız Etmeyin\'i keser"</string>
<string name="priority_onboarding_done_button_title" msgid="4569550984286506007">"Anladım"</string>
+ <string name="priority_onboarding_settings_button_title" msgid="6663601574303585927">"Ayarlar"</string>
<string name="magnification_overlay_title" msgid="6584179429612427958">"Yer Paylaşımlı Büyütme Penceresi"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"Büyütme Penceresi"</string>
<string name="magnification_controls_title" msgid="8421106606708891519">"Büyütme Penceresi Kontrolleri"</string>
@@ -1049,7 +1042,7 @@
<string name="accessibility_control_change_unfavorite" msgid="6997408061750740327">"favorilerden kaldırın"</string>
<string name="accessibility_control_move" msgid="8980344493796647792">"<xliff:g id="NUMBER">%d</xliff:g>. konuma taşı"</string>
<string name="controls_favorite_default_title" msgid="967742178688938137">"Kontroller"</string>
- <string name="controls_favorite_subtitle" msgid="6604402232298443956">"Güç menüsünden erişmek için denetimleri seçin"</string>
+ <string name="controls_favorite_subtitle" msgid="6604402232298443956">"Güç menüsünden erişmek istediğiniz denetimleri seçin"</string>
<string name="controls_favorite_rearrange" msgid="5616952398043063519">"Kontrolleri yeniden düzenlemek için basılı tutup sürükleyin"</string>
<string name="controls_favorite_removed" msgid="5276978408529217272">"Tüm kontroller kaldırıldı"</string>
<string name="controls_favorite_toast_no_changes" msgid="7094494210840877931">"Değişiklikler kaydedilmedi"</string>
@@ -1070,9 +1063,13 @@
<string name="controls_structure_tooltip" msgid="4355922222944447867">"Diğer öğeleri görmek için hızlıca kaydırın"</string>
<string name="controls_seeding_in_progress" msgid="3033855341410264148">"Öneriler yükleniyor"</string>
<string name="controls_media_close_session" msgid="9023534788828414585">"Bu medya oturumunu kapat"</string>
+ <string name="controls_media_resume" msgid="1933520684481586053">"Devam ettir"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"Devre dışı, uygulamaya bakın"</string>
<string name="controls_error_retryable" msgid="864025882878378470">"Hata, yeniden deneniyor…"</string>
- <string name="controls_error_removed" msgid="6299213591234723805">"Cihaz kaldırıldı"</string>
+ <string name="controls_error_removed" msgid="6675638069846014366">"Bulunamadı"</string>
+ <string name="controls_error_removed_title" msgid="1207794911208047818">"Kontrol kullanılamıyor"</string>
+ <string name="controls_error_removed_message" msgid="2885911717034750542">"<xliff:g id="DEVICE">%1$s</xliff:g> cihazına erişilemedi Kontrolün hâlâ kullanılabilir olduğundan ve uygulama ayarlarının değişmediğinden emin olmak için <xliff:g id="APPLICATION">%2$s</xliff:g> uygulamasını kontrol edin."</string>
+ <string name="controls_open_app" msgid="483650971094300141">"Uygulama aç"</string>
<string name="controls_error_generic" msgid="352500456918362905">"Durum yüklenemiyor"</string>
<string name="controls_error_failed" msgid="960228639198558525">"Hata, yeniden deneyin"</string>
<string name="controls_in_progress" msgid="4421080500238215939">"Devam ediyor"</string>
diff --git a/packages/SystemUI/res/values-uk/strings.xml b/packages/SystemUI/res/values-uk/strings.xml
index 0aa3f7a259ab..4c39f43a8845 100644
--- a/packages/SystemUI/res/values-uk/strings.xml
+++ b/packages/SystemUI/res/values-uk/strings.xml
@@ -77,9 +77,6 @@
<string name="compat_mode_on" msgid="4963711187149440884">"Масштабув. на весь екран"</string>
<string name="compat_mode_off" msgid="7682459748279487945">"Розтягнути на весь екран"</string>
<string name="global_action_screenshot" msgid="2760267567509131654">"Знімок екрана"</string>
- <string name="global_action_lock_message" product="default" msgid="4466026255205186456">"Розблокуйте телефон, щоб переглянути інші параметри"</string>
- <string name="global_action_lock_message" product="tablet" msgid="7621167597240332986">"Розблокуйте планшет, щоб переглянути інші параметри"</string>
- <string name="global_action_lock_message" product="device" msgid="538790401275363781">"Розблокуйте пристрій, щоб переглянути інші параметри"</string>
<string name="remote_input_image_insertion_text" msgid="4850791636452521123">"надіслане зображення"</string>
<string name="screenshot_saving_ticker" msgid="6519186952674544916">"Збереження знімка екрана..."</string>
<string name="screenshot_saving_title" msgid="2298349784913287333">"Збереження знімка екрана..."</string>
@@ -422,7 +419,7 @@
<string name="quick_settings_cellular_detail_data_limit" msgid="1791389609409211628">"Обмеження: <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
<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="2754212289804324685">"Робочий профіль"</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>
@@ -601,29 +598,21 @@
<string name="volume_odi_captions_hint_enable" msgid="2073091194012843195">"увімкнути"</string>
<string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"вимкнути"</string>
<string name="accessibility_output_chooser" msgid="7807898688967194183">"Увімкніть пристрій виведення"</string>
- <!-- no translation found for screen_pinning_title (9058007390337841305) -->
- <skip />
+ <string name="screen_pinning_title" msgid="9058007390337841305">"Додаток закріплено"</string>
<string name="screen_pinning_description" msgid="8699395373875667743">"Ви постійно бачитимете екран, доки не відкріпите його. Щоб відкріпити екран, натисніть і втримуйте кнопки \"Назад\" та \"Огляд\"."</string>
<string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"Ви бачитимете цей екран, доки не відкріпите його. Для цього натисніть і утримуйте кнопки \"Назад\" та \"Головний екран\"."</string>
<string name="screen_pinning_description_gestural" msgid="7246323931831232068">"Ви бачитимете цей екран, доки не відкріпите його. Для цього проведіть пальцем угору й утримуйте екран."</string>
<string name="screen_pinning_description_accessible" msgid="7386449191953535332">"Ви постійно бачитимете екран, доки не відкріпите його. Щоб відкріпити екран, натисніть і втримуйте кнопку \"Огляд\"."</string>
<string name="screen_pinning_description_recents_invisible_accessible" msgid="2857071808674481986">"Ви бачитимете цей екран, доки не відкріпите його. Для цього натисніть і утримуйте кнопку \"Головний екран\"."</string>
- <!-- no translation found for screen_pinning_exposes_personal_data (8189852022981524789) -->
- <skip />
- <!-- no translation found for screen_pinning_can_open_other_apps (7529756813231421455) -->
- <skip />
- <!-- no translation found for screen_pinning_toast (8177286912533744328) -->
- <skip />
- <!-- no translation found for screen_pinning_toast_recents_invisible (6850978077443052594) -->
- <skip />
- <!-- no translation found for screen_pinning_toast_gesture_nav (170699893395336705) -->
- <skip />
+ <string name="screen_pinning_exposes_personal_data" msgid="8189852022981524789">"Закріплений додаток може отримувати доступ до персональних даних (наприклад, до контактів або електронних листів)."</string>
+ <string name="screen_pinning_can_open_other_apps" msgid="7529756813231421455">"Закріплений додаток може відкривати інші додатки."</string>
+ <string name="screen_pinning_toast" msgid="8177286912533744328">"Щоб відкріпити цей додаток, натисніть і утримуйте кнопки \"Назад\" та \"Огляд\""</string>
+ <string name="screen_pinning_toast_recents_invisible" msgid="6850978077443052594">"Щоб відкріпити цей додаток, натисніть і утримуйте кнопки \"Назад\" та \"Головний екран\""</string>
+ <string name="screen_pinning_toast_gesture_nav" msgid="170699893395336705">"Щоб відкріпити цей додаток, проведіть пальцем вгору й утримуйте його на екрані"</string>
<string name="screen_pinning_positive" msgid="3285785989665266984">"Зрозуміло"</string>
<string name="screen_pinning_negative" msgid="6882816864569211666">"Ні, дякую"</string>
- <!-- no translation found for screen_pinning_start (7483998671383371313) -->
- <skip />
- <!-- no translation found for screen_pinning_exit (4553787518387346893) -->
- <skip />
+ <string name="screen_pinning_start" msgid="7483998671383371313">"Додаток закріплено"</string>
+ <string name="screen_pinning_exit" msgid="4553787518387346893">"Додаток відкріплено"</string>
<string name="quick_settings_reset_confirmation_title" msgid="463533331480997595">"Сховати <xliff:g id="TILE_LABEL">%1$s</xliff:g>?"</string>
<string name="quick_settings_reset_confirmation_message" msgid="2320586180785674186">"З’явиться знову, коли ви ввімкнете його в налаштуваннях."</string>
<string name="quick_settings_reset_confirmation_button" msgid="3341477479055016776">"Сховати"</string>
@@ -736,7 +725,7 @@
<string name="notification_channel_summary_priority" msgid="7952654515769021553">"З\'являється вгорі розділу розмов у спливаючому сповіщенні та показує зображення профілю на заблокованому екрані"</string>
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"Налаштування"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"Пріоритет"</string>
- <string name="no_shortcut" msgid="7176375126961212514">"<xliff:g id="APP_NAME">%1$s</xliff:g> не підтримує налаштування для чату"</string>
+ <string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> не підтримує функції розмов"</string>
<string name="bubble_overflow_empty_title" msgid="3120029421991510842">"Немає нещодавніх спливаючих чатів"</string>
<string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"Тут з\'являтимуться нещодавні й закриті спливаючі чати"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"Ці сповіщення не можна змінити."</string>
@@ -1023,9 +1012,10 @@
<string name="bubble_accessibility_action_move_top_right" msgid="6916868852433483569">"Перемістити праворуч угору"</string>
<string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"Перемістити ліворуч униз"</string>
<string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"Перемістити праворуч униз"</string>
- <string name="bubble_dismiss_text" msgid="7071770411580452911">"Закрити"</string>
+ <!-- no translation found for bubble_dismiss_text (1314082410868930066) -->
+ <skip />
<string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"Не показувати спливаючі чати для розмов"</string>
- <string name="bubbles_user_education_title" msgid="5547017089271445797">"Чат зі спливаючими сповіщеннями"</string>
+ <string name="bubbles_user_education_title" msgid="5547017089271445797">"Спливаючий чат"</string>
<string name="bubbles_user_education_description" msgid="1160281719576715211">"Нові повідомлення чату з\'являються у вигляді спливаючих значків. Щоб відкрити чат, натисніть його, а щоб перемістити – перетягніть."</string>
<string name="bubbles_user_education_manage_title" msgid="2848511858160342320">"Налаштовуйте спливаючі чати будь-коли"</string>
<string name="bubbles_user_education_manage" msgid="1391639189507036423">"Натисніть \"Налаштувати\", щоб вимкнути спливаючі чати від цього додатка"</string>
@@ -1034,15 +1024,18 @@
<string name="notification_content_system_nav_changed" msgid="5077913144844684544">"Навігацію в системі оновлено. Щоб внести зміни, перейдіть у налаштування."</string>
<string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"Перейдіть у налаштування, щоб оновити навігацію в системі"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Режим очікування"</string>
+ <string name="priority_onboarding_title" msgid="2893070698479227616">"Розмову призначено важливою"</string>
+ <string name="priority_onboarding_behavior" msgid="5342816047020432929">"Важливі розмови:"</string>
<string name="priority_onboarding_show_at_top_text" msgid="1678400241025513541">"З\'являються вгорі розділу розмов"</string>
<string name="priority_onboarding_show_avatar_text" msgid="5756291381124091508">"Показують фото профілю на заблокованому екрані"</string>
<string name="priority_onboarding_appear_as_bubble_text" msgid="4227039772250263122">"З\'являються як спливаючі чати поверх додатків"</string>
<string name="priority_onboarding_ignores_dnd_text" msgid="2918952762719600529">"Переривають режим \"Не турбувати\""</string>
<string name="priority_onboarding_done_button_title" msgid="4569550984286506007">"OK"</string>
+ <string name="priority_onboarding_settings_button_title" msgid="6663601574303585927">"Налаштування"</string>
<string name="magnification_overlay_title" msgid="6584179429612427958">"Вікно збільшення з накладанням"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"Вікно збільшення"</string>
<string name="magnification_controls_title" msgid="8421106606708891519">"Елементи керування вікна збільшення"</string>
- <string name="quick_controls_title" msgid="6839108006171302273">"Елементи керування пристроями"</string>
+ <string name="quick_controls_title" msgid="6839108006171302273">"Керування пристроями"</string>
<string name="quick_controls_subtitle" msgid="1667408093326318053">"Додайте елементи керування для підключених пристроїв"</string>
<string name="quick_controls_setup_title" msgid="8901436655997849822">"Налаштувати елементи керування пристроями"</string>
<string name="quick_controls_setup_subtitle" msgid="1681506617879773824">"Щоб відкрити елементи керування, утримуйте кнопку живлення"</string>
@@ -1061,7 +1054,7 @@
<string name="accessibility_control_change_unfavorite" msgid="6997408061750740327">"видалити з вибраного"</string>
<string name="accessibility_control_move" msgid="8980344493796647792">"Перемістити на позицію <xliff:g id="NUMBER">%d</xliff:g>"</string>
<string name="controls_favorite_default_title" msgid="967742178688938137">"Елементи керування"</string>
- <string name="controls_favorite_subtitle" msgid="6604402232298443956">"Виберіть, які елементи керування будуть у меню \"Живлення\""</string>
+ <string name="controls_favorite_subtitle" msgid="6604402232298443956">"Виберіть, які елементи керування будуть у меню кнопки живлення"</string>
<string name="controls_favorite_rearrange" msgid="5616952398043063519">"Щоб змінити порядок елементів керування, перетягуйте їх"</string>
<string name="controls_favorite_removed" msgid="5276978408529217272">"Усі елементи керування вилучено"</string>
<string name="controls_favorite_toast_no_changes" msgid="7094494210840877931">"Зміни не збережено"</string>
@@ -1072,7 +1065,7 @@
<string name="controls_dialog_message" msgid="342066938390663844">"Запропоновано додатком <xliff:g id="APP">%s</xliff:g>"</string>
<string name="controls_dialog_confirmation" msgid="586517302736263447">"Елементи керування оновлено"</string>
<string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"PIN-код містить літери чи символи"</string>
- <string name="controls_pin_verify" msgid="3452778292918877662">"<xliff:g id="DEVICE">%s</xliff:g>: підтвердити"</string>
+ <string name="controls_pin_verify" msgid="3452778292918877662">"<xliff:g id="DEVICE">%s</xliff:g>"</string>
<string name="controls_pin_wrong" msgid="6162694056042164211">"Неправильний PIN-код"</string>
<string name="controls_pin_verifying" msgid="3755045989392131746">"Підтвердження…"</string>
<string name="controls_pin_instructions" msgid="6363309783822475238">"Введіть PIN-код"</string>
@@ -1082,9 +1075,13 @@
<string name="controls_structure_tooltip" msgid="4355922222944447867">"Гортайте, щоб переглянути інші"</string>
<string name="controls_seeding_in_progress" msgid="3033855341410264148">"Завантаження рекомендацій"</string>
<string name="controls_media_close_session" msgid="9023534788828414585">"Закрити цей сеанс медіа"</string>
+ <string name="controls_media_resume" msgid="1933520684481586053">"Відновити"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"Неактивно, перейдіть у додаток"</string>
<string name="controls_error_retryable" msgid="864025882878378470">"Помилка. Повторна спроба…"</string>
- <string name="controls_error_removed" msgid="6299213591234723805">"Пристрій вилучено"</string>
+ <string name="controls_error_removed" msgid="6675638069846014366">"Не знайдено"</string>
+ <string name="controls_error_removed_title" msgid="1207794911208047818">"Елемент керування недоступний"</string>
+ <string name="controls_error_removed_message" msgid="2885911717034750542">"<xliff:g id="DEVICE">%1$s</xliff:g>: немає доступу. Перевірте в додатку <xliff:g id="APPLICATION">%2$s</xliff:g>, чи його налаштування не змінились і чи елемент керування доступний."</string>
+ <string name="controls_open_app" msgid="483650971094300141">"Відкрити додаток"</string>
<string name="controls_error_generic" msgid="352500456918362905">"Не вдалося завантажити статус"</string>
<string name="controls_error_failed" msgid="960228639198558525">"Помилка. Спробуйте знову"</string>
<string name="controls_in_progress" msgid="4421080500238215939">"Виконується"</string>
diff --git a/packages/SystemUI/res/values-ur/strings.xml b/packages/SystemUI/res/values-ur/strings.xml
index 47eebc7e3fe2..feb894a56eb0 100644
--- a/packages/SystemUI/res/values-ur/strings.xml
+++ b/packages/SystemUI/res/values-ur/strings.xml
@@ -77,9 +77,6 @@
<string name="compat_mode_on" msgid="4963711187149440884">"پوری سکرین پر زوم کریں"</string>
<string name="compat_mode_off" msgid="7682459748279487945">"پوری سکرین پر پھیلائیں"</string>
<string name="global_action_screenshot" msgid="2760267567509131654">"اسکرین شاٹ"</string>
- <string name="global_action_lock_message" product="default" msgid="4466026255205186456">"مزید اختیارات کے لیے اپنا فون غیر مقفل کریں"</string>
- <string name="global_action_lock_message" product="tablet" msgid="7621167597240332986">"مزید اختیارات کے لیے اپنا ٹیبلیٹ غیر مقفل کریں"</string>
- <string name="global_action_lock_message" product="device" msgid="538790401275363781">"مزید اختیارات کے لیے اپنا آلہ غیر مقفل کریں"</string>
<string name="remote_input_image_insertion_text" msgid="4850791636452521123">"ایک تصویر بھیجی"</string>
<string name="screenshot_saving_ticker" msgid="6519186952674544916">"اسکرین شاٹ محفوظ ہو رہا ہے…"</string>
<string name="screenshot_saving_title" msgid="2298349784913287333">"اسکرین شاٹ محفوظ ہو رہا ہے…"</string>
@@ -595,29 +592,21 @@
<string name="volume_odi_captions_hint_enable" msgid="2073091194012843195">"فعال کریں"</string>
<string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"غیر فعال کریں"</string>
<string name="accessibility_output_chooser" msgid="7807898688967194183">"آؤٹ پٹ آلہ سوئچ کریں"</string>
- <!-- no translation found for screen_pinning_title (9058007390337841305) -->
- <skip />
+ <string name="screen_pinning_title" msgid="9058007390337841305">"ایپ کو پن کر دیا گیا ہے"</string>
<string name="screen_pinning_description" msgid="8699395373875667743">"یہ اسے اس وقت تک نظر میں رکھتا ہے جب تک آپ اس سے پن ہٹا نہیں دیتے۔ پن ہٹانے کیلئے پیچھے اور مجموعی جائزہ بٹنز کو ٹچ کریں اور دبائے رکھیں۔"</string>
<string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"یہ اس کو اس وقت تک مد نظر رکھتا ہے جب تک آپ اس سے پن نہیں ہٹا دیتے۔ پن ہٹانے کیلئے \"پیچھے\" اور \"ہوم\" بٹنز کو ٹچ کریں اور دبائے رکھیں۔"</string>
<string name="screen_pinning_description_gestural" msgid="7246323931831232068">"یہ اس کو اس وقت تک مد نظر رکھتا ہے جب تک آپ اس سے پن نہیں ہٹا دیتے۔ پن ہٹانے کے لیے سوائپ کریں اور پکڑ کر رکھیں۔"</string>
<string name="screen_pinning_description_accessible" msgid="7386449191953535332">"یہ اسے اس وقت تک نظر میں رکھتا ہے جب تک آپ اس سے پن ہٹا نہیں دیتے۔ پن ہٹانے کیلئے مجموعی جائزہ بٹن کو ٹچ کریں اور دبائے رکھیں۔"</string>
<string name="screen_pinning_description_recents_invisible_accessible" msgid="2857071808674481986">"یہ اس کو اس وقت تک مد نظر رکھتا ہے جب تک آپ اس سے پن نہیں ہٹا دیتے۔ پن ہٹانے کیلئے \"ہوم\" بٹن کو ٹچ کریں اور دبائے رکھیں۔"</string>
- <!-- no translation found for screen_pinning_exposes_personal_data (8189852022981524789) -->
- <skip />
- <!-- no translation found for screen_pinning_can_open_other_apps (7529756813231421455) -->
- <skip />
- <!-- no translation found for screen_pinning_toast (8177286912533744328) -->
- <skip />
- <!-- no translation found for screen_pinning_toast_recents_invisible (6850978077443052594) -->
- <skip />
- <!-- no translation found for screen_pinning_toast_gesture_nav (170699893395336705) -->
- <skip />
+ <string name="screen_pinning_exposes_personal_data" msgid="8189852022981524789">"ذاتی ڈیٹا قابل رسائی ہو سکتا ہے (جیسے رابطے اور ای میل کا مواد)۔"</string>
+ <string name="screen_pinning_can_open_other_apps" msgid="7529756813231421455">"پن کردہ ایپ دیگر ایپس کو کھول سکتی ہے۔"</string>
+ <string name="screen_pinning_toast" msgid="8177286912533744328">"اس ایپ سے پن ہٹانے کے لیے، \"واپس جائیں\" اور \"مجموعی جائزہ\" بٹنز کو ٹچ کریں اور دبائے رکھیں"</string>
+ <string name="screen_pinning_toast_recents_invisible" msgid="6850978077443052594">"اس ایپ سے پن ہٹانے کے لیے، \"واپس جائیں\" اور \"ہوم\" بٹنز کو ٹچ کریں اور دبائے رکھیں"</string>
+ <string name="screen_pinning_toast_gesture_nav" msgid="170699893395336705">"اس ایپ سے پن ہٹانے کے لیے، اوپر کی طرف سوائپ کریں اور دبائے رکھیں"</string>
<string name="screen_pinning_positive" msgid="3285785989665266984">"سمجھ آ گئی"</string>
<string name="screen_pinning_negative" msgid="6882816864569211666">"نہیں شکریہ"</string>
- <!-- no translation found for screen_pinning_start (7483998671383371313) -->
- <skip />
- <!-- no translation found for screen_pinning_exit (4553787518387346893) -->
- <skip />
+ <string name="screen_pinning_start" msgid="7483998671383371313">"ایپ کو پن کر دیا گیا"</string>
+ <string name="screen_pinning_exit" msgid="4553787518387346893">"ایپ کا پن ہٹا دیا گیا"</string>
<string name="quick_settings_reset_confirmation_title" msgid="463533331480997595">"<xliff:g id="TILE_LABEL">%1$s</xliff:g> کو چھپائیں؟"</string>
<string name="quick_settings_reset_confirmation_message" msgid="2320586180785674186">"اگلی بار جب آپ اسے ترتیبات میں آن کریں گے تو یہ ظاہر ہوگی۔"</string>
<string name="quick_settings_reset_confirmation_button" msgid="3341477479055016776">"چھپائیں"</string>
@@ -730,7 +719,7 @@
<string name="notification_channel_summary_priority" msgid="7952654515769021553">"گفتگو کے سیکشن کے اوپری حصے پر دکھاتا ہے، تیرتے بلبلے کی طرح ظاہر ہوتا ہے، لاک اسکرین پر پروفائل تصویر دکھاتا ہے"</string>
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"ترتیبات"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"ترجیح"</string>
- <string name="no_shortcut" msgid="7176375126961212514">"<xliff:g id="APP_NAME">%1$s</xliff:g> گفتگو سے متعلق مخصوص ترتیبات کو سپورٹ نہیں کرتی"</string>
+ <string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> گفتگو کی خصوصیات کو سپورٹ نہیں کرتا ہے"</string>
<string name="bubble_overflow_empty_title" msgid="3120029421991510842">"کوئی حالیہ بلبلہ نہیں"</string>
<string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"حالیہ بلبلے اور برخاست شدہ بلبلے یہاں ظاہر ہوں گے"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"ان اطلاعات کی ترمیم نہیں کی جا سکتی۔"</string>
@@ -1013,7 +1002,8 @@
<string name="bubble_accessibility_action_move_top_right" msgid="6916868852433483569">"اوپر دائیں جانب لے جائيں"</string>
<string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"نیچے بائیں جانب لے جائیں"</string>
<string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"نیچے دائیں جانب لے جائیں"</string>
- <string name="bubble_dismiss_text" msgid="7071770411580452911">"برخاست کریں"</string>
+ <!-- no translation found for bubble_dismiss_text (1314082410868930066) -->
+ <skip />
<string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"بلبلہ گفتگو نہ کریں"</string>
<string name="bubbles_user_education_title" msgid="5547017089271445797">"بلبلے کے ذریعے چیٹ کریں"</string>
<string name="bubbles_user_education_description" msgid="1160281719576715211">"نئی گفتگوئیں فلوٹنگ آئیکن یا بلبلے کے طور پر ظاہر ہوں گی۔ بلبلہ کھولنے کے لیے تھپتھپائیں۔ اسے منتقل کرنے کے لیے گھسیٹیں۔"</string>
@@ -1024,11 +1014,14 @@
<string name="notification_content_system_nav_changed" msgid="5077913144844684544">"سسٹم نیویگیشن اپ ڈیٹ کیا گیا۔ تبدیلیاں کرنے کے لیے، ترتیبات پر جائیں۔"</string>
<string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"سسٹم نیویگیشن اپ ڈیٹ کرنے کے لیے ترتیبات پر جائیں"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"اسٹینڈ بائی"</string>
+ <string name="priority_onboarding_title" msgid="2893070698479227616">"گفتگو کو ترجیح پر سیٹ کیا گیا"</string>
+ <string name="priority_onboarding_behavior" msgid="5342816047020432929">"ترجیحی گفتگوئیں یہ ہوگی:"</string>
<string name="priority_onboarding_show_at_top_text" msgid="1678400241025513541">"گفتگو کے سیکشن میں سب سے اوپر دکھائیں"</string>
<string name="priority_onboarding_show_avatar_text" msgid="5756291381124091508">"مقفل سکرین پر پروفائل کی تصویر دکھائیں"</string>
<string name="priority_onboarding_appear_as_bubble_text" msgid="4227039772250263122">"ایپس کے سب سے اوپر فلوٹنگ بلبلہ کے طور پر ظاہر ہوں"</string>
<string name="priority_onboarding_ignores_dnd_text" msgid="2918952762719600529">"ڈسٹرب نہ کریں میں مداخلت کریں"</string>
<string name="priority_onboarding_done_button_title" msgid="4569550984286506007">"سمجھ آ گئی"</string>
+ <string name="priority_onboarding_settings_button_title" msgid="6663601574303585927">"ترتیبات"</string>
<string name="magnification_overlay_title" msgid="6584179429612427958">"میگنیفیکیشن اوورلے ونڈو"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"میگنیفکیشن ونڈو"</string>
<string name="magnification_controls_title" msgid="8421106606708891519">"میگنیفکیشن ونڈو کنٹرولز"</string>
@@ -1060,19 +1053,23 @@
<string name="controls_dialog_message" msgid="342066938390663844">"<xliff:g id="APP">%s</xliff:g> کی طرف سے تجویز کردہ"</string>
<string name="controls_dialog_confirmation" msgid="586517302736263447">"کنٹرولز اپ ڈیٹ کیے گئے"</string>
<string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"‏PIN میں حروف یا علامات شامل ہیں"</string>
- <string name="controls_pin_verify" msgid="3452778292918877662">"<xliff:g id="DEVICE">%s</xliff:g> کی تصدیق کریں"</string>
+ <string name="controls_pin_verify" msgid="3452778292918877662">"‫<xliff:g id="DEVICE">%s</xliff:g> کی تصدیق کریں"</string>
<string name="controls_pin_wrong" msgid="6162694056042164211">"‏غلط PIN"</string>
<string name="controls_pin_verifying" msgid="3755045989392131746">"توثیق ہو رہی ہے…"</string>
- <string name="controls_pin_instructions" msgid="6363309783822475238">"‏PIN درج کریں"</string>
- <string name="controls_pin_instructions_retry" msgid="1566667581012131046">"‏کوئی دوسرا PIN آزمائیں"</string>
+ <string name="controls_pin_instructions" msgid="6363309783822475238">"‏‫PIN درج کریں"</string>
+ <string name="controls_pin_instructions_retry" msgid="1566667581012131046">"‏‫کوئی دوسرا PIN آزمائیں"</string>
<string name="controls_confirmation_confirming" msgid="2596071302617310665">"توثیق کی جا رہی ہے…"</string>
<string name="controls_confirmation_message" msgid="7744104992609594859">"<xliff:g id="DEVICE">%s</xliff:g> کی تبدیلی کی توثیق کریں"</string>
<string name="controls_structure_tooltip" msgid="4355922222944447867">"مزید دیکھنے کیلئے سوائپ کریں"</string>
<string name="controls_seeding_in_progress" msgid="3033855341410264148">"تجاویز لوڈ ہو رہی ہیں"</string>
<string name="controls_media_close_session" msgid="9023534788828414585">"اس میڈیا سیشن کو بند کریں"</string>
+ <string name="controls_media_resume" msgid="1933520684481586053">"دوبارہ شروع کریں"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"غیر فعال، ایپ چیک کریں"</string>
<string name="controls_error_retryable" msgid="864025882878378470">"خرابی، دوبارہ کوشش کی جا رہی ہے…"</string>
- <string name="controls_error_removed" msgid="6299213591234723805">"آلہ ہٹا دیا گیا"</string>
+ <string name="controls_error_removed" msgid="6675638069846014366">"نہیں ملا"</string>
+ <string name="controls_error_removed_title" msgid="1207794911208047818">"کنٹرول دستیاب نہیں ہے"</string>
+ <string name="controls_error_removed_message" msgid="2885911717034750542">"<xliff:g id="DEVICE">%1$s</xliff:g> تک رسائی حاصل نہیں ہو سکی۔ اس بات کو یقینی بنانے کے لیے کہ کنٹرول ابھی بھی دستیاب ہے اور ایپ کی ترتیبات تبدیل نہیں ہوئی، تو <xliff:g id="APPLICATION">%2$s</xliff:g> ایپ چیک کریں۔"</string>
+ <string name="controls_open_app" msgid="483650971094300141">"ایپ کھولیں"</string>
<string name="controls_error_generic" msgid="352500456918362905">"صورتحال لوڈ نہیں ہو سکتی"</string>
<string name="controls_error_failed" msgid="960228639198558525">"خرابی، دوبارہ کوشش کریں"</string>
<string name="controls_in_progress" msgid="4421080500238215939">"پیشرفت میں"</string>
diff --git a/packages/SystemUI/res/values-uz/strings.xml b/packages/SystemUI/res/values-uz/strings.xml
index be7c62632a4b..1145fa7b92df 100644
--- a/packages/SystemUI/res/values-uz/strings.xml
+++ b/packages/SystemUI/res/values-uz/strings.xml
@@ -436,7 +436,7 @@
<string name="recents_swipe_up_onboarding" msgid="2820265886420993995">"Ilovalarni almashtirish uchun ekranni tepaga suring"</string>
<string name="recents_quick_scrub_onboarding" msgid="765934300283514912">"Ilovalarni tezkor almashtirish uchun o‘ngga torting"</string>
<string name="quick_step_accessibility_toggle_overview" msgid="7908949976727578403">"Umumiy nazar rejimini almashtirish"</string>
- <string name="expanded_header_battery_charged" msgid="5307907517976548448">"Batareya quvvati to‘ldi"</string>
+ <string name="expanded_header_battery_charged" msgid="5307907517976548448">"Quvvat oldi"</string>
<string name="expanded_header_battery_charging" msgid="1717522253171025549">"Quvvat olmoqda"</string>
<string name="expanded_header_battery_charging_with_time" msgid="757991461445765011">"<xliff:g id="CHARGING_TIME">%s</xliff:g>da to‘ladi"</string>
<string name="expanded_header_battery_not_charging" msgid="809409140358955848">"Quvvat olmayapti"</string>
@@ -592,29 +592,21 @@
<string name="volume_odi_captions_hint_enable" msgid="2073091194012843195">"faollashtirish"</string>
<string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"faolsizlantirish"</string>
<string name="accessibility_output_chooser" msgid="7807898688967194183">"Audiochiqish qurilmasini almashtirish"</string>
- <!-- no translation found for screen_pinning_title (9058007390337841305) -->
- <skip />
+ <string name="screen_pinning_title" msgid="9058007390337841305">"Ilova mahkamlandi"</string>
<string name="screen_pinning_description" msgid="8699395373875667743">"Ekran yechilmaguncha u o‘zgarmas holatda qoladi. Uni yechish uchun “Orqaga” va “Umumiy ma’lumot” tugmalarini bosib turing."</string>
<string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"Ekran yechib olinmagunicha u mahkamlangan holatda qoladi. Uni yechish uchun Orqaga va Asosiy tugmalarni birga bosib turing."</string>
<string name="screen_pinning_description_gestural" msgid="7246323931831232068">"Yechilmaguncha chiqib turadi. Yechish uchun tepaga suring va qoʻlingizni kerakli holatda tutib turing."</string>
<string name="screen_pinning_description_accessible" msgid="7386449191953535332">"Ekran yechilmaguncha u o‘zgarmas holatda qoladi. Uni yechish uchun “Umumiy ma’lumot” tugmasini bosib turing."</string>
<string name="screen_pinning_description_recents_invisible_accessible" msgid="2857071808674481986">"Ekran yechib olinmagunicha u mahkamlangan holatda qoladi. Uni yechish uchun Orqaga va Asosiy tugmlarni birga bosib turing."</string>
- <!-- no translation found for screen_pinning_exposes_personal_data (8189852022981524789) -->
- <skip />
- <!-- no translation found for screen_pinning_can_open_other_apps (7529756813231421455) -->
- <skip />
- <!-- no translation found for screen_pinning_toast (8177286912533744328) -->
- <skip />
- <!-- no translation found for screen_pinning_toast_recents_invisible (6850978077443052594) -->
- <skip />
- <!-- no translation found for screen_pinning_toast_gesture_nav (170699893395336705) -->
- <skip />
+ <string name="screen_pinning_exposes_personal_data" msgid="8189852022981524789">"Shaxsiy maʼlumotlarga kira oladi (masalan, kontaktlar va email ichidagilarga)"</string>
+ <string name="screen_pinning_can_open_other_apps" msgid="7529756813231421455">"Mahkamlangan ilova boshqa ilovalarni ochishi mumkin."</string>
+ <string name="screen_pinning_toast" msgid="8177286912533744328">"Bu ilovadan chiqish uchun Orqaga va Menyu tugmalarini bosib turing"</string>
+ <string name="screen_pinning_toast_recents_invisible" msgid="6850978077443052594">"Bu ilovani olib tashlash uchun Orqaga va Bosh ekran tugmalarini bosib turing"</string>
+ <string name="screen_pinning_toast_gesture_nav" msgid="170699893395336705">"Bu ilovani olib tashlash uchun tepaga surib, bosib turing"</string>
<string name="screen_pinning_positive" msgid="3285785989665266984">"OK"</string>
<string name="screen_pinning_negative" msgid="6882816864569211666">"Yo‘q, kerakmas"</string>
- <!-- no translation found for screen_pinning_start (7483998671383371313) -->
- <skip />
- <!-- no translation found for screen_pinning_exit (4553787518387346893) -->
- <skip />
+ <string name="screen_pinning_start" msgid="7483998671383371313">"Ilova mahkamlandi"</string>
+ <string name="screen_pinning_exit" msgid="4553787518387346893">"Ilova olib tashlandi"</string>
<string name="quick_settings_reset_confirmation_title" msgid="463533331480997595">"<xliff:g id="TILE_LABEL">%1$s</xliff:g> berkitilsinmi?"</string>
<string name="quick_settings_reset_confirmation_message" msgid="2320586180785674186">"Keyingi safar sozlamalardan yoqilgan paydo bo‘ladi."</string>
<string name="quick_settings_reset_confirmation_button" msgid="3341477479055016776">"Berkitish"</string>
@@ -727,13 +719,13 @@
<string name="notification_channel_summary_priority" msgid="7952654515769021553">"Suhbatlar ruknining tepasida qalqib chiquvchi bulutcha shaklida chiqadi, ekran qulfida profil rasmi chiqadi"</string>
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"Sozlamalar"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"Muhim"</string>
- <string name="no_shortcut" msgid="7176375126961212514">"<xliff:g id="APP_NAME">%1$s</xliff:g> ilovasida suhbat sozlamalari ishlamaydi"</string>
+ <string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> ilovasida suhbat funksiyalari ishlamaydi"</string>
<string name="bubble_overflow_empty_title" msgid="3120029421991510842">"Avvalgi bulutchalar topilmadi"</string>
<string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"Bu yerda oxirgi va yopilgan bulutcha shaklidagi bildirishnomalar chiqadi"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"Bu bildirishnomalarni tahrirlash imkonsiz."</string>
<string name="notification_multichannel_desc" msgid="7414593090056236179">"Ushbu bildirishnomalar guruhi bu yerda sozlanmaydi"</string>
<string name="notification_delegate_header" msgid="1264510071031479920">"Ishonchli bildirishnoma"</string>
- <string name="notification_channel_dialog_title" msgid="6856514143093200019">"<xliff:g id="APP_NAME">%1$s</xliff:g> ilovasining barcha bildirishnomalari"</string>
+ <string name="notification_channel_dialog_title" msgid="6856514143093200019">"Barcha <xliff:g id="APP_NAME">%1$s</xliff:g> bildirishnomalari"</string>
<string name="see_more_title" msgid="7409317011708185729">"Yana"</string>
<string name="appops_camera" msgid="5215967620896725715">"Bu ilova kameradan foydalanmoqda."</string>
<string name="appops_microphone" msgid="8805468338613070149">"Bu ilova mikrofondan foydalanmoqda."</string>
@@ -1010,7 +1002,8 @@
<string name="bubble_accessibility_action_move_top_right" msgid="6916868852433483569">"Yuqori oʻngga surish"</string>
<string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"Quyi chapga surish"</string>
<string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"Quyi oʻngga surish"</string>
- <string name="bubble_dismiss_text" msgid="7071770411580452911">"Yopish"</string>
+ <!-- no translation found for bubble_dismiss_text (1314082410868930066) -->
+ <skip />
<string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"Suhbatlar bulutchalar shaklida chiqmasin"</string>
<string name="bubbles_user_education_title" msgid="5547017089271445797">"Bulutchalar yordamida subhatlashish"</string>
<string name="bubbles_user_education_description" msgid="1160281719576715211">"Yangi xabarlar qalqib chiquvchi belgilar yoki bulutchalar kabi chiqadi. Xabarni ochish uchun bildirishnoma ustiga bosing. Xabarni qayta joylash uchun bildirishnomani suring."</string>
@@ -1021,16 +1014,19 @@
<string name="notification_content_system_nav_changed" msgid="5077913144844684544">"Tizim navigatsiyasi yangilandi. Buni Sozlamalar orqali oʻzgartirishingiz mumkin."</string>
<string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"Tizim navigatsiyasini yangilash uchun Sozlamalarni oching"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Kutib turing"</string>
+ <string name="priority_onboarding_title" msgid="2893070698479227616">"Suhbat muhim deb belgilandi"</string>
+ <string name="priority_onboarding_behavior" msgid="5342816047020432929">"Muhim suhbatlar quyidagi amallarni bajaradi:"</string>
<string name="priority_onboarding_show_at_top_text" msgid="1678400241025513541">"Suhbatlar ruknining tepasida chiqarish"</string>
<string name="priority_onboarding_show_avatar_text" msgid="5756291381124091508">"Ekran qulfida profil rasmini chiqarish"</string>
<string name="priority_onboarding_appear_as_bubble_text" msgid="4227039772250263122">"Ilovalar ustida bulutchali xabar sifatida chiqadi"</string>
<string name="priority_onboarding_ignores_dnd_text" msgid="2918952762719600529">"Bezovta qilinmasin rejimida chiqarish"</string>
<string name="priority_onboarding_done_button_title" msgid="4569550984286506007">"OK"</string>
+ <string name="priority_onboarding_settings_button_title" msgid="6663601574303585927">"Sozlamalar"</string>
<string name="magnification_overlay_title" msgid="6584179429612427958">"Kattalashtirish oynasining ustidan ochilishi"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"Kattalashtirish oynasi"</string>
<string name="magnification_controls_title" msgid="8421106606708891519">"Kattalashtirish oynasi sozlamalari"</string>
- <string name="quick_controls_title" msgid="6839108006171302273">"Qurilma boshqaruv elementlari"</string>
- <string name="quick_controls_subtitle" msgid="1667408093326318053">"Ulangan qurilmalarga boshqaruv elementlarini kiriting"</string>
+ <string name="quick_controls_title" msgid="6839108006171302273">"Qurilmalarni boshqarish"</string>
+ <string name="quick_controls_subtitle" msgid="1667408093326318053">"Ulangan qurilmalar uchun boshqaruv elementlari"</string>
<string name="quick_controls_setup_title" msgid="8901436655997849822">"Qurilma boshqaruv elementlarini sozlash"</string>
<string name="quick_controls_setup_subtitle" msgid="1681506617879773824">"Boshqaruv elementlariga kirish uchun oʻchirib-yoqish tugmasini bosib turing"</string>
<string name="controls_providers_title" msgid="6879775889857085056">"Boshqaruv elementlarini kiritish uchun ilovani tanlang"</string>
@@ -1056,7 +1052,7 @@
<string name="controls_dialog_ok" msgid="2770230012857881822">"Kiritish"</string>
<string name="controls_dialog_message" msgid="342066938390663844">"<xliff:g id="APP">%s</xliff:g> taklif etgan"</string>
<string name="controls_dialog_confirmation" msgid="586517302736263447">"Boshqaruv elementlari yangilandi"</string>
- <string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"PIN kod harflar va belgilardan iborat boʻladi"</string>
+ <string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"Harflar yoki maxsus belgilardan iborat PIN kod"</string>
<string name="controls_pin_verify" msgid="3452778292918877662">"Tekshirish: <xliff:g id="DEVICE">%s</xliff:g>"</string>
<string name="controls_pin_wrong" msgid="6162694056042164211">"PIN kod xato"</string>
<string name="controls_pin_verifying" msgid="3755045989392131746">"Tekshirilmoqda…"</string>
@@ -1067,13 +1063,17 @@
<string name="controls_structure_tooltip" msgid="4355922222944447867">"Batafsil axborot olish uchun suring"</string>
<string name="controls_seeding_in_progress" msgid="3033855341410264148">"Tavsiyalar yuklanmoqda"</string>
<string name="controls_media_close_session" msgid="9023534788828414585">"Bu media seansni yopish"</string>
+ <string name="controls_media_resume" msgid="1933520684481586053">"Davom etish"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"Nofaol. Ilovani tekshiring"</string>
<string name="controls_error_retryable" msgid="864025882878378470">"Xato, qayta urinilmoqda…"</string>
- <string name="controls_error_removed" msgid="6299213591234723805">"Qurilma olib tashlandi"</string>
+ <string name="controls_error_removed" msgid="6675638069846014366">"Topilmadi"</string>
+ <string name="controls_error_removed_title" msgid="1207794911208047818">"Boshqarish imkonsiz"</string>
+ <string name="controls_error_removed_message" msgid="2885911717034750542">"<xliff:g id="DEVICE">%1$s</xliff:g> ochilmadi. <xliff:g id="APPLICATION">%2$s</xliff:g> ilovasining sozlamalari oʻzgarmaganini va hali ham boshqarishga ruxsat borligini tekshiring."</string>
+ <string name="controls_open_app" msgid="483650971094300141">"Ilovani ochish"</string>
<string name="controls_error_generic" msgid="352500456918362905">"Holat axboroti yuklanmadi"</string>
<string name="controls_error_failed" msgid="960228639198558525">"Xato, qayta urining"</string>
<string name="controls_in_progress" msgid="4421080500238215939">"Bajarilmoqda"</string>
<string name="controls_added_tooltip" msgid="4842812921719153085">"Yangi boshqaruv elementlari bilan tanishish uchun quvvat tugmasini bosib turing"</string>
- <string name="controls_menu_add" msgid="4447246119229920050">"Boshqaruv elementlarini kiritish"</string>
- <string name="controls_menu_edit" msgid="890623986951347062">"Boshqaruv elementlarini tahrirlash"</string>
+ <string name="controls_menu_add" msgid="4447246119229920050">"Element kiritish"</string>
+ <string name="controls_menu_edit" msgid="890623986951347062">"Elementlarni tahrirlash"</string>
</resources>
diff --git a/packages/SystemUI/res/values-vi/strings.xml b/packages/SystemUI/res/values-vi/strings.xml
index bd483b8b1c5e..8cd238c8529a 100644
--- a/packages/SystemUI/res/values-vi/strings.xml
+++ b/packages/SystemUI/res/values-vi/strings.xml
@@ -77,9 +77,6 @@
<string name="compat_mode_on" msgid="4963711187149440884">"T.phóng để lấp đầy m.hình"</string>
<string name="compat_mode_off" msgid="7682459748279487945">"Giãn ra để lấp đầy m.hình"</string>
<string name="global_action_screenshot" msgid="2760267567509131654">"Chụp ảnh màn hình"</string>
- <string name="global_action_lock_message" product="default" msgid="4466026255205186456">"Mở khóa điện thoại của bạn để xem thêm tùy chọn"</string>
- <string name="global_action_lock_message" product="tablet" msgid="7621167597240332986">"Mở khóa máy tính bảng của bạn để xem thêm tùy chọn"</string>
- <string name="global_action_lock_message" product="device" msgid="538790401275363781">"Mở khóa thiết bị của bạn để xem thêm tùy chọn"</string>
<string name="remote_input_image_insertion_text" msgid="4850791636452521123">"đã gửi hình ảnh"</string>
<string name="screenshot_saving_ticker" msgid="6519186952674544916">"Đang lưu ảnh chụp màn hình..."</string>
<string name="screenshot_saving_title" msgid="2298349784913287333">"Đang lưu ảnh chụp màn hình..."</string>
@@ -595,29 +592,21 @@
<string name="volume_odi_captions_hint_enable" msgid="2073091194012843195">"bật"</string>
<string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"tắt"</string>
<string name="accessibility_output_chooser" msgid="7807898688967194183">"Chuyển đổi thiết bị đầu ra"</string>
- <!-- no translation found for screen_pinning_title (9058007390337841305) -->
- <skip />
+ <string name="screen_pinning_title" msgid="9058007390337841305">"Đã ghim ứng dụng"</string>
<string name="screen_pinning_description" msgid="8699395373875667743">"Thao tác này sẽ duy trì hiển thị màn hình cho đến khi bạn bỏ ghim. Hãy chạm và giữ Quay lại và Tổng quan để bỏ ghim."</string>
<string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"Thao tác này sẽ duy trì hiển thị màn hình cho đến khi bạn bỏ ghim. Hãy chạm và giữ nút Quay lại và nút Màn hình chính để bỏ ghim."</string>
<string name="screen_pinning_description_gestural" msgid="7246323931831232068">"Màn hình tiếp tục hiển thị cho tới khi bạn bỏ ghim. Hãy vuốt lên và giữ để bỏ ghim."</string>
<string name="screen_pinning_description_accessible" msgid="7386449191953535332">"Thao tác này sẽ duy trì hiển thị màn hình cho đến khi bạn bỏ ghim. Hãy chạm và giữ Tổng quan để bỏ ghim."</string>
<string name="screen_pinning_description_recents_invisible_accessible" msgid="2857071808674481986">"Thao tác này sẽ duy trì hiển thị màn hình cho đến khi bạn bỏ ghim. Hãy chạm và giữ nút Màn hình chính để bỏ ghim."</string>
- <!-- no translation found for screen_pinning_exposes_personal_data (8189852022981524789) -->
- <skip />
- <!-- no translation found for screen_pinning_can_open_other_apps (7529756813231421455) -->
- <skip />
- <!-- no translation found for screen_pinning_toast (8177286912533744328) -->
- <skip />
- <!-- no translation found for screen_pinning_toast_recents_invisible (6850978077443052594) -->
- <skip />
- <!-- no translation found for screen_pinning_toast_gesture_nav (170699893395336705) -->
- <skip />
+ <string name="screen_pinning_exposes_personal_data" msgid="8189852022981524789">"Dữ liệu cá nhân có thể bị truy cập (chẳng hạn như danh bạ và nội dung email)."</string>
+ <string name="screen_pinning_can_open_other_apps" msgid="7529756813231421455">"Ứng dụng đã ghim có thể mở các ứng dụng khác."</string>
+ <string name="screen_pinning_toast" msgid="8177286912533744328">"Để bỏ ghim ứng dụng này, hãy chạm và giữ nút Quay lại và nút Tổng quan"</string>
+ <string name="screen_pinning_toast_recents_invisible" msgid="6850978077443052594">"Để bỏ ghim ứng dụng này, hãy chạm và giữ nút Quay lại và nút Màn hình chính"</string>
+ <string name="screen_pinning_toast_gesture_nav" msgid="170699893395336705">"Để bỏ ghim ứng dụng này, hãy vuốt lên và giữ"</string>
<string name="screen_pinning_positive" msgid="3285785989665266984">"Ok"</string>
<string name="screen_pinning_negative" msgid="6882816864569211666">"Không, cảm ơn"</string>
- <!-- no translation found for screen_pinning_start (7483998671383371313) -->
- <skip />
- <!-- no translation found for screen_pinning_exit (4553787518387346893) -->
- <skip />
+ <string name="screen_pinning_start" msgid="7483998671383371313">"Đã ghim ứng dụng"</string>
+ <string name="screen_pinning_exit" msgid="4553787518387346893">"Đã bỏ ghim ứng dụng"</string>
<string name="quick_settings_reset_confirmation_title" msgid="463533331480997595">"Ẩn <xliff:g id="TILE_LABEL">%1$s</xliff:g>?"</string>
<string name="quick_settings_reset_confirmation_message" msgid="2320586180785674186">"Thông báo này sẽ xuất hiện lại vào lần tiếp theo bạn bật thông báo trong cài đặt."</string>
<string name="quick_settings_reset_confirmation_button" msgid="3341477479055016776">"Ẩn"</string>
@@ -724,13 +713,13 @@
<string name="notification_bubble_title" msgid="8330481035191903164">"Bong bóng"</string>
<string name="notification_channel_summary_low" msgid="4860617986908931158">"Không phát âm thanh hoặc rung"</string>
<string name="notification_conversation_summary_low" msgid="1734433426085468009">"Không phát âm thanh hoặc rung và xuất hiện phía dưới trong phần cuộc trò chuyện"</string>
- <string name="notification_channel_summary_default" msgid="3282930979307248890">"Có thể đổ chuông hoặc rung tùy theo phần cài đặt trên điện thoại"</string>
- <string name="notification_channel_summary_default_with_bubbles" msgid="1782419896613644568">"Có thể đổ chuông hoặc rung tùy theo phần cài đặt trên điện thoại. Theo mặc định, các cuộc trò chuyện từ <xliff:g id="APP_NAME">%1$s</xliff:g> được phép hiển thị dưới dạng bong bóng."</string>
+ <string name="notification_channel_summary_default" msgid="3282930979307248890">"Có thể đổ chuông hoặc rung tùy theo chế độ cài đặt trên điện thoại"</string>
+ <string name="notification_channel_summary_default_with_bubbles" msgid="1782419896613644568">"Có thể đổ chuông hoặc rung tùy theo chế độ cài đặt trên điện thoại. Theo mặc định, các cuộc trò chuyện từ <xliff:g id="APP_NAME">%1$s</xliff:g> được phép hiển thị dưới dạng bong bóng."</string>
<string name="notification_channel_summary_bubble" msgid="7235935211580860537">"Luôn chú ý vào nội dung này bằng phím tắt nổi."</string>
<string name="notification_channel_summary_priority" msgid="7952654515769021553">"Hiển thị cuộc trò chuyện ở đầu phần cuộc trò chuyện và dưới dạng bong bóng nổi, hiển thị ảnh hồ sơ trên màn hình khóa"</string>
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"Cài đặt"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"Mức độ ưu tiên"</string>
- <string name="no_shortcut" msgid="7176375126961212514">"Ứng dụng <xliff:g id="APP_NAME">%1$s</xliff:g> không hỗ trợ tùy chọn cài đặt dành riêng cho cuộc trò chuyệ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>
<string name="bubble_overflow_empty_title" msgid="3120029421991510842">"Không có bong bóng trò chuyện nào gần đây"</string>
<string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"Bong bóng trò chuyện đã đóng và bong bóng trò chuyện gần đây sẽ xuất hiện ở đây"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"Không thể sửa đổi các thông báo này."</string>
@@ -1013,7 +1002,8 @@
<string name="bubble_accessibility_action_move_top_right" msgid="6916868852433483569">"Chuyển lên trên cùng bên phải"</string>
<string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"Chuyển tới dưới cùng bên trái"</string>
<string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"Chuyển tới dưới cùng bên phải"</string>
- <string name="bubble_dismiss_text" msgid="7071770411580452911">"Loại bỏ"</string>
+ <!-- no translation found for bubble_dismiss_text (1314082410868930066) -->
+ <skip />
<string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"Dừng trò chuyện bằng bong bóng"</string>
<string name="bubbles_user_education_title" msgid="5547017089271445797">"Trò chuyện bằng bong bóng trò chuyện"</string>
<string name="bubbles_user_education_description" msgid="1160281719576715211">"Các cuộc trò chuyện mới hiển thị dưới dạng biểu tượng nổi hoặc bong bóng trò chuyện. Nhấn để mở bong bóng trò chuyện. Kéo để di chuyển bong bóng trò chuyện."</string>
@@ -1024,11 +1014,14 @@
<string name="notification_content_system_nav_changed" msgid="5077913144844684544">"Đã cập nhật chế độ di chuyển trên hệ thống. Để thay đổi, hãy chuyển đến phần Cài đặt."</string>
<string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"Chuyển đến phần Cài đặt để cập nhật chế độ di chuyển trên hệ thống"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Chế độ chờ"</string>
+ <string name="priority_onboarding_title" msgid="2893070698479227616">"Đặt cuộc trò chuyện thành ưu tiên"</string>
+ <string name="priority_onboarding_behavior" msgid="5342816047020432929">"Cuộc trò chuyện ưu tiên sẽ:"</string>
<string name="priority_onboarding_show_at_top_text" msgid="1678400241025513541">"Hiển thị ở đầu phần cuộc trò chuyện"</string>
<string name="priority_onboarding_show_avatar_text" msgid="5756291381124091508">"Hiển thị ảnh hồ sơ trên màn hình khóa"</string>
<string name="priority_onboarding_appear_as_bubble_text" msgid="4227039772250263122">"Hiện ở dạng bong bóng nổi ở trên cùng của ứng dụng"</string>
<string name="priority_onboarding_ignores_dnd_text" msgid="2918952762719600529">"Làm gián đoạn chế độ Không làm phiền"</string>
<string name="priority_onboarding_done_button_title" msgid="4569550984286506007">"OK"</string>
+ <string name="priority_onboarding_settings_button_title" msgid="6663601574303585927">"Cài đặt"</string>
<string name="magnification_overlay_title" msgid="6584179429612427958">"Cửa sổ lớp phủ phóng to"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"Cửa sổ phóng to"</string>
<string name="magnification_controls_title" msgid="8421106606708891519">"Các tùy chọn điều khiển cửa sổ phóng to"</string>
@@ -1070,9 +1063,13 @@
<string name="controls_structure_tooltip" msgid="4355922222944447867">"Vuốt để xem thêm"</string>
<string name="controls_seeding_in_progress" msgid="3033855341410264148">"Đang tải các đề xuất"</string>
<string name="controls_media_close_session" msgid="9023534788828414585">"Đóng phiên đa phương tiện này"</string>
+ <string name="controls_media_resume" msgid="1933520684481586053">"Tiếp tục"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"Không hoạt động, hãy kiểm tra ứng dụng"</string>
<string name="controls_error_retryable" msgid="864025882878378470">"Lỗi, đang thử lại…"</string>
- <string name="controls_error_removed" msgid="6299213591234723805">"Đã xóa thiết bị"</string>
+ <string name="controls_error_removed" msgid="6675638069846014366">"Không tìm thấy"</string>
+ <string name="controls_error_removed_title" msgid="1207794911208047818">"Không có chức năng điều khiển"</string>
+ <string name="controls_error_removed_message" msgid="2885911717034750542">"Không thể sử dụng <xliff:g id="DEVICE">%1$s</xliff:g>. Hãy kiểm tra ứng dụng <xliff:g id="APPLICATION">%2$s</xliff:g> để đảm bảo rằng vẫn chức năng điều khiển vẫn dùng được và thông tin cài đặt của ứng dụng chưa thay đổi."</string>
+ <string name="controls_open_app" msgid="483650971094300141">"Mở ứng dụng"</string>
<string name="controls_error_generic" msgid="352500456918362905">"Không tải được trạng thái"</string>
<string name="controls_error_failed" msgid="960228639198558525">"Lỗi, hãy thử lại"</string>
<string name="controls_in_progress" msgid="4421080500238215939">"Đang thực hiện"</string>
diff --git a/packages/SystemUI/res/values-zh-rCN/strings.xml b/packages/SystemUI/res/values-zh-rCN/strings.xml
index 970d21843616..86f43c9d55f0 100644
--- a/packages/SystemUI/res/values-zh-rCN/strings.xml
+++ b/packages/SystemUI/res/values-zh-rCN/strings.xml
@@ -77,9 +77,6 @@
<string name="compat_mode_on" msgid="4963711187149440884">"缩放以填满屏幕"</string>
<string name="compat_mode_off" msgid="7682459748279487945">"拉伸以填满屏幕"</string>
<string name="global_action_screenshot" msgid="2760267567509131654">"屏幕截图"</string>
- <string name="global_action_lock_message" product="default" msgid="4466026255205186456">"解锁手机即可查看更多选项"</string>
- <string name="global_action_lock_message" product="tablet" msgid="7621167597240332986">"解锁平板电脑即可查看更多选项"</string>
- <string name="global_action_lock_message" product="device" msgid="538790401275363781">"解锁设备即可查看更多选项"</string>
<string name="remote_input_image_insertion_text" msgid="4850791636452521123">"发送了一张图片"</string>
<string name="screenshot_saving_ticker" msgid="6519186952674544916">"正在保存屏幕截图..."</string>
<string name="screenshot_saving_title" msgid="2298349784913287333">"正在保存屏幕截图..."</string>
@@ -595,29 +592,21 @@
<string name="volume_odi_captions_hint_enable" msgid="2073091194012843195">"启用"</string>
<string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"停用"</string>
<string name="accessibility_output_chooser" msgid="7807898688967194183">"切换输出设备"</string>
- <!-- no translation found for screen_pinning_title (9058007390337841305) -->
- <skip />
+ <string name="screen_pinning_title" msgid="9058007390337841305">"应用已固定"</string>
<string name="screen_pinning_description" msgid="8699395373875667743">"这将会固定显示此屏幕,直到您取消固定为止。触摸并按住“返回”和“概览”即可取消固定屏幕。"</string>
<string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"这将会固定显示此屏幕,直到您取消固定为止。触摸并按住“返回”和“主屏幕”即可取消固定屏幕。"</string>
<string name="screen_pinning_description_gestural" msgid="7246323931831232068">"这会使此屏幕固定显示,直到您取消固定为止。向上滑动并按住即可取消固定。"</string>
<string name="screen_pinning_description_accessible" msgid="7386449191953535332">"这将会固定显示此屏幕,直到您取消固定为止。触摸并按住“概览”即可取消固定屏幕。"</string>
<string name="screen_pinning_description_recents_invisible_accessible" msgid="2857071808674481986">"这将会固定显示此屏幕,直到您取消固定为止。触摸并按住“主屏幕”即可取消固定屏幕。"</string>
- <!-- no translation found for screen_pinning_exposes_personal_data (8189852022981524789) -->
- <skip />
- <!-- no translation found for screen_pinning_can_open_other_apps (7529756813231421455) -->
- <skip />
- <!-- no translation found for screen_pinning_toast (8177286912533744328) -->
- <skip />
- <!-- no translation found for screen_pinning_toast_recents_invisible (6850978077443052594) -->
- <skip />
- <!-- no translation found for screen_pinning_toast_gesture_nav (170699893395336705) -->
- <skip />
+ <string name="screen_pinning_exposes_personal_data" msgid="8189852022981524789">"可访问个人数据(例如通讯录和电子邮件内容)。"</string>
+ <string name="screen_pinning_can_open_other_apps" msgid="7529756813231421455">"固定的应用可打开其他应用。"</string>
+ <string name="screen_pinning_toast" msgid="8177286912533744328">"如需取消固定此应用,请轻触并按住“返回”按钮和“概览”按钮"</string>
+ <string name="screen_pinning_toast_recents_invisible" msgid="6850978077443052594">"如需取消固定此应用,请轻触并按住“返回”按钮和主屏幕按钮"</string>
+ <string name="screen_pinning_toast_gesture_nav" msgid="170699893395336705">"如需取消固定此应用,请向上滑动并按住"</string>
<string name="screen_pinning_positive" msgid="3285785989665266984">"知道了"</string>
<string name="screen_pinning_negative" msgid="6882816864569211666">"不用了"</string>
- <!-- no translation found for screen_pinning_start (7483998671383371313) -->
- <skip />
- <!-- no translation found for screen_pinning_exit (4553787518387346893) -->
- <skip />
+ <string name="screen_pinning_start" msgid="7483998671383371313">"已固定应用"</string>
+ <string name="screen_pinning_exit" msgid="4553787518387346893">"已取消固定应用"</string>
<string name="quick_settings_reset_confirmation_title" msgid="463533331480997595">"要隐藏“<xliff:g id="TILE_LABEL">%1$s</xliff:g>”吗?"</string>
<string name="quick_settings_reset_confirmation_message" msgid="2320586180785674186">"下次在设置中将其开启后,此快捷设置条目将会重新显示。"</string>
<string name="quick_settings_reset_confirmation_button" msgid="3341477479055016776">"隐藏"</string>
@@ -722,15 +711,15 @@
<string name="notification_silence_title" msgid="8608090968400832335">"静音"</string>
<string name="notification_alert_title" msgid="3656229781017543655">"默认"</string>
<string name="notification_bubble_title" msgid="8330481035191903164">"气泡"</string>
- <string name="notification_channel_summary_low" msgid="4860617986908931158">"不发出提示音也不振动"</string>
- <string name="notification_conversation_summary_low" msgid="1734433426085468009">"不发出提示音也不振动,显示在对话部分的靠下位置"</string>
+ <string name="notification_channel_summary_low" msgid="4860617986908931158">"不发出提示音,也不振动"</string>
+ <string name="notification_conversation_summary_low" msgid="1734433426085468009">"不发出提示音,也不振动;显示在对话部分的靠下位置"</string>
<string name="notification_channel_summary_default" msgid="3282930979307248890">"可能会响铃或振动(取决于手机设置)"</string>
<string name="notification_channel_summary_default_with_bubbles" msgid="1782419896613644568">"可能会响铃或振动(取决于手机设置)。默认情况下,来自<xliff:g id="APP_NAME">%1$s</xliff:g>的对话会以对话泡的形式显示。"</string>
<string name="notification_channel_summary_bubble" msgid="7235935211580860537">"通过可链接到这项内容的浮动快捷方式吸引您的注意。"</string>
<string name="notification_channel_summary_priority" msgid="7952654515769021553">"以悬浮对话泡形式显示在对话部分顶部,如果设备处于锁定状态,在锁定屏幕上显示个人资料照片"</string>
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"设置"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"优先"</string>
- <string name="no_shortcut" msgid="7176375126961212514">"<xliff:g id="APP_NAME">%1$s</xliff:g>不支持对话专用设置"</string>
+ <string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g>不支持对话功能"</string>
<string name="bubble_overflow_empty_title" msgid="3120029421991510842">"最近没有对话泡"</string>
<string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"此处会显示最近的对话泡和已关闭的对话泡"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"无法修改这些通知。"</string>
@@ -1013,7 +1002,8 @@
<string name="bubble_accessibility_action_move_top_right" msgid="6916868852433483569">"移至右上角"</string>
<string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"移至左下角"</string>
<string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"移至右下角"</string>
- <string name="bubble_dismiss_text" msgid="7071770411580452911">"关闭"</string>
+ <!-- no translation found for bubble_dismiss_text (1314082410868930066) -->
+ <skip />
<string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"不以对话泡形式显示对话"</string>
<string name="bubbles_user_education_title" msgid="5547017089271445797">"使用对话泡聊天"</string>
<string name="bubbles_user_education_description" msgid="1160281719576715211">"新对话会以浮动图标或对话泡形式显示。点按即可打开对话泡。拖动即可移动对话泡。"</string>
@@ -1024,19 +1014,22 @@
<string name="notification_content_system_nav_changed" msgid="5077913144844684544">"系统导航已更新。要进行更改,请转到“设置”。"</string>
<string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"转到“设置”即可更新系统导航"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"待机"</string>
+ <string name="priority_onboarding_title" msgid="2893070698479227616">"已设置为优先对话"</string>
+ <string name="priority_onboarding_behavior" msgid="5342816047020432929">"优先对话将:"</string>
<string name="priority_onboarding_show_at_top_text" msgid="1678400241025513541">"显示在对话部分顶部"</string>
<string name="priority_onboarding_show_avatar_text" msgid="5756291381124091508">"在锁定屏幕上显示个人资料照片"</string>
<string name="priority_onboarding_appear_as_bubble_text" msgid="4227039772250263122">"以悬浮对话泡的形式显示在应用之上"</string>
<string name="priority_onboarding_ignores_dnd_text" msgid="2918952762719600529">"中断勿扰模式"</string>
<string name="priority_onboarding_done_button_title" msgid="4569550984286506007">"知道了"</string>
+ <string name="priority_onboarding_settings_button_title" msgid="6663601574303585927">"设置"</string>
<string name="magnification_overlay_title" msgid="6584179429612427958">"放大叠加窗口"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"放大窗口"</string>
<string name="magnification_controls_title" msgid="8421106606708891519">"放大窗口控件"</string>
- <string name="quick_controls_title" msgid="6839108006171302273">"设备控制器"</string>
+ <string name="quick_controls_title" msgid="6839108006171302273">"设备控件"</string>
<string name="quick_controls_subtitle" msgid="1667408093326318053">"为您所连接的设备添加控件"</string>
- <string name="quick_controls_setup_title" msgid="8901436655997849822">"设置设备控制器"</string>
+ <string name="quick_controls_setup_title" msgid="8901436655997849822">"设置设备控件"</string>
<string name="quick_controls_setup_subtitle" msgid="1681506617879773824">"按住电源按钮即可访问您的控件"</string>
- <string name="controls_providers_title" msgid="6879775889857085056">"选择应用以添加控件"</string>
+ <string name="controls_providers_title" msgid="6879775889857085056">"选择要添加控制器的应用"</string>
<plurals name="controls_number_of_favorites" formatted="false" msgid="1057347832073807380">
<item quantity="other">已添加 <xliff:g id="NUMBER_1">%s</xliff:g> 个控件。</item>
<item quantity="one">已添加 <xliff:g id="NUMBER_0">%s</xliff:g> 个控件。</item>
@@ -1055,7 +1048,7 @@
<string name="controls_favorite_toast_no_changes" msgid="7094494210840877931">"未保存更改"</string>
<string name="controls_favorite_load_error" msgid="2533215155804455348">"无法加载所有控件的列表。"</string>
<string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"其他"</string>
- <string name="controls_dialog_title" msgid="2343565267424406202">"添加到设备控制器"</string>
+ <string name="controls_dialog_title" msgid="2343565267424406202">"添加到设备控件"</string>
<string name="controls_dialog_ok" msgid="2770230012857881822">"添加"</string>
<string name="controls_dialog_message" msgid="342066938390663844">"来自<xliff:g id="APP">%s</xliff:g>的建议"</string>
<string name="controls_dialog_confirmation" msgid="586517302736263447">"控件已更新"</string>
@@ -1070,9 +1063,13 @@
<string name="controls_structure_tooltip" msgid="4355922222944447867">"滑动可查看更多结构"</string>
<string name="controls_seeding_in_progress" msgid="3033855341410264148">"正在加载推荐内容"</string>
<string name="controls_media_close_session" msgid="9023534788828414585">"关闭此媒体会话"</string>
+ <string name="controls_media_resume" msgid="1933520684481586053">"继续播放"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"无效,请检查应用"</string>
<string name="controls_error_retryable" msgid="864025882878378470">"出现错误,正在重试…"</string>
- <string name="controls_error_removed" msgid="6299213591234723805">"设备已移除"</string>
+ <string name="controls_error_removed" msgid="6675638069846014366">"未找到"</string>
+ <string name="controls_error_removed_title" msgid="1207794911208047818">"控件不可用"</string>
+ <string name="controls_error_removed_message" msgid="2885911717034750542">"无法访问<xliff:g id="DEVICE">%1$s</xliff:g>。请查看<xliff:g id="APPLICATION">%2$s</xliff:g>应用,确保其中仍有该控件,并且应用设置没有更改。"</string>
+ <string name="controls_open_app" msgid="483650971094300141">"打开应用"</string>
<string name="controls_error_generic" msgid="352500456918362905">"无法加载状态"</string>
<string name="controls_error_failed" msgid="960228639198558525">"出现错误,请重试"</string>
<string name="controls_in_progress" msgid="4421080500238215939">"正在进行"</string>
diff --git a/packages/SystemUI/res/values-zh-rHK/strings.xml b/packages/SystemUI/res/values-zh-rHK/strings.xml
index 909336451d95..6d9ee9913981 100644
--- a/packages/SystemUI/res/values-zh-rHK/strings.xml
+++ b/packages/SystemUI/res/values-zh-rHK/strings.xml
@@ -77,9 +77,6 @@
<string name="compat_mode_on" msgid="4963711187149440884">"放大為全螢幕"</string>
<string name="compat_mode_off" msgid="7682459748279487945">"放大為全螢幕"</string>
<string name="global_action_screenshot" msgid="2760267567509131654">"螢幕截圖"</string>
- <string name="global_action_lock_message" product="default" msgid="4466026255205186456">"解鎖手機以存取更多選項"</string>
- <string name="global_action_lock_message" product="tablet" msgid="7621167597240332986">"解鎖平板電腦以存取更多選項"</string>
- <string name="global_action_lock_message" product="device" msgid="538790401275363781">"解鎖裝置以存取更多選項"</string>
<string name="remote_input_image_insertion_text" msgid="4850791636452521123">"已傳送圖片"</string>
<string name="screenshot_saving_ticker" msgid="6519186952674544916">"正在儲存螢幕擷取畫面..."</string>
<string name="screenshot_saving_title" msgid="2298349784913287333">"正在儲存螢幕擷取畫面..."</string>
@@ -595,29 +592,21 @@
<string name="volume_odi_captions_hint_enable" msgid="2073091194012843195">"啟用"</string>
<string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"停用"</string>
<string name="accessibility_output_chooser" msgid="7807898688967194183">"切換輸出裝置"</string>
- <!-- no translation found for screen_pinning_title (9058007390337841305) -->
- <skip />
+ <string name="screen_pinning_title" msgid="9058007390337841305">"已固定應用程式"</string>
<string name="screen_pinning_description" msgid="8699395373875667743">"畫面將會繼續顯示,直至您取消固定。按住 [返回] 和 [概覽] 即可取消固定。"</string>
<string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"畫面將會繼續顯示,直至您取消固定為止。按住 [返回] 按鈕和主按鈕即可取消固定。"</string>
<string name="screen_pinning_description_gestural" msgid="7246323931831232068">"畫面將會繼續顯示,直至您取消固定為止。向上滑動並按住即可取消固定。"</string>
<string name="screen_pinning_description_accessible" msgid="7386449191953535332">"畫面將會繼續顯示,直至您取消固定。按住 [概覽] 即可取消固定。"</string>
<string name="screen_pinning_description_recents_invisible_accessible" msgid="2857071808674481986">"畫面將會繼續顯示,直至您取消固定為止。按住主按鈕即可取消固定。"</string>
- <!-- no translation found for screen_pinning_exposes_personal_data (8189852022981524789) -->
- <skip />
- <!-- no translation found for screen_pinning_can_open_other_apps (7529756813231421455) -->
- <skip />
- <!-- no translation found for screen_pinning_toast (8177286912533744328) -->
- <skip />
- <!-- no translation found for screen_pinning_toast_recents_invisible (6850978077443052594) -->
- <skip />
- <!-- no translation found for screen_pinning_toast_gesture_nav (170699893395336705) -->
- <skip />
+ <string name="screen_pinning_exposes_personal_data" msgid="8189852022981524789">"該應用程式可存取個人資料 (例如聯絡人和電郵內容)。"</string>
+ <string name="screen_pinning_can_open_other_apps" msgid="7529756813231421455">"固定的應用程式可開啟其他應用程式。"</string>
+ <string name="screen_pinning_toast" msgid="8177286912533744328">"如要取消固定此應用程式,請按住「返回」按鈕和「概覽」按鈕"</string>
+ <string name="screen_pinning_toast_recents_invisible" msgid="6850978077443052594">"如要取消固定此應用程式,請按住「返回」按鈕和主按鈕"</string>
+ <string name="screen_pinning_toast_gesture_nav" msgid="170699893395336705">"如要取消固定此應用程式,請向上滑動並按住"</string>
<string name="screen_pinning_positive" msgid="3285785989665266984">"知道了"</string>
<string name="screen_pinning_negative" msgid="6882816864569211666">"不用了,謝謝"</string>
- <!-- no translation found for screen_pinning_start (7483998671383371313) -->
- <skip />
- <!-- no translation found for screen_pinning_exit (4553787518387346893) -->
- <skip />
+ <string name="screen_pinning_start" msgid="7483998671383371313">"已固定應用程式"</string>
+ <string name="screen_pinning_exit" msgid="4553787518387346893">"已取消固定應用程式"</string>
<string name="quick_settings_reset_confirmation_title" msgid="463533331480997595">"隱藏 <xliff:g id="TILE_LABEL">%1$s</xliff:g>?"</string>
<string name="quick_settings_reset_confirmation_message" msgid="2320586180785674186">"下一次您在設定開啟它時,它將再次出現。"</string>
<string name="quick_settings_reset_confirmation_button" msgid="3341477479055016776">"隱藏"</string>
@@ -730,7 +719,7 @@
<string name="notification_channel_summary_priority" msgid="7952654515769021553">"在對話部分的頂部以浮動對話氣泡顯示,並在上鎖畫面顯示個人檔案相片"</string>
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"設定"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"重要"</string>
- <string name="no_shortcut" msgid="7176375126961212514">"「<xliff:g id="APP_NAME">%1$s</xliff:g>」不支援對話專用設定"</string>
+ <string name="no_shortcut" msgid="8257177117568230126">"「<xliff:g id="APP_NAME">%1$s</xliff:g>」不支援對話功能"</string>
<string name="bubble_overflow_empty_title" msgid="3120029421991510842">"沒有最近曾使用的小視窗"</string>
<string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"最近使用和關閉的小視窗會在這裡顯示"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"無法修改這些通知。"</string>
@@ -1013,7 +1002,8 @@
<string name="bubble_accessibility_action_move_top_right" msgid="6916868852433483569">"移去右上角"</string>
<string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"移去左下角"</string>
<string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"移去右下角"</string>
- <string name="bubble_dismiss_text" msgid="7071770411580452911">"關閉"</string>
+ <!-- no translation found for bubble_dismiss_text (1314082410868930066) -->
+ <skip />
<string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"不要透過小視窗顯示對話"</string>
<string name="bubbles_user_education_title" msgid="5547017089271445797">"使用小視窗進行即時通訊"</string>
<string name="bubbles_user_education_description" msgid="1160281719576715211">"新對話會以浮動圖示 (小視窗) 顯示。輕按即可開啟小視窗。拖曳即可移動小視窗。"</string>
@@ -1024,11 +1014,14 @@
<string name="notification_content_system_nav_changed" msgid="5077913144844684544">"系統導覽已更新。如需變更,請前往「設定」。"</string>
<string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"前往「設定」更新系統導覽"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"待機"</string>
+ <string name="priority_onboarding_title" msgid="2893070698479227616">"對話已設為優先"</string>
+ <string name="priority_onboarding_behavior" msgid="5342816047020432929">"優先對話將會:"</string>
<string name="priority_onboarding_show_at_top_text" msgid="1678400241025513541">"在對話部分的頂部顯示"</string>
<string name="priority_onboarding_show_avatar_text" msgid="5756291381124091508">"在上鎖畫面顯示個人檔案相片"</string>
<string name="priority_onboarding_appear_as_bubble_text" msgid="4227039772250263122">"在應用程式上以浮動小視窗顯示"</string>
<string name="priority_onboarding_ignores_dnd_text" msgid="2918952762719600529">"中斷「請勿騷擾」"</string>
<string name="priority_onboarding_done_button_title" msgid="4569550984286506007">"知道了"</string>
+ <string name="priority_onboarding_settings_button_title" msgid="6663601574303585927">"設定"</string>
<string name="magnification_overlay_title" msgid="6584179429612427958">"放大重疊視窗"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"放大視窗"</string>
<string name="magnification_controls_title" msgid="8421106606708891519">"放大視窗控制項"</string>
@@ -1036,7 +1029,7 @@
<string name="quick_controls_subtitle" msgid="1667408093326318053">"為已連接的裝置新增控制項"</string>
<string name="quick_controls_setup_title" msgid="8901436655997849822">"設定裝置控制"</string>
<string name="quick_controls_setup_subtitle" msgid="1681506617879773824">"按住「開關」按鈕便可存取控制項"</string>
- <string name="controls_providers_title" msgid="6879775889857085056">"選擇應用程式以新增控制項"</string>
+ <string name="controls_providers_title" msgid="6879775889857085056">"選擇要新增控制項的應用程式"</string>
<plurals name="controls_number_of_favorites" formatted="false" msgid="1057347832073807380">
<item quantity="other">已新增 <xliff:g id="NUMBER_1">%s</xliff:g> 個控制項。</item>
<item quantity="one">已新增 <xliff:g id="NUMBER_0">%s</xliff:g> 個控制項。</item>
@@ -1049,7 +1042,7 @@
<string name="accessibility_control_change_unfavorite" msgid="6997408061750740327">"取消收藏"</string>
<string name="accessibility_control_move" msgid="8980344493796647792">"移至位置 <xliff:g id="NUMBER">%d</xliff:g>"</string>
<string name="controls_favorite_default_title" msgid="967742178688938137">"控制項"</string>
- <string name="controls_favorite_subtitle" msgid="6604402232298443956">"從電源選單選擇要存取的控制項"</string>
+ <string name="controls_favorite_subtitle" msgid="6604402232298443956">"選擇可從電源選單使用的控制項"</string>
<string name="controls_favorite_rearrange" msgid="5616952398043063519">"按住並拖曳便可重新排列控制項"</string>
<string name="controls_favorite_removed" msgid="5276978408529217272">"已移除所有控制項"</string>
<string name="controls_favorite_toast_no_changes" msgid="7094494210840877931">"未儲存變更"</string>
@@ -1070,9 +1063,13 @@
<string name="controls_structure_tooltip" msgid="4355922222944447867">"滑動以查看更多"</string>
<string name="controls_seeding_in_progress" msgid="3033855341410264148">"正在載入建議"</string>
<string name="controls_media_close_session" msgid="9023534788828414585">"關閉此媒體版面"</string>
+ <string name="controls_media_resume" msgid="1933520684481586053">"繼續播放"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"已停用,請檢查應用程式"</string>
<string name="controls_error_retryable" msgid="864025882878378470">"發生錯誤,正在重試…"</string>
- <string name="controls_error_removed" msgid="6299213591234723805">"已移除裝置"</string>
+ <string name="controls_error_removed" msgid="6675638069846014366">"找不到"</string>
+ <string name="controls_error_removed_title" msgid="1207794911208047818">"無法使用控制功能"</string>
+ <string name="controls_error_removed_message" msgid="2885911717034750542">"無法存取 <xliff:g id="DEVICE">%1$s</xliff:g>。請檢查 <xliff:g id="APPLICATION">%2$s</xliff:g> 應用程式,確定控制功能仍可使用,同時應用程式設定並無變更。"</string>
+ <string name="controls_open_app" msgid="483650971094300141">"開啟應用程式"</string>
<string name="controls_error_generic" msgid="352500456918362905">"無法載入狀態"</string>
<string name="controls_error_failed" msgid="960228639198558525">"發生錯誤,請再試一次"</string>
<string name="controls_in_progress" msgid="4421080500238215939">"進行中"</string>
diff --git a/packages/SystemUI/res/values-zh-rTW/strings.xml b/packages/SystemUI/res/values-zh-rTW/strings.xml
index f93464c71c00..11e2be069a2f 100644
--- a/packages/SystemUI/res/values-zh-rTW/strings.xml
+++ b/packages/SystemUI/res/values-zh-rTW/strings.xml
@@ -77,9 +77,6 @@
<string name="compat_mode_on" msgid="4963711187149440884">"放大為全螢幕"</string>
<string name="compat_mode_off" msgid="7682459748279487945">"放大為全螢幕"</string>
<string name="global_action_screenshot" msgid="2760267567509131654">"擷取螢幕畫面"</string>
- <string name="global_action_lock_message" product="default" msgid="4466026255205186456">"解鎖手機可查看更多選項"</string>
- <string name="global_action_lock_message" product="tablet" msgid="7621167597240332986">"解鎖平板電腦可查看更多選項"</string>
- <string name="global_action_lock_message" product="device" msgid="538790401275363781">"解鎖裝置可查看更多選項"</string>
<string name="remote_input_image_insertion_text" msgid="4850791636452521123">"傳送了一張圖片"</string>
<string name="screenshot_saving_ticker" msgid="6519186952674544916">"正在儲存螢幕截圖…"</string>
<string name="screenshot_saving_title" msgid="2298349784913287333">"正在儲存螢幕截圖…"</string>
@@ -595,29 +592,21 @@
<string name="volume_odi_captions_hint_enable" msgid="2073091194012843195">"啟用"</string>
<string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"停用"</string>
<string name="accessibility_output_chooser" msgid="7807898688967194183">"切換輸出裝置"</string>
- <!-- no translation found for screen_pinning_title (9058007390337841305) -->
- <skip />
+ <string name="screen_pinning_title" msgid="9058007390337841305">"應用程式已固定"</string>
<string name="screen_pinning_description" msgid="8699395373875667743">"這會讓目前的螢幕畫面保持顯示狀態,直到取消固定為止。按住 [返回] 按鈕和 [總覽] 按鈕即可取消固定。"</string>
<string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"這會讓應用程式顯示在螢幕上,直到取消固定為止。按住 [返回] 按鈕和主螢幕按鈕即可取消固定。"</string>
<string name="screen_pinning_description_gestural" msgid="7246323931831232068">"這會讓目前的螢幕畫面保持顯示狀態,直到取消固定為止。向上滑動並按住即可取消固定。"</string>
<string name="screen_pinning_description_accessible" msgid="7386449191953535332">"這會讓目前的螢幕畫面保持顯示狀態,直到取消固定為止。按住 [總覽] 按鈕即可取消固定。"</string>
<string name="screen_pinning_description_recents_invisible_accessible" msgid="2857071808674481986">"這會讓應用程式顯示在螢幕上,直到取消固定為止。按住主螢幕按鈕即可取消固定。"</string>
- <!-- no translation found for screen_pinning_exposes_personal_data (8189852022981524789) -->
- <skip />
- <!-- no translation found for screen_pinning_can_open_other_apps (7529756813231421455) -->
- <skip />
- <!-- no translation found for screen_pinning_toast (8177286912533744328) -->
- <skip />
- <!-- no translation found for screen_pinning_toast_recents_invisible (6850978077443052594) -->
- <skip />
- <!-- no translation found for screen_pinning_toast_gesture_nav (170699893395336705) -->
- <skip />
+ <string name="screen_pinning_exposes_personal_data" msgid="8189852022981524789">"個人資料 (例如聯絡人和電子郵件內容) 可能會遭存取。"</string>
+ <string name="screen_pinning_can_open_other_apps" msgid="7529756813231421455">"已設為固定的應用程式或許仍可開啟其他應用程式。"</string>
+ <string name="screen_pinning_toast" msgid="8177286912533744328">"如要取消固定這個應用程式,請按住「返回」按鈕和「總覽」按鈕"</string>
+ <string name="screen_pinning_toast_recents_invisible" msgid="6850978077443052594">"如要取消固定這個應用程式,請按住「返回」按鈕和主畫面按鈕"</string>
+ <string name="screen_pinning_toast_gesture_nav" msgid="170699893395336705">"如要取消固定這個應用程式,請向上滑動並按住"</string>
<string name="screen_pinning_positive" msgid="3285785989665266984">"知道了"</string>
<string name="screen_pinning_negative" msgid="6882816864569211666">"不用了,謝謝"</string>
- <!-- no translation found for screen_pinning_start (7483998671383371313) -->
- <skip />
- <!-- no translation found for screen_pinning_exit (4553787518387346893) -->
- <skip />
+ <string name="screen_pinning_start" msgid="7483998671383371313">"已固定應用程式"</string>
+ <string name="screen_pinning_exit" msgid="4553787518387346893">"已取消固定應用程式"</string>
<string name="quick_settings_reset_confirmation_title" msgid="463533331480997595">"隱藏<xliff:g id="TILE_LABEL">%1$s</xliff:g>?"</string>
<string name="quick_settings_reset_confirmation_message" msgid="2320586180785674186">"只要在設定頁面中重新啟用,就能再次看到快捷設定選項。"</string>
<string name="quick_settings_reset_confirmation_button" msgid="3341477479055016776">"隱藏"</string>
@@ -724,13 +713,13 @@
<string name="notification_bubble_title" msgid="8330481035191903164">"泡泡"</string>
<string name="notification_channel_summary_low" msgid="4860617986908931158">"不震動或發出聲音"</string>
<string name="notification_conversation_summary_low" msgid="1734433426085468009">"不震動或發出聲音,並顯示在對話部分的下方"</string>
- <string name="notification_channel_summary_default" msgid="3282930979307248890">"可能會根據手機的設定響鈴或震動"</string>
+ <string name="notification_channel_summary_default" msgid="3282930979307248890">"根據手機的設定響鈴或震動"</string>
<string name="notification_channel_summary_default_with_bubbles" msgid="1782419896613644568">"可能會根據手機的設定響鈴或震動。根據預設,來自「<xliff:g id="APP_NAME">%1$s</xliff:g>」的對話會以對話框形式顯示。"</string>
<string name="notification_channel_summary_bubble" msgid="7235935211580860537">"利用浮動式捷徑快速存取這項內容。"</string>
<string name="notification_channel_summary_priority" msgid="7952654515769021553">"以浮動對話框的形式顯示在對話部分的頂端。如果裝置處於鎖定狀態,則在螢幕鎖定畫面上顯示個人資料相片"</string>
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"設定"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"優先"</string>
- <string name="no_shortcut" msgid="7176375126961212514">"「<xliff:g id="APP_NAME">%1$s</xliff:g>」不支援對話專用設定"</string>
+ <string name="no_shortcut" msgid="8257177117568230126">"「<xliff:g id="APP_NAME">%1$s</xliff:g>」不支援對話功能"</string>
<string name="bubble_overflow_empty_title" msgid="3120029421991510842">"最近沒有任何對話框"</string>
<string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"最近的對話框和已關閉的對話框會顯示在這裡"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"無法修改這些通知。"</string>
@@ -1013,7 +1002,8 @@
<string name="bubble_accessibility_action_move_top_right" msgid="6916868852433483569">"移至右上方"</string>
<string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"移至左下方"</string>
<string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"移至右下方"</string>
- <string name="bubble_dismiss_text" msgid="7071770411580452911">"關閉"</string>
+ <!-- no translation found for bubble_dismiss_text (1314082410868930066) -->
+ <skip />
<string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"不要以對話框形式顯示對話"</string>
<string name="bubbles_user_education_title" msgid="5547017089271445797">"使用對話框進行即時通訊"</string>
<string name="bubbles_user_education_description" msgid="1160281719576715211">"新的對話會以浮動圖示或對話框形式顯示。輕觸即可開啟對話框,拖曳則可移動對話框。"</string>
@@ -1024,11 +1014,14 @@
<string name="notification_content_system_nav_changed" msgid="5077913144844684544">"系統操作機制已更新。如要進行變更,請前往「設定」。"</string>
<string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"請前往「設定」更新系統操作機制"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"待機"</string>
+ <string name="priority_onboarding_title" msgid="2893070698479227616">"將對話設為優先"</string>
+ <string name="priority_onboarding_behavior" msgid="5342816047020432929">"優先對話會:"</string>
<string name="priority_onboarding_show_at_top_text" msgid="1678400241025513541">"顯示在對話部分的頂端"</string>
<string name="priority_onboarding_show_avatar_text" msgid="5756291381124091508">"在螢幕鎖定畫面上顯示個人資料相片"</string>
<string name="priority_onboarding_appear_as_bubble_text" msgid="4227039772250263122">"以浮動對話框形式顯示在應用程式最上層"</string>
<string name="priority_onboarding_ignores_dnd_text" msgid="2918952762719600529">"中斷零打擾模式"</string>
<string name="priority_onboarding_done_button_title" msgid="4569550984286506007">"我知道了"</string>
+ <string name="priority_onboarding_settings_button_title" msgid="6663601574303585927">"設定"</string>
<string name="magnification_overlay_title" msgid="6584179429612427958">"放大重疊視窗"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"放大視窗"</string>
<string name="magnification_controls_title" msgid="8421106606708891519">"放大視窗控制項"</string>
@@ -1070,9 +1063,13 @@
<string name="controls_structure_tooltip" msgid="4355922222944447867">"滑動即可查看其他結構"</string>
<string name="controls_seeding_in_progress" msgid="3033855341410264148">"正在載入建議控制項"</string>
<string name="controls_media_close_session" msgid="9023534788828414585">"關閉這個媒體工作階段"</string>
+ <string name="controls_media_resume" msgid="1933520684481586053">"繼續播放"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"無效,請查看應用程式"</string>
<string name="controls_error_retryable" msgid="864025882878378470">"發生錯誤,正在重試…"</string>
- <string name="controls_error_removed" msgid="6299213591234723805">"裝置已遭到移除"</string>
+ <string name="controls_error_removed" msgid="6675638069846014366">"找不到控制項"</string>
+ <string name="controls_error_removed_title" msgid="1207794911208047818">"無法使用控制項"</string>
+ <string name="controls_error_removed_message" msgid="2885911717034750542">"無法存取「<xliff:g id="DEVICE">%1$s</xliff:g>」。請查看 <xliff:g id="APPLICATION">%2$s</xliff:g> 應用程式,確認當中是否仍有相關控制項,且應用程式設定沒有任何異動。"</string>
+ <string name="controls_open_app" msgid="483650971094300141">"開啟應用程式"</string>
<string name="controls_error_generic" msgid="352500456918362905">"無法載入狀態"</string>
<string name="controls_error_failed" msgid="960228639198558525">"發生錯誤,請再試一次"</string>
<string name="controls_in_progress" msgid="4421080500238215939">"進行中"</string>
diff --git a/packages/SystemUI/res/values-zu/strings.xml b/packages/SystemUI/res/values-zu/strings.xml
index e8be37d0060d..358792161575 100644
--- a/packages/SystemUI/res/values-zu/strings.xml
+++ b/packages/SystemUI/res/values-zu/strings.xml
@@ -77,9 +77,6 @@
<string name="compat_mode_on" msgid="4963711187149440884">"Sondeza ukugcwalisa isikrini"</string>
<string name="compat_mode_off" msgid="7682459748279487945">"Nweba ukugcwalisa isikrini"</string>
<string name="global_action_screenshot" msgid="2760267567509131654">"Isithombe-skrini"</string>
- <string name="global_action_lock_message" product="default" msgid="4466026255205186456">"Vula ifoni yakho ukuthola izinketho ezengeziwe"</string>
- <string name="global_action_lock_message" product="tablet" msgid="7621167597240332986">"Vula ithebulethi yakho ukuthola izinketho ezengeziwe"</string>
- <string name="global_action_lock_message" product="device" msgid="538790401275363781">"Vula idivayisi yakho ukuthola izinketho ezengeziwe"</string>
<string name="remote_input_image_insertion_text" msgid="4850791636452521123">"uthumele isithombe"</string>
<string name="screenshot_saving_ticker" msgid="6519186952674544916">"Ilondoloz umfanekiso weskrini..."</string>
<string name="screenshot_saving_title" msgid="2298349784913287333">"Ilondoloz umfanekiso weskrini..."</string>
@@ -722,7 +719,7 @@
<string name="notification_channel_summary_priority" msgid="7952654515769021553">"Iboniswa ngenhla kwesigaba sengxoxo, ivela njengebhamuza elintantayo, ibonisa isithombe sephrofayela kukukhiya isikrini"</string>
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"Izilungiselelo"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"Okubalulekile"</string>
- <string name="no_shortcut" msgid="7176375126961212514">"I-<xliff:g id="APP_NAME">%1$s</xliff:g> ayisekeli amasethingi athile engxoxo"</string>
+ <string name="no_shortcut" msgid="8257177117568230126">"I-<xliff:g id="APP_NAME">%1$s</xliff:g> ayisekeli izici zengxoxo"</string>
<string name="bubble_overflow_empty_title" msgid="3120029421991510842">"Awekho amabhamuza akamuva"</string>
<string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"Amabhamuza akamuva namabhamuza asusiwe azobonakala lapha."</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"Lezi zaziso azikwazi ukushintshwa."</string>
@@ -1005,7 +1002,8 @@
<string name="bubble_accessibility_action_move_top_right" msgid="6916868852433483569">"Hambisa phezulu ngakwesokudla"</string>
<string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"Hambisa inkinobho ngakwesokunxele"</string>
<string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"Hambisa inkinobho ngakwesokudla"</string>
- <string name="bubble_dismiss_text" msgid="7071770411580452911">"Cashisa"</string>
+ <!-- no translation found for bubble_dismiss_text (1314082410868930066) -->
+ <skip />
<string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"Ungayibhamuzi ingxoxo"</string>
<string name="bubbles_user_education_title" msgid="5547017089271445797">"Xoxa usebenzisa amabhamuza"</string>
<string name="bubbles_user_education_description" msgid="1160281719576715211">"Izingxoxo ezintsha zivela njengezithonjana ezintantayo, noma amabhamuza. Thepha ukuze uvule ibhamuza. Hudula ukuze ulihambise."</string>
@@ -1016,11 +1014,14 @@
<string name="notification_content_system_nav_changed" msgid="5077913144844684544">"Ukuzulazula kwesistimu kubuyekeziwe. Ukuze wenze ushintsho, hamba kokuthi Izilungiselelo."</string>
<string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"Hamba kuzilungiselelo ukuze ubuyekeze ukuzulazula kwesistimu"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Ilindile"</string>
+ <string name="priority_onboarding_title" msgid="2893070698479227616">"Izingxoxo zisethwe kweziza kuqala"</string>
+ <string name="priority_onboarding_behavior" msgid="5342816047020432929">"Izingxoxo eziza kuqala zizo:"</string>
<string name="priority_onboarding_show_at_top_text" msgid="1678400241025513541">"Kubonakala esigabeni esiphezulu sengxoxo"</string>
<string name="priority_onboarding_show_avatar_text" msgid="5756291381124091508">"Kubonakala esithombeni sephrofayela esikrinini esikhiyiwe"</string>
<string name="priority_onboarding_appear_as_bubble_text" msgid="4227039772250263122">"Kubonakala njengebhamuza elintantayo phezu kwezinhlelo zokusebenza"</string>
<string name="priority_onboarding_ignores_dnd_text" msgid="2918952762719600529">"Thikameza Ukungaphazamisi"</string>
<string name="priority_onboarding_done_button_title" msgid="4569550984286506007">"Ngiyezwa"</string>
+ <string name="priority_onboarding_settings_button_title" msgid="6663601574303585927">"Amasethingi"</string>
<string name="magnification_overlay_title" msgid="6584179429612427958">"Iwindi Lembondela Lesikhulisi"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"Iwindi Lesikhulisi"</string>
<string name="magnification_controls_title" msgid="8421106606708891519">"Izilawuli Zewindi Lesikhulisi"</string>
@@ -1062,9 +1063,13 @@
<string name="controls_structure_tooltip" msgid="4355922222944447867">"Swayipha ukuze ubone okuningi"</string>
<string name="controls_seeding_in_progress" msgid="3033855341410264148">"Ilayisha izincomo"</string>
<string name="controls_media_close_session" msgid="9023534788828414585">"Vala leseshini yemidiya"</string>
+ <string name="controls_media_resume" msgid="1933520684481586053">"Qalisa kabusha"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"Akusebenzi, hlola uhlelo lokusebenza"</string>
<string name="controls_error_retryable" msgid="864025882878378470">"Iphutha, iyazama futhi…"</string>
- <string name="controls_error_removed" msgid="6299213591234723805">"Idivayisi isusiwe"</string>
+ <string name="controls_error_removed" msgid="6675638069846014366">"Ayitholakali"</string>
+ <string name="controls_error_removed_title" msgid="1207794911208047818">"Ukulawula akutholakali"</string>
+ <string name="controls_error_removed_message" msgid="2885911717034750542">"Ayikwazanga ukufinyelela ku-<xliff:g id="DEVICE">%1$s</xliff:g>. Hlola uhlelo lokusebenza le-<xliff:g id="APPLICATION">%2$s</xliff:g> ukuqinisekisa ukuthi ukulawula kusatholakala nokuthi amasethingi wohlelo lokusebenza awakashintshi."</string>
+ <string name="controls_open_app" msgid="483650971094300141">"Vula uhlelo"</string>
<string name="controls_error_generic" msgid="352500456918362905">"Ayikwazi ukulayisha isimo"</string>
<string name="controls_error_failed" msgid="960228639198558525">"Iphutha, zama futhi"</string>
<string name="controls_in_progress" msgid="4421080500238215939">"Iyaqhubeka"</string>
diff --git a/packages/SystemUI/res/values/colors.xml b/packages/SystemUI/res/values/colors.xml
index 837627c02638..4fc904b21741 100644
--- a/packages/SystemUI/res/values/colors.xml
+++ b/packages/SystemUI/res/values/colors.xml
@@ -202,6 +202,10 @@
<color name="global_screenshot_dismiss_foreground">@color/GM2_grey_500</color>
<color name="global_screenshot_background_protection_start">#40000000</color> <!-- 25% black -->
+ <!-- Bubbles -->
+ <color name="bubbles_pointer_light">#FFFFFF</color>
+ <color name="bubbles_pointer_dark">@color/GM2_grey_800</color>
+
<!-- GM2 colors -->
<color name="GM2_grey_50">#F8F9FA</color>
<color name="GM2_grey_100">#F1F3F4</color>
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index a7d176443c55..abc560bed595 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -224,6 +224,7 @@
<dimen name="notification_guts_conversation_icon_size">56dp</dimen>
<dimen name="notification_guts_conversation_action_height">56dp</dimen>
<dimen name="notification_guts_conversation_action_text_padding_start">32dp</dimen>
+ <dimen name="conversation_onboarding_bullet_gap_width">6dp</dimen>
<!-- The height of the header in inline settings -->
<dimen name="notification_guts_header_height">24dp</dimen>
@@ -482,7 +483,8 @@
<dimen name="pull_span_min">25dp</dimen>
<dimen name="qs_tile_height">106dp</dimen>
- <dimen name="qs_tile_layout_margin_side">6dp</dimen>
+ <!--notification_side_paddings + notification_content_margin_start - (qs_quick_tile_size - qs_tile_background_size) / 2 -->
+ <dimen name="qs_tile_layout_margin_side">18dp</dimen>
<dimen name="qs_tile_margin_horizontal">18dp</dimen>
<dimen name="qs_tile_margin_horizontal_two_line">2dp</dimen>
<dimen name="qs_tile_margin_vertical">24dp</dimen>
@@ -498,7 +500,6 @@
<dimen name="qs_quick_tile_size">48dp</dimen>
<dimen name="qs_quick_tile_padding">12dp</dimen>
<dimen name="qs_header_gear_translation">16dp</dimen>
- <dimen name="qs_header_tile_margin_horizontal">4dp</dimen>
<dimen name="qs_header_tile_margin_bottom">18dp</dimen>
<dimen name="qs_page_indicator_width">16dp</dimen>
<dimen name="qs_page_indicator_height">8dp</dimen>
@@ -973,7 +974,9 @@
<dimen name="recents_quick_scrub_onboarding_margin_start">8dp</dimen>
<!-- The height of the gradient indicating the dismiss edge when moving a PIP. -->
- <dimen name="floating_dismiss_gradient_height">176dp</dimen>
+ <dimen name="floating_dismiss_gradient_height">250dp</dimen>
+
+ <dimen name="floating_dismiss_bottom_margin">50dp</dimen>
<!-- The bottom margin of the PIP drag to dismiss info text shown when moving a PIP. -->
<dimen name="pip_dismiss_text_bottom_margin">24dp</dimen>
@@ -1031,8 +1034,23 @@
<dimen name="global_actions_grid_container_shadow_offset">20dp</dimen>
<dimen name="global_actions_grid_container_negative_shadow_offset">-20dp</dimen>
+ <!-- Global actions grid -->
+ <dimen name="global_actions_grid_vertical_padding">3dp</dimen>
+ <dimen name="global_actions_grid_horizontal_padding">3dp</dimen>
+
+ <dimen name="global_actions_grid_item_side_margin">5dp</dimen>
+ <dimen name="global_actions_grid_item_vertical_margin">4dp</dimen>
+ <dimen name="global_actions_grid_item_width">64dp</dimen>
+ <dimen name="global_actions_grid_item_height">64dp</dimen>
+
+ <dimen name="global_actions_grid_item_icon_width">20dp</dimen>
+ <dimen name="global_actions_grid_item_icon_height">20dp</dimen>
+ <dimen name="global_actions_grid_item_icon_top_margin">12dp</dimen>
+ <dimen name="global_actions_grid_item_icon_side_margin">22dp</dimen>
+ <dimen name="global_actions_grid_item_icon_bottom_margin">4dp</dimen>
+
<!-- Margins at the left and right of the power menu and home controls widgets. -->
- <dimen name="global_actions_side_margin">16dp</dimen>
+ <dimen name="global_actions_side_margin">10dp</dimen>
<!-- Amount to shift the layout when exiting/entering for controls activities -->
<dimen name="global_actions_controls_y_translation">20dp</dimen>
@@ -1057,9 +1075,8 @@
<dimen name="edge_margin">8dp</dimen>
<!-- The absolute side margins of quick settings -->
- <dimen name="quick_settings_side_margins">16dp</dimen>
<dimen name="quick_settings_expanded_bottom_margin">16dp</dimen>
- <dimen name="quick_settings_media_extra_bottom_margin">4dp</dimen>
+ <dimen name="quick_settings_media_extra_bottom_margin">6dp</dimen>
<dimen name="rounded_corner_content_padding">0dp</dimen>
<dimen name="nav_content_padding">0dp</dimen>
<dimen name="nav_quick_scrub_track_edge_padding">24dp</dimen>
@@ -1205,10 +1222,6 @@
<dimen name="bubble_dismiss_slop">16dp</dimen>
<!-- Height of button allowing users to adjust settings for bubbles. -->
<dimen name="bubble_manage_button_height">48dp</dimen>
- <!-- How far, horizontally, to animate the expanded view over when animating in/out. -->
- <dimen name="bubble_expanded_animate_x_distance">100dp</dimen>
- <!-- How far, vertically, to animate the expanded view over when animating in/out. -->
- <dimen name="bubble_expanded_animate_y_distance">500dp</dimen>
<!-- Max width of the message bubble-->
<dimen name="bubble_message_max_width">144dp</dimen>
<!-- Min width of the message bubble -->
@@ -1235,7 +1248,7 @@
<!-- Bubbles user education views -->
<dimen name="bubbles_manage_education_width">160dp</dimen>
<!-- The inset from the top bound of the manage button to place the user education. -->
- <dimen name="bubbles_manage_education_top_inset">10dp</dimen>
+ <dimen name="bubbles_manage_education_top_inset">65dp</dimen>
<!-- Size of padding for the user education cling, this should at minimum be larger than
individual_bubble_size + some padding. -->
<dimen name="bubble_stack_user_education_side_inset">72dp</dimen>
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index 97a0d032c4a7..48ff5c681853 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -1256,7 +1256,7 @@
<string name="manage_notifications_history_text">History</string>
<!-- Section title for notifications that have recently appeared. [CHAR LIMIT=40] -->
- <string name="notification_section_header_incoming">Incoming</string>
+ <string name="notification_section_header_incoming">New</string>
<!-- Section title for notifications that do not vibrate or make noise. [CHAR LIMIT=40] -->
<string name="notification_section_header_gentle">Silent</string>
@@ -2641,7 +2641,7 @@
<!-- Action in accessibility menu to move the stack of bubbles to the bottom right of the screen. [CHAR LIMIT=30]-->
<string name="bubble_accessibility_action_move_bottom_right">Move bottom right</string>
<!-- Text used for the bubble dismiss area. Bubbles dragged to, or flung towards, this area will go away. [CHAR LIMIT=20] -->
- <string name="bubble_dismiss_text">Dismiss</string>
+ <string name="bubble_dismiss_text">Dismiss bubble</string>
<!-- Button text to stop a conversation from bubbling [CHAR LIMIT=60]-->
<string name="bubbles_dont_bubble_conversation">Don\u2019t bubble conversation</string>
<!-- Title text for the bubbles feature education cling shown when a bubble is on screen for the first time. [CHAR LIMIT=60]-->
@@ -2667,6 +2667,11 @@
<string name="inattentive_sleep_warning_title">Standby</string>
<!-- Priority conversation onboarding screen -->
+ <!-- title of priority onboarding [CHAR LIMIT=75] -->
+ <string name="priority_onboarding_title">Conversation set to priority</string>
+ <!-- Text explaining that the following actions are the behaviors of priority conversations.
+ E.g. priority conversations will show at the top of the conversation section [CHAR LIMIT=75] -->
+ <string name="priority_onboarding_behavior">Priority conversations will:</string>
<!-- Text explaining that priority conversations show at the top of the conversation section [CHAR LIMIT=75] -->
<string name="priority_onboarding_show_at_top_text">Show at top of conversation section</string>
<!-- Text explaining that priority conversations show an avatar on the lock screen [CHAR LIMIT=75] -->
@@ -2677,6 +2682,8 @@
<string name="priority_onboarding_ignores_dnd_text">Interrupt Do Not Disturb</string>
<!-- Title for the affirmative button [CHAR LIMIT=50] -->
<string name="priority_onboarding_done_button_title">Got it</string>
+ <!-- Title for the settings button button [CHAR LIMIT=50] -->
+ <string name="priority_onboarding_settings_button_title">Settings</string>
<!-- Window Magnification strings -->
<!-- Title for Magnification Overlay Window [CHAR LIMIT=NONE] -->
@@ -2774,6 +2781,8 @@
<!-- Close the controls associated with a specific media session [CHAR_LIMIT=NONE] -->
<string name="controls_media_close_session">Close this media session</string>
+ <!-- Label for button to resume media playback [CHAR_LIMIT=NONE] -->
+ <string name="controls_media_resume">Resume</string>
<!-- Error message indicating that a control timed out while waiting for an update [CHAR_LIMIT=30] -->
<string name="controls_error_timeout">Inactive, check app</string>
@@ -2781,7 +2790,13 @@
a retry will be attempted [CHAR LIMIT=30] -->
<string name="controls_error_retryable">Error, retrying\u2026</string>
<!-- Error message indicating that the control is no longer available in the application [CHAR LIMIT=30] -->
- <string name="controls_error_removed">Device removed</string>
+ <string name="controls_error_removed">Not found</string>
+ <!-- Title for dialog indicating that the control is no longer available in the application [CHAR LIMIT=30] -->
+ <string name="controls_error_removed_title">Control is unavailable</string>
+ <!-- Message body for dialog indicating that the control is no longer available in the application [CHAR LIMIT=NONE] -->
+ <string name="controls_error_removed_message">Couldn\u2019t access <xliff:g id="device" example="Backdoor lock">%1$s</xliff:g>. Check the <xliff:g id="application" example="Google Home">%2$s</xliff:g> app to make sure the control is still available and that the app settings haven\u2019t changed.</string>
+ <!-- Text for button to open the corresponding application [CHAR_LIMIT=20] -->
+ <string name="controls_open_app">Open app</string>
<!-- Error message indicating that an unspecified error occurred while getting the status [CHAR LIMIT=30] -->
<string name="controls_error_generic">Can\u2019t load status</string>
<!-- Error message indicating that a control action failed [CHAR_LIMIT=30] -->
diff --git a/packages/SystemUI/res/values/styles.xml b/packages/SystemUI/res/values/styles.xml
index ed36bdbe1e7e..8097c01cb042 100644
--- a/packages/SystemUI/res/values/styles.xml
+++ b/packages/SystemUI/res/values/styles.xml
@@ -387,6 +387,11 @@
<item name="android:homeAsUpIndicator">@drawable/ic_arrow_back</item>
</style>
+ <style name="qs_security_footer" parent="@style/qs_theme">
+ <item name="android:textColor">?android:attr/textColorSecondary</item>
+ <item name="android:tint">?android:attr/textColorSecondary</item>
+ </style>
+
<style name="systemui_theme_remote_input" parent="@android:style/Theme.DeviceDefault.Light">
<item name="android:colorAccent">@color/remote_input_accent</item>
</style>
@@ -544,6 +549,13 @@
<style name="TextAppearance.NotificationImportanceChannelGroup">
<item name="android:textSize">@dimen/notification_importance_channel_group_text</item>
<item name="android:fontFamily">@*android:string/config_headlineFontFamily</item>
+ <item name="android:textColor">@color/notification_guts_header_text_color</item>
+ <item name="android:textSize">@dimen/notification_importance_channel_group_text</item>
+ </style>
+
+ <style name="TextAppearance.NotificationImportanceApp">
+ <item name="android:textSize">@dimen/notification_importance_channel_group_text</item>
+ <item name="android:fontFamily">@*android:string/config_headlineFontFamily</item>
<item name="android:textColor">@color/notification_guts_sub_text_color</item>
<item name="android:textSize">@dimen/notification_importance_channel_group_text</item>
</style>
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/ISystemUiProxy.aidl b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/ISystemUiProxy.aidl
index 35ad422c56b8..655008b7745a 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/ISystemUiProxy.aidl
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/ISystemUiProxy.aidl
@@ -23,10 +23,11 @@ import android.os.Bundle;
import android.view.MotionEvent;
import com.android.systemui.shared.recents.IPinnedStackAnimationListener;
+import com.android.systemui.shared.recents.model.Task;
/**
* Temporary callbacks into SystemUI.
- * Next id = 26
+ * Next id = 27
*/
interface ISystemUiProxy {
@@ -122,6 +123,9 @@ interface ISystemUiProxy {
/**
* Handle the provided image as if it was a screenshot.
+ *
+ * Deprecated, use handleImageBundleAsScreenshot with image bundle and UserTask
+ * @deprecated
*/
void handleImageAsScreenshot(in Bitmap screenImage, in Rect locationInScreen,
in Insets visibleInsets, int taskId) = 21;
@@ -146,4 +150,10 @@ interface ISystemUiProxy {
* @param rotation indicates which Surface.Rotation the gesture was started in
*/
void onQuickSwitchToNewTask(int rotation) = 25;
+
+ /**
+ * Handle the provided image as if it was a screenshot.
+ */
+ void handleImageBundleAsScreenshot(in Bundle screenImageBundle, in Rect locationInScreen,
+ in Insets visibleInsets, in Task.TaskKey task) = 26;
}
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/Task.aidl b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/Task.aidl
new file mode 100644
index 000000000000..e7cad2acc645
--- /dev/null
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/Task.aidl
@@ -0,0 +1,19 @@
+/*
+ * 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.shared.recents.model;
+
+parcelable Task.TaskKey; \ No newline at end of file
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/Task.java b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/Task.java
index dcb134ec933e..186379af4b1d 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/Task.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/Task.java
@@ -26,6 +26,8 @@ import android.content.Intent;
import android.content.pm.ActivityInfo;
import android.graphics.Color;
import android.graphics.drawable.Drawable;
+import android.os.Parcel;
+import android.os.Parcelable;
import android.view.ViewDebug;
import com.android.systemui.shared.recents.utilities.Utilities;
@@ -52,8 +54,10 @@ public class Task {
void onTaskWindowingModeChanged();
}
- /* The Task Key represents the unique primary key for the task */
- public static class TaskKey {
+ /**
+ * The Task Key represents the unique primary key for the task
+ */
+ public static class TaskKey implements Parcelable {
@ViewDebug.ExportedProperty(category="recents")
public final int id;
@ViewDebug.ExportedProperty(category="recents")
@@ -157,6 +161,48 @@ public class Task {
private void updateHashCode() {
mHashCode = Objects.hash(id, windowingMode, userId);
}
+
+ public static final Parcelable.Creator<TaskKey> CREATOR =
+ new Parcelable.Creator<TaskKey>() {
+ @Override
+ public TaskKey createFromParcel(Parcel source) {
+ return TaskKey.readFromParcel(source);
+ }
+
+ @Override
+ public TaskKey[] newArray(int size) {
+ return new TaskKey[size];
+ }
+ };
+
+ @Override
+ public final void writeToParcel(Parcel parcel, int flags) {
+ parcel.writeInt(id);
+ parcel.writeInt(windowingMode);
+ parcel.writeTypedObject(baseIntent, flags);
+ parcel.writeInt(userId);
+ parcel.writeLong(lastActiveTime);
+ parcel.writeInt(displayId);
+ parcel.writeTypedObject(sourceComponent, flags);
+ }
+
+ private static TaskKey readFromParcel(Parcel parcel) {
+ int id = parcel.readInt();
+ int windowingMode = parcel.readInt();
+ Intent baseIntent = parcel.readTypedObject(Intent.CREATOR);
+ int userId = parcel.readInt();
+ long lastActiveTime = parcel.readLong();
+ int displayId = parcel.readInt();
+ ComponentName sourceComponent = parcel.readTypedObject(ComponentName.CREATOR);
+
+ return new TaskKey(id, windowingMode, baseIntent, sourceComponent, userId,
+ lastActiveTime, displayId);
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
}
@ViewDebug.ExportedProperty(deepExport=true, prefix="key_")
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/utilities/BitmapUtil.java b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/utilities/BitmapUtil.java
new file mode 100644
index 000000000000..b79fcbd43972
--- /dev/null
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/utilities/BitmapUtil.java
@@ -0,0 +1,86 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.shared.recents.utilities;
+
+import android.graphics.Bitmap;
+import android.graphics.ColorSpace;
+import android.graphics.ParcelableColorSpace;
+import android.hardware.HardwareBuffer;
+import android.os.Bundle;
+
+import java.util.Objects;
+
+/**
+ * Utils for working with Bitmaps.
+ */
+public final class BitmapUtil {
+ private static final String KEY_BUFFER = "bitmap_util_buffer";
+ private static final String KEY_COLOR_SPACE = "bitmap_util_color_space";
+
+ private BitmapUtil(){ }
+
+ /**
+ * Creates a Bundle that represents the given Bitmap.
+ * <p>The Bundle will contain a wrapped version of the Bitmaps HardwareBuffer, so will avoid
+ * copies when passing across processes, only pass to processes you trust.
+ *
+ * <p>Returns a new Bundle rather than modifying an exiting one to avoid key collisions, the
+ * returned Bundle should be treated as a standalone object.
+ *
+ * @param bitmap to convert to bundle
+ * @return a Bundle representing the bitmap, should only be parsed by
+ * {@link #bundleToHardwareBitmap(Bundle)}
+ */
+ public static Bundle hardwareBitmapToBundle(Bitmap bitmap) {
+ if (bitmap.getConfig() != Bitmap.Config.HARDWARE) {
+ throw new IllegalArgumentException(
+ "Passed bitmap must have hardware config, found: " + bitmap.getConfig());
+ }
+
+ // Bitmap assumes SRGB for null color space
+ ParcelableColorSpace colorSpace =
+ bitmap.getColorSpace() == null
+ ? new ParcelableColorSpace(ColorSpace.get(ColorSpace.Named.SRGB))
+ : new ParcelableColorSpace(bitmap.getColorSpace());
+
+ Bundle bundle = new Bundle();
+ bundle.putParcelable(KEY_BUFFER, bitmap.getHardwareBuffer());
+ bundle.putParcelable(KEY_COLOR_SPACE, colorSpace);
+
+ return bundle;
+ }
+
+ /**
+ * Extracts the Bitmap added to a Bundle with {@link #hardwareBitmapToBundle(Bitmap)} .}
+ *
+ * <p>This Bitmap contains the HardwareBuffer from the original caller, be careful passing this
+ * Bitmap on to any other source.
+ *
+ * @param bundle containing the bitmap
+ * @return a hardware Bitmap
+ */
+ public static Bitmap bundleToHardwareBitmap(Bundle bundle) {
+ if (!bundle.containsKey(KEY_BUFFER) || !bundle.containsKey(KEY_COLOR_SPACE)) {
+ throw new IllegalArgumentException("Bundle does not contain a hardware bitmap");
+ }
+
+ HardwareBuffer buffer = bundle.getParcelable(KEY_BUFFER);
+ ParcelableColorSpace colorSpace = bundle.getParcelable(KEY_COLOR_SPACE);
+
+ return Bitmap.wrapHardwareBuffer(Objects.requireNonNull(buffer), colorSpace);
+ }
+}
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/TaskStackChangeListener.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/TaskStackChangeListener.java
index dd5cc7c9bbd4..44372d76bb23 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/TaskStackChangeListener.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/TaskStackChangeListener.java
@@ -114,4 +114,7 @@ public abstract class TaskStackChangeListener {
/** @see ITaskStackListener#onRecentTaskListFrozenChanged(boolean) */
public void onRecentTaskListFrozenChanged(boolean frozen) { }
+
+ /** @see ITaskStackListener#onActivityRotation(int)*/
+ public void onActivityRotation(int displayId) { }
}
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/TaskStackChangeListeners.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/TaskStackChangeListeners.java
index a76a901c5c81..f214648d89f1 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/TaskStackChangeListeners.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/TaskStackChangeListeners.java
@@ -237,6 +237,12 @@ public class TaskStackChangeListeners extends TaskStackListener {
mHandler.obtainMessage(H.ON_TASK_DESCRIPTION_CHANGED, taskInfo).sendToTarget();
}
+ @Override
+ public void onActivityRotation(int displayId) {
+ mHandler.obtainMessage(H.ON_ACTIVITY_ROTATION, displayId, 0 /* unused */)
+ .sendToTarget();
+ }
+
private final class H extends Handler {
private static final int ON_TASK_STACK_CHANGED = 1;
private static final int ON_TASK_SNAPSHOT_CHANGED = 2;
@@ -260,6 +266,7 @@ public class TaskStackChangeListeners extends TaskStackListener {
private static final int ON_SINGLE_TASK_DISPLAY_EMPTY = 22;
private static final int ON_TASK_LIST_FROZEN_UNFROZEN = 23;
private static final int ON_TASK_DESCRIPTION_CHANGED = 24;
+ private static final int ON_ACTIVITY_ROTATION = 25;
public H(Looper looper) {
@@ -427,6 +434,12 @@ public class TaskStackChangeListeners extends TaskStackListener {
}
break;
}
+ case ON_ACTIVITY_ROTATION: {
+ for (int i = mTaskStackListeners.size() - 1; i >= 0; i--) {
+ mTaskStackListeners.get(i).onActivityRotation(msg.arg1);
+ }
+ break;
+ }
}
}
if (msg.obj instanceof SomeArgs) {
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/ViewRootImplCompat.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/ViewRootImplCompat.java
index dd613263e5c2..73783ae7ece2 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/ViewRootImplCompat.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/ViewRootImplCompat.java
@@ -15,6 +15,7 @@
*/
package com.android.systemui.shared.system;
+import android.graphics.HardwareRenderer;
import android.view.SurfaceControl;
import android.view.View;
import android.view.ViewRootImpl;
@@ -50,7 +51,13 @@ public class ViewRootImplCompat {
public void registerRtFrameCallback(LongConsumer callback) {
if (mViewRoot != null) {
- mViewRoot.registerRtFrameCallback(callback::accept);
+ mViewRoot.registerRtFrameCallback(
+ new HardwareRenderer.FrameDrawingCallback() {
+ @Override
+ public void onFrameDraw(long l) {
+ callback.accept(l);
+ }
+ });
}
}
}
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardFaceListenModel.kt b/packages/SystemUI/src/com/android/keyguard/KeyguardFaceListenModel.kt
new file mode 100644
index 000000000000..8cd68ef8acbc
--- /dev/null
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardFaceListenModel.kt
@@ -0,0 +1,26 @@
+package com.android.keyguard
+
+import android.annotation.CurrentTimeMillisLong
+
+/**
+ * Data class for tracking information associated with [KeyguardUpdateMonitor.shouldListenForFace]
+ * method calls.
+ */
+data class KeyguardFaceListenModel(
+ @CurrentTimeMillisLong val timeMillis: Long,
+ val userId: Int,
+ val isListeningForFace: Boolean,
+ val isBouncer: Boolean,
+ val isAuthInterruptActive: Boolean,
+ val isKeyguardAwake: Boolean,
+ val isListeningForFaceAssistant: Boolean,
+ val isSwitchingUser: Boolean,
+ val isFaceDisabled: Boolean,
+ val isBecauseCannotSkipBouncer: Boolean,
+ val isKeyguardGoingAway: Boolean,
+ val isFaceSettingEnabledForUser: Boolean,
+ val isLockIconPressed: Boolean,
+ val isScanningAllowedByStrongAuth: Boolean,
+ val isPrimaryUser: Boolean,
+ val isSecureCameraLaunched: Boolean
+)
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSliceView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSliceView.java
index 9d8c54501c02..f639c880c97a 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSliceView.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSliceView.java
@@ -141,14 +141,6 @@ public class KeyguardSliceView extends LinearLayout implements View.OnClickListe
mLayoutTransition.setAnimateParentHierarchy(false);
}
- // Temporary workaround to allow KeyguardStatusView to inflate a copy for Universal Smartspace.
- // Eventually the existing copy will be reparented instead, and we won't need this.
- public KeyguardSliceView(Context context, AttributeSet attributeSet) {
- this(context, attributeSet, Dependency.get(ActivityStarter.class),
- Dependency.get(ConfigurationController.class), Dependency.get(TunerService.class),
- context.getResources());
- }
-
@Override
protected void onFinishInflate() {
super.onFinishInflate();
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardStatusView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardStatusView.java
index a181ce4b000a..5a1c9976f021 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardStatusView.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardStatusView.java
@@ -18,10 +18,7 @@ package com.android.keyguard;
import android.app.ActivityManager;
import android.app.IActivityManager;
-import android.content.BroadcastReceiver;
import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
import android.content.res.Resources;
import android.graphics.Color;
import android.os.Handler;
@@ -43,8 +40,6 @@ import androidx.core.graphics.ColorUtils;
import com.android.internal.widget.LockPatternUtils;
import com.android.systemui.Dependency;
import com.android.systemui.R;
-import com.android.systemui.shared.system.SurfaceViewRequestReceiver;
-import com.android.systemui.shared.system.UniversalSmartspaceUtils;
import com.android.systemui.statusbar.policy.ConfigurationController;
import java.io.FileDescriptor;
@@ -127,21 +122,6 @@ public class KeyguardStatusView extends GridLayout implements
}
};
- private final BroadcastReceiver mUniversalSmartspaceBroadcastReceiver =
- new BroadcastReceiver() {
- private final SurfaceViewRequestReceiver mReceiver = new SurfaceViewRequestReceiver();
-
- @Override
- public void onReceive(Context context, Intent i) {
- // TODO(b/148159743): Restrict to Pixel Launcher.
- if (UniversalSmartspaceUtils.ACTION_REQUEST_SMARTSPACE_VIEW.equals(i.getAction())) {
- mReceiver.onReceive(context,
- i.getBundleExtra(UniversalSmartspaceUtils.INTENT_BUNDLE_KEY),
- inflate(mContext, R.layout.keyguard_status_area, null));
- }
- }
- };
-
public KeyguardStatusView(Context context) {
this(context, null, 0);
}
@@ -336,8 +316,6 @@ public class KeyguardStatusView extends GridLayout implements
super.onAttachedToWindow();
Dependency.get(KeyguardUpdateMonitor.class).registerCallback(mInfoCallback);
Dependency.get(ConfigurationController.class).addCallback(this);
- getContext().registerReceiver(mUniversalSmartspaceBroadcastReceiver,
- new IntentFilter(UniversalSmartspaceUtils.ACTION_REQUEST_SMARTSPACE_VIEW));
}
@Override
@@ -345,7 +323,6 @@ public class KeyguardStatusView extends GridLayout implements
super.onDetachedFromWindow();
Dependency.get(KeyguardUpdateMonitor.class).removeCallback(mInfoCallback);
Dependency.get(ConfigurationController.class).removeCallback(this);
- getContext().unregisterReceiver(mUniversalSmartspaceBroadcastReceiver);
}
@Override
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
index 0db713e9c276..ee31706c0b94 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
@@ -58,6 +58,7 @@ import android.hardware.face.FaceManager;
import android.hardware.fingerprint.FingerprintManager;
import android.hardware.fingerprint.FingerprintManager.AuthenticationCallback;
import android.hardware.fingerprint.FingerprintManager.AuthenticationResult;
+import android.os.Build;
import android.os.CancellationSignal;
import android.os.Handler;
import android.os.IRemoteCallback;
@@ -108,9 +109,13 @@ import com.google.android.collect.Lists;
import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.lang.ref.WeakReference;
+import java.text.SimpleDateFormat;
+import java.util.ArrayDeque;
import java.util.ArrayList;
+import java.util.Date;
import java.util.HashMap;
import java.util.List;
+import java.util.Locale;
import java.util.Map;
import java.util.Map.Entry;
import java.util.TimeZone;
@@ -131,7 +136,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
private static final String TAG = "KeyguardUpdateMonitor";
private static final boolean DEBUG = KeyguardConstants.DEBUG;
private static final boolean DEBUG_SIM_STATES = KeyguardConstants.DEBUG_SIM_STATES;
- private static final boolean DEBUG_FACE = true;
+ private static final boolean DEBUG_FACE = Build.IS_DEBUGGABLE;
private static final boolean DEBUG_SPEW = false;
private static final int LOW_BATTERY_THRESHOLD = 20;
@@ -362,6 +367,10 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
@VisibleForTesting
SparseArray<BiometricAuthenticated> mUserFaceAuthenticated = new SparseArray<>();
+ // Keep track of recent calls to shouldListenForFace() for debugging.
+ private static final int FACE_LISTEN_CALLS_QUEUE_SIZE = 20;
+ private ArrayDeque<KeyguardFaceListenModel> mFaceListenModels;
+
private static int sCurrentUser;
private Runnable mUpdateBiometricListeningState = this::updateBiometricListeningState;
@@ -1945,25 +1954,48 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
&& strongAuthAllowsScanning && mIsPrimaryUser
&& !mSecureCameraLaunched;
+ // Aggregate relevant fields for debug logging.
+ if (DEBUG_FACE || DEBUG_SPEW) {
+ final KeyguardFaceListenModel model = new KeyguardFaceListenModel(
+ System.currentTimeMillis(),
+ user,
+ shouldListen,
+ mBouncer,
+ mAuthInterruptActive,
+ awakeKeyguard,
+ shouldListenForFaceAssistant(),
+ mSwitchingUser,
+ isFaceDisabled(user),
+ becauseCannotSkipBouncer,
+ mKeyguardGoingAway,
+ mFaceSettingEnabledForUser.get(user),
+ mLockIconPressed,
+ strongAuthAllowsScanning,
+ mIsPrimaryUser,
+ mSecureCameraLaunched);
+ maybeLogFaceListenerModelData(model);
+ }
+
+ return shouldListen;
+ }
+
+ private void maybeLogFaceListenerModelData(KeyguardFaceListenModel model) {
// Too chatty, but very useful when debugging issues.
if (DEBUG_SPEW) {
- Log.v(TAG, "shouldListenForFace(" + user + ")=" + shouldListen + "... "
- + ", mBouncer: " + mBouncer
- + ", mAuthInterruptActive: " + mAuthInterruptActive
- + ", awakeKeyguard: " + awakeKeyguard
- + ", shouldListenForFaceAssistant: " + shouldListenForFaceAssistant()
- + ", mSwitchingUser: " + mSwitchingUser
- + ", isFaceDisabled(" + user + "): " + isFaceDisabled(user)
- + ", becauseCannotSkipBouncer: " + becauseCannotSkipBouncer
- + ", mKeyguardGoingAway: " + mKeyguardGoingAway
- + ", mFaceSettingEnabledForUser(" + user + "): "
- + mFaceSettingEnabledForUser.get(user)
- + ", mLockIconPressed: " + mLockIconPressed
- + ", strongAuthAllowsScanning: " + strongAuthAllowsScanning
- + ", isPrimaryUser: " + mIsPrimaryUser
- + ", mSecureCameraLaunched: " + mSecureCameraLaunched);
+ Log.v(TAG, model.toString());
+ }
+
+ // Add model data to the historical buffer.
+ if (DEBUG_FACE && mFaceRunningState != BIOMETRIC_STATE_RUNNING
+ && model.isListeningForFace()) {
+ if (mFaceListenModels == null) {
+ mFaceListenModels = new ArrayDeque<>(FACE_LISTEN_CALLS_QUEUE_SIZE);
+ }
+ if (mFaceListenModels.size() >= FACE_LISTEN_CALLS_QUEUE_SIZE) {
+ mFaceListenModels.remove();
+ }
+ mFaceListenModels.add(model);
}
- return shouldListen;
}
/**
@@ -2919,5 +2951,14 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
pw.println(" enabledByUser=" + mFaceSettingEnabledForUser.get(userId));
pw.println(" mSecureCameraLaunched=" + mSecureCameraLaunched);
}
+ if (mFaceListenModels != null && !mFaceListenModels.isEmpty()) {
+ final SimpleDateFormat dateFormat =
+ new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS", Locale.US);
+ pw.println(" Face listen results (last " + FACE_LISTEN_CALLS_QUEUE_SIZE + " calls):");
+ for (final KeyguardFaceListenModel model : mFaceListenModels) {
+ final String time = dateFormat.format(new Date(model.getTimeMillis()));
+ pw.println(" " + time + " " + model.toString());
+ }
+ }
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/Prefs.java b/packages/SystemUI/src/com/android/systemui/Prefs.java
index 87990cd3bffa..0218cd237037 100644
--- a/packages/SystemUI/src/com/android/systemui/Prefs.java
+++ b/packages/SystemUI/src/com/android/systemui/Prefs.java
@@ -124,7 +124,7 @@ public final class Prefs {
String HAS_SEEN_BUBBLES_MANAGE_EDUCATION = "HasSeenBubblesManageOnboarding";
String CONTROLS_STRUCTURE_SWIPE_TOOLTIP_COUNT = "ControlsStructureSwipeTooltipCount";
/** Tracks whether the user has seen the onboarding screen for priority conversations */
- String HAS_SEEN_PRIORITY_ONBOARDING = "HasSeenPriorityOnboarding";
+ String HAS_SEEN_PRIORITY_ONBOARDING = "HasUserSeenPriorityOnboarding";
}
public static boolean getBoolean(Context context, @Key String key, boolean defaultValue) {
diff --git a/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java b/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java
index be82a2d5325b..5674fdd3bb36 100644
--- a/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java
+++ b/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java
@@ -28,6 +28,7 @@ import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.widget.LockPatternUtils;
import com.android.keyguard.KeyguardUpdateMonitor;
import com.android.keyguard.ViewMediatorCallback;
+import com.android.systemui.bubbles.BubbleController;
import com.android.systemui.dagger.DaggerSystemUIRootComponent;
import com.android.systemui.dagger.DependencyProvider;
import com.android.systemui.dagger.SystemUIRootComponent;
@@ -164,7 +165,8 @@ public class SystemUIFactory {
wakeUpCoordinator, keyguardBypassController,
Dependency.get(NotificationMediaManager.class),
Dependency.get(NotificationListener.class),
- Dependency.get(DozeParameters.class));
+ Dependency.get(DozeParameters.class),
+ Dependency.get(BubbleController.class));
}
@Module
diff --git a/packages/SystemUI/src/com/android/systemui/assist/AssistManager.java b/packages/SystemUI/src/com/android/systemui/assist/AssistManager.java
index a876dee0e52d..a7533adc795e 100644
--- a/packages/SystemUI/src/com/android/systemui/assist/AssistManager.java
+++ b/packages/SystemUI/src/com/android/systemui/assist/AssistManager.java
@@ -40,8 +40,11 @@ import android.widget.ImageView;
import com.android.internal.app.AssistUtils;
import com.android.internal.app.IVoiceInteractionSessionListener;
import com.android.internal.app.IVoiceInteractionSessionShowCallback;
+import com.android.internal.logging.InstanceId;
+import com.android.internal.logging.InstanceIdSequence;
import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
+import com.android.internal.util.FrameworkStatsLog;
import com.android.keyguard.KeyguardUpdateMonitor;
import com.android.settingslib.applications.InterestingConfigChanges;
import com.android.systemui.R;
@@ -121,6 +124,7 @@ public class AssistManager {
private static final long TIMEOUT_SERVICE = 2500;
private static final long TIMEOUT_ACTIVITY = 1000;
+ private static final int INSTANCE_ID_MAX = 1 << 20;
protected final Context mContext;
private final WindowManager mWindowManager;
@@ -130,6 +134,8 @@ public class AssistManager {
private final AssistHandleBehaviorController mHandleController;
private final UiController mUiController;
protected final Lazy<SysUiState> mSysUiState;
+ protected final InstanceIdSequence mInstanceIdSequence =
+ new InstanceIdSequence(INSTANCE_ID_MAX);
private AssistOrbContainer mView;
private final DeviceProvisionedController mDeviceProvisionedController;
@@ -299,7 +305,8 @@ public class AssistManager {
int phoneState = mPhoneStateMonitor.getPhoneState();
args.putInt(INVOCATION_PHONE_STATE_KEY, phoneState);
args.putLong(INVOCATION_TIME_MS_KEY, SystemClock.elapsedRealtime());
- logStartAssist(invocationType, phoneState);
+ logStartAssist(/* instanceId = */ null, invocationType, phoneState);
+ logStartAssistLegacy(invocationType, phoneState);
startAssistInternal(args, assistComponent, isService);
}
@@ -499,7 +506,35 @@ public class AssistManager {
return toLoggingSubType(invocationType, mPhoneStateMonitor.getPhoneState());
}
- protected void logStartAssist(int invocationType, int phoneState) {
+ protected void logStartAssist(
+ @Nullable InstanceId instanceId, int invocationType, int deviceState) {
+ InstanceId currentInstanceId =
+ instanceId == null ? mInstanceIdSequence.newInstanceId() : instanceId;
+ ComponentName assistantComponent =
+ mAssistUtils.getAssistComponentForUser(UserHandle.USER_CURRENT);
+ int assistantUid = 0;
+ try {
+ assistantUid =
+ mContext.getPackageManager()
+ .getApplicationInfo(
+ assistantComponent.getPackageName(),
+ /* flags = */ 0)
+ .uid;
+ } catch (PackageManager.NameNotFoundException e) {
+ Log.e(TAG, "Unable to find Assistant UID", e);
+ }
+
+ FrameworkStatsLog.write(
+ FrameworkStatsLog.ASSISTANT_INVOCATION_REPORTED,
+ AssistantInvocationEvent.Companion.eventIdFromLegacyInvocationType(invocationType),
+ assistantUid,
+ assistantComponent.flattenToString(),
+ currentInstanceId.getId(),
+ AssistantInvocationEvent.Companion.deviceStateFromLegacyDeviceState(deviceState),
+ mHandleController.areHandlesShowing());
+ }
+
+ protected void logStartAssistLegacy(int invocationType, int phoneState) {
MetricsLogger.action(
new LogMaker(MetricsEvent.ASSISTANT)
.setType(MetricsEvent.TYPE_OPEN)
diff --git a/packages/SystemUI/src/com/android/systemui/assist/AssistantInvocationEvent.kt b/packages/SystemUI/src/com/android/systemui/assist/AssistantInvocationEvent.kt
new file mode 100644
index 000000000000..1de7b8423617
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/assist/AssistantInvocationEvent.kt
@@ -0,0 +1,119 @@
+/*
+ * 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.assist
+
+import com.android.internal.logging.UiEvent
+import com.android.internal.logging.UiEventLogger
+import com.android.internal.util.FrameworkStatsLog.ASSISTANT_INVOCATION_REPORTED__DEVICE_STATE__AOD1
+import com.android.internal.util.FrameworkStatsLog.ASSISTANT_INVOCATION_REPORTED__DEVICE_STATE__AOD2
+import com.android.internal.util.FrameworkStatsLog.ASSISTANT_INVOCATION_REPORTED__DEVICE_STATE__APP_DEFAULT
+import com.android.internal.util.FrameworkStatsLog.ASSISTANT_INVOCATION_REPORTED__DEVICE_STATE__APP_FULLSCREEN
+import com.android.internal.util.FrameworkStatsLog.ASSISTANT_INVOCATION_REPORTED__DEVICE_STATE__APP_IMMERSIVE
+import com.android.internal.util.FrameworkStatsLog.ASSISTANT_INVOCATION_REPORTED__DEVICE_STATE__BOUNCER
+import com.android.internal.util.FrameworkStatsLog.ASSISTANT_INVOCATION_REPORTED__DEVICE_STATE__LAUNCHER_ALL_APPS
+import com.android.internal.util.FrameworkStatsLog.ASSISTANT_INVOCATION_REPORTED__DEVICE_STATE__LAUNCHER_HOME
+import com.android.internal.util.FrameworkStatsLog.ASSISTANT_INVOCATION_REPORTED__DEVICE_STATE__LAUNCHER_OVERVIEW
+import com.android.internal.util.FrameworkStatsLog.ASSISTANT_INVOCATION_REPORTED__DEVICE_STATE__UNKNOWN_DEVICE_STATE
+import com.android.internal.util.FrameworkStatsLog.ASSISTANT_INVOCATION_REPORTED__DEVICE_STATE__UNLOCKED_LOCKSCREEN
+
+enum class AssistantInvocationEvent(private val id: Int) : UiEventLogger.UiEventEnum {
+ @UiEvent(doc = "Assistant invoked by unknown method")
+ ASSISTANT_INVOCATION_UNKNOWN(442),
+
+ @UiEvent(doc = "Assistant invoked by touch gesture")
+ ASSISTANT_INVOCATION_TOUCH_GESTURE(443),
+
+ @UiEvent(doc = "Assistant invoked by alternate touch gesture")
+ ASSISTANT_INVOCATION_TOUCH_GESTURE_ALT(444),
+
+ @UiEvent(doc = "Assistant invoked by hotword")
+ ASSISTANT_INVOCATION_HOTWORD(445),
+
+ @UiEvent(doc = "Assistant invoked by tapping quick search bar icon")
+ ASSISTANT_INVOCATION_QUICK_SEARCH_BAR(446),
+
+ @UiEvent(doc = "Assistant invoked by home button long press")
+ ASSISTANT_INVOCATION_HOME_LONG_PRESS(447),
+
+ @UiEvent(doc = "Assistant invoked by physical gesture")
+ ASSISTANT_INVOCATION_PHYSICAL_GESTURE(448);
+
+ override fun getId(): Int {
+ return id
+ }
+
+ companion object {
+ fun eventIdFromLegacyInvocationType(legacyInvocationType: Int): Int {
+ return when (legacyInvocationType) {
+ AssistManager.INVOCATION_TYPE_GESTURE ->
+ ASSISTANT_INVOCATION_TOUCH_GESTURE
+
+ AssistManager.INVOCATION_TYPE_OTHER ->
+ ASSISTANT_INVOCATION_PHYSICAL_GESTURE
+
+ AssistManager.INVOCATION_TYPE_VOICE ->
+ ASSISTANT_INVOCATION_HOTWORD
+
+ AssistManager.INVOCATION_TYPE_QUICK_SEARCH_BAR ->
+ ASSISTANT_INVOCATION_QUICK_SEARCH_BAR
+
+ AssistManager.INVOCATION_HOME_BUTTON_LONG_PRESS ->
+ ASSISTANT_INVOCATION_HOME_LONG_PRESS
+
+ else ->
+ ASSISTANT_INVOCATION_UNKNOWN
+ }.id
+ }
+
+ fun deviceStateFromLegacyDeviceState(legacyDeviceState: Int): Int {
+ return when (legacyDeviceState) {
+ PhoneStateMonitor.PHONE_STATE_AOD1 ->
+ ASSISTANT_INVOCATION_REPORTED__DEVICE_STATE__AOD1
+
+ PhoneStateMonitor.PHONE_STATE_AOD2 ->
+ ASSISTANT_INVOCATION_REPORTED__DEVICE_STATE__AOD2
+
+ PhoneStateMonitor.PHONE_STATE_BOUNCER ->
+ ASSISTANT_INVOCATION_REPORTED__DEVICE_STATE__BOUNCER
+
+ PhoneStateMonitor.PHONE_STATE_UNLOCKED_LOCKSCREEN ->
+ ASSISTANT_INVOCATION_REPORTED__DEVICE_STATE__UNLOCKED_LOCKSCREEN
+
+ PhoneStateMonitor.PHONE_STATE_HOME ->
+ ASSISTANT_INVOCATION_REPORTED__DEVICE_STATE__LAUNCHER_HOME
+
+ PhoneStateMonitor.PHONE_STATE_OVERVIEW ->
+ ASSISTANT_INVOCATION_REPORTED__DEVICE_STATE__LAUNCHER_OVERVIEW
+
+ PhoneStateMonitor.PHONE_STATE_ALL_APPS ->
+ ASSISTANT_INVOCATION_REPORTED__DEVICE_STATE__LAUNCHER_ALL_APPS
+
+ PhoneStateMonitor.PHONE_STATE_APP_DEFAULT ->
+ ASSISTANT_INVOCATION_REPORTED__DEVICE_STATE__APP_DEFAULT
+
+ PhoneStateMonitor.PHONE_STATE_APP_IMMERSIVE ->
+ ASSISTANT_INVOCATION_REPORTED__DEVICE_STATE__APP_IMMERSIVE
+
+ PhoneStateMonitor.PHONE_STATE_APP_FULLSCREEN ->
+ ASSISTANT_INVOCATION_REPORTED__DEVICE_STATE__APP_FULLSCREEN
+
+ else ->
+ ASSISTANT_INVOCATION_REPORTED__DEVICE_STATE__UNKNOWN_DEVICE_STATE
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/assist/PhoneStateMonitor.java b/packages/SystemUI/src/com/android/systemui/assist/PhoneStateMonitor.java
index 9de6854a6024..652ce6f04db0 100644
--- a/packages/SystemUI/src/com/android/systemui/assist/PhoneStateMonitor.java
+++ b/packages/SystemUI/src/com/android/systemui/assist/PhoneStateMonitor.java
@@ -50,16 +50,16 @@ import dagger.Lazy;
@Singleton
public final class PhoneStateMonitor {
- private static final int PHONE_STATE_AOD1 = 1;
- private static final int PHONE_STATE_AOD2 = 2;
- private static final int PHONE_STATE_BOUNCER = 3;
- private static final int PHONE_STATE_UNLOCKED_LOCKSCREEN = 4;
- private static final int PHONE_STATE_HOME = 5;
- private static final int PHONE_STATE_OVERVIEW = 6;
- private static final int PHONE_STATE_ALL_APPS = 7;
- private static final int PHONE_STATE_APP_DEFAULT = 8;
- private static final int PHONE_STATE_APP_IMMERSIVE = 9;
- private static final int PHONE_STATE_APP_FULLSCREEN = 10;
+ public static final int PHONE_STATE_AOD1 = 1;
+ public static final int PHONE_STATE_AOD2 = 2;
+ public static final int PHONE_STATE_BOUNCER = 3;
+ public static final int PHONE_STATE_UNLOCKED_LOCKSCREEN = 4;
+ public static final int PHONE_STATE_HOME = 5;
+ public static final int PHONE_STATE_OVERVIEW = 6;
+ public static final int PHONE_STATE_ALL_APPS = 7;
+ public static final int PHONE_STATE_APP_DEFAULT = 8;
+ public static final int PHONE_STATE_APP_IMMERSIVE = 9;
+ public static final int PHONE_STATE_APP_FULLSCREEN = 10;
private static final String[] DEFAULT_HOME_CHANGE_ACTIONS = new String[] {
PackageManagerWrapper.ACTION_PREFERRED_ACTIVITY_CHANGED,
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthContainerView.java b/packages/SystemUI/src/com/android/systemui/biometrics/AuthContainerView.java
index 1dd6409b8582..dbe5a77965be 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthContainerView.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthContainerView.java
@@ -34,6 +34,7 @@ import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
+import android.view.WindowInsets;
import android.view.WindowManager;
import android.view.animation.Interpolator;
import android.widget.FrameLayout;
@@ -632,6 +633,7 @@ public class AuthContainerView extends LinearLayout
windowFlags,
PixelFormat.TRANSLUCENT);
lp.privateFlags |= WindowManager.LayoutParams.SYSTEM_FLAG_SHOW_FOR_ALL_USERS;
+ lp.setFitInsetsTypes(lp.getFitInsetsTypes() & ~WindowInsets.Type.ime());
lp.setTitle("BiometricPrompt");
lp.token = windowToken;
return lp;
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/Bubble.java b/packages/SystemUI/src/com/android/systemui/bubbles/Bubble.java
index 15eda0689101..7f78ddf2cf1c 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/Bubble.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/Bubble.java
@@ -21,6 +21,7 @@ import static android.view.Display.INVALID_DISPLAY;
import static com.android.internal.annotations.VisibleForTesting.Visibility.PRIVATE;
+import android.annotation.DimenRes;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.Notification;
@@ -104,27 +105,39 @@ class Bubble implements BubbleViewProvider {
private Path mDotPath;
private int mFlags;
+ @NonNull
+ private UserHandle mUser;
+ @NonNull
+ private String mPackageName;
+ private int mDesiredHeight;
+ @DimenRes
+ private int mDesiredHeightResId;
+
/**
* Create a bubble with limited information based on given {@link ShortcutInfo}.
* Note: Currently this is only being used when the bubble is persisted to disk.
*/
- Bubble(@NonNull final String key, @NonNull final ShortcutInfo shortcutInfo) {
+ Bubble(@NonNull final String key, @NonNull final ShortcutInfo shortcutInfo,
+ final int desiredHeight, final int desiredHeightResId) {
Objects.requireNonNull(key);
Objects.requireNonNull(shortcutInfo);
mShortcutInfo = shortcutInfo;
mKey = key;
mFlags = 0;
+ mUser = shortcutInfo.getUserHandle();
+ mPackageName = shortcutInfo.getPackage();
+ mDesiredHeight = desiredHeight;
+ mDesiredHeightResId = desiredHeightResId;
}
/** Used in tests when no UI is required. */
@VisibleForTesting(visibility = PRIVATE)
- Bubble(NotificationEntry e,
- BubbleController.NotificationSuppressionChangedListener listener) {
- mEntry = e;
+ Bubble(@NonNull final NotificationEntry e,
+ @Nullable final BubbleController.NotificationSuppressionChangedListener listener) {
+ Objects.requireNonNull(e);
mKey = e.getKey();
- mLastUpdated = e.getSbn().getPostTime();
mSuppressionListener = listener;
- mFlags = e.getSbn().getNotification().flags;
+ setEntry(e);
}
@Override
@@ -137,17 +150,14 @@ class Bubble implements BubbleViewProvider {
return mEntry;
}
- @Nullable
+ @NonNull
public UserHandle getUser() {
- if (mEntry != null) return mEntry.getSbn().getUser();
- if (mShortcutInfo != null) return mShortcutInfo.getUserHandle();
- return null;
+ return mUser;
}
+ @NonNull
public String getPackageName() {
- return mEntry == null
- ? mShortcutInfo == null ? null : mShortcutInfo.getPackage()
- : mEntry.getSbn().getPackageName();
+ return mPackageName;
}
@Override
@@ -293,10 +303,10 @@ class Bubble implements BubbleViewProvider {
mDotPath = info.dotPath;
if (mExpandedView != null) {
- mExpandedView.update(/* bubble */ this);
+ mExpandedView.update(this /* bubble */);
}
if (mIconView != null) {
- mIconView.setRenderedBubble(/* bubble */ this);
+ mIconView.setRenderedBubble(this /* bubble */);
}
}
@@ -318,9 +328,18 @@ class Bubble implements BubbleViewProvider {
/**
* Sets the entry associated with this bubble.
*/
- void setEntry(NotificationEntry entry) {
+ void setEntry(@NonNull final NotificationEntry entry) {
+ Objects.requireNonNull(entry);
+ Objects.requireNonNull(entry.getSbn());
mEntry = entry;
mLastUpdated = entry.getSbn().getPostTime();
+ mFlags = entry.getSbn().getNotification().flags;
+ mPackageName = entry.getSbn().getPackageName();
+ mUser = entry.getSbn().getUser();
+ if (entry.getBubbleMetadata() != null) {
+ mDesiredHeight = entry.getBubbleMetadata().getDesiredHeight();
+ mDesiredHeightResId = entry.getBubbleMetadata().getDesiredHeightResId();
+ }
}
/**
@@ -434,28 +453,30 @@ class Bubble implements BubbleViewProvider {
return mFlyoutMessage;
}
+ int getRawDesiredHeight() {
+ return mDesiredHeight;
+ }
+
+ int getRawDesiredHeightResId() {
+ return mDesiredHeightResId;
+ }
+
float getDesiredHeight(Context context) {
- if (mEntry == null) return 0;
- Notification.BubbleMetadata data = mEntry.getBubbleMetadata();
- boolean useRes = data.getDesiredHeightResId() != 0;
+ boolean useRes = mDesiredHeightResId != 0;
if (useRes) {
- return getDimenForPackageUser(context, data.getDesiredHeightResId(),
- mEntry.getSbn().getPackageName(),
- mEntry.getSbn().getUser().getIdentifier());
+ return getDimenForPackageUser(context, mDesiredHeightResId, mPackageName,
+ mUser.getIdentifier());
} else {
- return data.getDesiredHeight()
- * context.getResources().getDisplayMetrics().density;
+ return mDesiredHeight * context.getResources().getDisplayMetrics().density;
}
}
String getDesiredHeightString() {
- if (mEntry == null) return String.valueOf(0);
- Notification.BubbleMetadata data = mEntry.getBubbleMetadata();
- boolean useRes = data.getDesiredHeightResId() != 0;
+ boolean useRes = mDesiredHeightResId != 0;
if (useRes) {
- return String.valueOf(data.getDesiredHeightResId());
+ return String.valueOf(mDesiredHeightResId);
} else {
- return String.valueOf(data.getDesiredHeight());
+ return String.valueOf(mDesiredHeight);
}
}
@@ -527,13 +548,13 @@ class Bubble implements BubbleViewProvider {
}
private boolean shouldSuppressNotification() {
- if (mEntry == null) return false;
+ if (mEntry == null) return true;
return mEntry.getBubbleMetadata() != null
&& mEntry.getBubbleMetadata().isNotificationSuppressed();
}
boolean shouldAutoExpand() {
- if (mEntry == null) return false;
+ if (mEntry == null) return mShouldAutoExpand;
Notification.BubbleMetadata metadata = mEntry.getBubbleMetadata();
return (metadata != null && metadata.getAutoExpandBubble()) || mShouldAutoExpand;
}
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java
index f05d547edd0c..2affe0605d89 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java
@@ -156,6 +156,7 @@ public class BubbleController implements ConfigurationController.ConfigurationLi
private final ShadeController mShadeController;
private final FloatingContentCoordinator mFloatingContentCoordinator;
private final BubbleDataRepository mDataRepository;
+ private BubbleLogger mLogger = new BubbleLoggerImpl();
private BubbleData mBubbleData;
private ScrimView mBubbleScrim;
@@ -212,6 +213,13 @@ public class BubbleController implements ConfigurationController.ConfigurationLi
private final List<NotifCallback> mCallbacks = new ArrayList<>();
/**
+ * Whether the IME is visible, as reported by the BubbleStackView. If it is, we'll make the
+ * Bubbles window NOT_FOCUSABLE so that touches on the Bubbles UI doesn't steal focus from the
+ * ActivityView and hide the IME.
+ */
+ private boolean mImeVisible = false;
+
+ /**
* Listener to find out about stack expansion / collapse events.
*/
public interface BubbleExpandListener {
@@ -310,6 +318,7 @@ public class BubbleController implements ConfigurationController.ConfigurationLi
BubbleDataRepository dataRepository,
SysUiState sysUiState,
INotificationManager notificationManager,
+ @Nullable IStatusBarService statusBarService,
WindowManager windowManager) {
dumpManager.registerDumpable(TAG, this);
mContext = context;
@@ -380,8 +389,10 @@ public class BubbleController implements ConfigurationController.ConfigurationLi
mSurfaceSynchronizer = synchronizer;
mWindowManager = windowManager;
- mBarService = IStatusBarService.Stub.asInterface(
- ServiceManager.getService(Context.STATUS_BAR_SERVICE));
+ mBarService = statusBarService == null
+ ? IStatusBarService.Stub.asInterface(
+ ServiceManager.getService(Context.STATUS_BAR_SERVICE))
+ : statusBarService;
mBubbleScrim = new ScrimView(mContext);
@@ -408,6 +419,16 @@ public class BubbleController implements ConfigurationController.ConfigurationLi
mCallbacks.add(callback);
}
+ /**
+ * Dispatches a back press into the expanded Bubble's ActivityView if its IME is visible,
+ * causing it to hide.
+ */
+ public void hideImeFromExpandedBubble() {
+ if (mStackView != null) {
+ mStackView.hideImeFromExpandedBubble();
+ }
+ }
+
private void setupNEM() {
mNotificationEntryManager.addNotificationEntryListener(
new NotificationEntryListener() {
@@ -571,6 +592,18 @@ public class BubbleController implements ConfigurationController.ConfigurationLi
}
/**
+ * Called when the status bar has become visible or invisible (either permanently or
+ * temporarily).
+ */
+ public void onStatusBarVisibilityChanged(boolean visible) {
+ if (mStackView != null) {
+ // Hide the stack temporarily if the status bar has been made invisible, and the stack
+ // is collapsed. An expanded stack should remain visible until collapsed.
+ mStackView.setTemporarilyInvisible(!visible && !isStackExpanded());
+ }
+ }
+
+ /**
* Sets whether to perform inflation on the same thread as the caller. This method should only
* be used in tests, not in production.
*/
@@ -598,7 +631,8 @@ public class BubbleController implements ConfigurationController.ConfigurationLi
if (mStackView == null) {
mStackView = new BubbleStackView(
mContext, mBubbleData, mSurfaceSynchronizer, mFloatingContentCoordinator,
- mSysUiState, mNotificationShadeWindowController, this::onAllBubblesAnimatedOut);
+ mSysUiState, this::onAllBubblesAnimatedOut,
+ this::onImeVisibilityChanged);
mStackView.addView(mBubbleScrim);
if (mExpandListener != null) {
mStackView.setExpandListener(mExpandListener);
@@ -649,6 +683,11 @@ public class BubbleController implements ConfigurationController.ConfigurationLi
}
}
+ private void onImeVisibilityChanged(boolean imeVisible) {
+ mImeVisible = imeVisible;
+ updateWmFlags();
+ }
+
/** Removes the BubbleStackView from the WindowManager if it's there. */
private void removeFromWindowManagerMaybe() {
if (!mAddedToWindowManager) {
@@ -676,13 +715,14 @@ public class BubbleController implements ConfigurationController.ConfigurationLi
* the new params if the stack has been added.
*/
private void updateWmFlags() {
- if (isStackExpanded()) {
- // If we're expanded, we want to be focusable so that the ActivityView can receive focus
- // and show the IME.
+ if (isStackExpanded() && !mImeVisible) {
+ // If we're expanded, and the IME isn't visible, we want to be focusable. This ensures
+ // that any taps within Bubbles (including on the ActivityView) results in Bubbles
+ // receiving focus and clearing it from any other windows that might have it.
mWmLayoutParams.flags &= ~WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
} else {
- // If we're collapsed, we don't want to be able to receive focus. Doing so would
- // preclude applications from using the IME since we are always above them.
+ // If we're collapsed, we don't want to be focusable since tapping on the stack would
+ // steal focus from apps. We also don't want to be focusable if the IME is visible,
mWmLayoutParams.flags |= WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
}
@@ -784,6 +824,8 @@ public class BubbleController implements ConfigurationController.ConfigurationLi
mBubbleIconFactory = new BubbleIconFactory(mContext);
mStackView.onDisplaySizeChanged();
}
+
+ mStackView.onLayoutDirectionChanged();
}
}
@@ -853,10 +895,24 @@ public class BubbleController implements ConfigurationController.ConfigurationLi
return (isSummary && isSuppressedSummary) || isSuppressedBubble;
}
+ /**
+ * True if:
+ * (1) The current notification entry same as selected bubble notification entry and the
+ * stack is currently expanded.
+ *
+ * False otherwise.
+ */
+ public boolean isBubbleExpanded(NotificationEntry entry) {
+ return isStackExpanded() && mBubbleData != null && mBubbleData.getSelectedBubble() != null
+ && mBubbleData.getSelectedBubble().getKey().equals(entry.getKey()) ? true : false;
+ }
+
void promoteBubbleFromOverflow(Bubble bubble) {
+ mLogger.log(bubble, BubbleLogger.Event.BUBBLE_OVERFLOW_REMOVE_BACK_TO_STACK);
bubble.setInflateSynchronously(mInflateSynchronously);
- setIsBubble(bubble, /* isBubble */ true);
- mBubbleData.promoteBubbleFromOverflow(bubble, mStackView, mBubbleIconFactory);
+ bubble.setShouldAutoExpand(true);
+ bubble.markUpdatedAt(System.currentTimeMillis());
+ setIsBubble(bubble, true /* isBubble */);
}
/**
@@ -870,20 +926,17 @@ public class BubbleController implements ConfigurationController.ConfigurationLi
Bubble bubble = mBubbleData.getBubbleInStackWithKey(key);
if (bubble != null) {
mBubbleData.setSelectedBubble(bubble);
+ mBubbleData.setExpanded(true);
} else {
bubble = mBubbleData.getOverflowBubbleWithKey(key);
if (bubble != null) {
- bubble.setShouldAutoExpand(true);
promoteBubbleFromOverflow(bubble);
} else if (entry.canBubble()) {
// It can bubble but it's not -- it got aged out of the overflow before it
// was dismissed or opened, make it a bubble again.
- setIsBubble(entry, true);
- updateBubble(entry, true /* suppressFlyout */, false /* showInShade */);
+ setIsBubble(entry, true /* isBubble */, true /* autoExpand */);
}
}
-
- mBubbleData.setExpanded(true);
}
/**
@@ -927,13 +980,17 @@ public class BubbleController implements ConfigurationController.ConfigurationLi
}
void updateBubble(NotificationEntry notif, boolean suppressFlyout, boolean showInShade) {
- // Lazy init stack view when a bubble is created
- ensureStackViewCreated();
// If this is an interruptive notif, mark that it's interrupted
if (notif.getImportance() >= NotificationManager.IMPORTANCE_HIGH) {
notif.setInterruption();
}
- Bubble bubble = mBubbleData.getOrCreateBubble(notif);
+ Bubble bubble = mBubbleData.getOrCreateBubble(notif, null /* persistedBubble */);
+ inflateAndAdd(bubble, suppressFlyout, showInShade);
+ }
+
+ void inflateAndAdd(Bubble bubble, boolean suppressFlyout, boolean showInShade) {
+ // Lazy init stack view when a bubble is created
+ ensureStackViewCreated();
bubble.setInflateSynchronously(mInflateSynchronously);
bubble.inflate(
b -> {
@@ -1079,7 +1136,8 @@ public class BubbleController implements ConfigurationController.ConfigurationLi
}
}
- private void setIsBubble(@NonNull final NotificationEntry entry, final boolean isBubble) {
+ private void setIsBubble(@NonNull final NotificationEntry entry, final boolean isBubble,
+ final boolean autoExpand) {
Objects.requireNonNull(entry);
if (isBubble) {
entry.getSbn().getNotification().flags |= FLAG_BUBBLE;
@@ -1087,7 +1145,12 @@ public class BubbleController implements ConfigurationController.ConfigurationLi
entry.getSbn().getNotification().flags &= ~FLAG_BUBBLE;
}
try {
- mBarService.onNotificationBubbleChanged(entry.getKey(), isBubble, 0);
+ int flags = 0;
+ if (autoExpand) {
+ flags = Notification.BubbleMetadata.FLAG_SUPPRESS_NOTIFICATION;
+ flags |= Notification.BubbleMetadata.FLAG_AUTO_EXPAND_BUBBLE;
+ }
+ mBarService.onNotificationBubbleChanged(entry.getKey(), isBubble, flags);
} catch (RemoteException e) {
// Bad things have happened
}
@@ -1101,13 +1164,15 @@ public class BubbleController implements ConfigurationController.ConfigurationLi
b.disable(FLAG_BUBBLE);
}
if (b.getEntry() != null) {
- setIsBubble(b.getEntry(), isBubble);
- } else {
- try {
- mBarService.onNotificationBubbleChanged(b.getKey(), isBubble, 0);
- } catch (RemoteException e) {
- // Bad things have happened
- }
+ // Updating the entry to be a bubble will trigger our normal update flow
+ setIsBubble(b.getEntry(), isBubble, b.shouldAutoExpand());
+ } else if (isBubble) {
+ // If we have no entry to update, it's a persisted bubble so
+ // we need to add it to the stack ourselves
+ Bubble bubble = mBubbleData.getOrCreateBubble(null, b /* persistedBubble */);
+ inflateAndAdd(bubble, bubble.shouldAutoExpand() /* suppressFlyout */,
+ !bubble.shouldAutoExpand() /* showInShade */);
+
}
}
@@ -1116,6 +1181,8 @@ public class BubbleController implements ConfigurationController.ConfigurationLi
@Override
public void applyUpdate(BubbleData.Update update) {
+ ensureStackViewCreated();
+
// Lazy load overflow bubbles from disk
loadOverflowBubblesFromDisk();
// Update bubbles in overflow.
@@ -1157,7 +1224,7 @@ public class BubbleController implements ConfigurationController.ConfigurationLi
}
}
} else {
- if (bubble.isBubble() && bubble.showInShade()) {
+ if (bubble.isBubble()) {
setIsBubble(bubble, false /* isBubble */);
}
if (bubble.getEntry() != null && bubble.getEntry().getRow() != null) {
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleData.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleData.java
index 996a5553b5b2..24d44d5cb291 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleData.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleData.java
@@ -115,7 +115,7 @@ public class BubbleData {
/** Bubbles that aged out to overflow. */
private final List<Bubble> mOverflowBubbles;
/** Bubbles that are being loaded but haven't been added to the stack just yet. */
- private final List<Bubble> mPendingBubbles;
+ private final HashMap<String, Bubble> mPendingBubbles;
private Bubble mSelectedBubble;
private boolean mShowingOverflow;
private boolean mExpanded;
@@ -151,7 +151,7 @@ public class BubbleData {
mContext = context;
mBubbles = new ArrayList<>();
mOverflowBubbles = new ArrayList<>();
- mPendingBubbles = new ArrayList<>();
+ mPendingBubbles = new HashMap<>();
mStateChange = new Update(mBubbles, mOverflowBubbles);
mMaxBubbles = mContext.getResources().getInteger(R.integer.bubbles_max_rendered);
mMaxOverflowBubbles = mContext.getResources().getInteger(R.integer.bubbles_max_overflow);
@@ -203,62 +203,46 @@ public class BubbleData {
dispatchPendingChanges();
}
- public void promoteBubbleFromOverflow(Bubble bubble, BubbleStackView stack,
- BubbleIconFactory factory) {
- if (DEBUG_BUBBLE_DATA) {
- Log.d(TAG, "promoteBubbleFromOverflow: " + bubble);
- }
- mLogger.log(bubble, BubbleLogger.Event.BUBBLE_OVERFLOW_REMOVE_BACK_TO_STACK);
- moveOverflowBubbleToPending(bubble);
- // Preserve new order for next repack, which sorts by last updated time.
- bubble.inflate(
- b -> {
- b.setShouldAutoExpand(true);
- b.markUpdatedAt(mTimeSource.currentTimeMillis());
- notificationEntryUpdated(bubble, false /* suppressFlyout */,
- true /* showInShade */);
- },
- mContext, stack, factory, false /* skipInflation */);
- }
-
void setShowingOverflow(boolean showingOverflow) {
mShowingOverflow = showingOverflow;
}
- private void moveOverflowBubbleToPending(Bubble b) {
- mOverflowBubbles.remove(b);
- mPendingBubbles.add(b);
- }
-
/**
* Constructs a new bubble or returns an existing one. Does not add new bubbles to
* bubble data, must go through {@link #notificationEntryUpdated(Bubble, boolean, boolean)}
* for that.
+ *
+ * @param entry The notification entry to use, only null if it's a bubble being promoted from
+ * the overflow that was persisted over reboot.
+ * @param persistedBubble The bubble to use, only non-null if it's a bubble being promoted from
+ * the overflow that was persisted over reboot.
*/
- Bubble getOrCreateBubble(NotificationEntry entry) {
- String key = entry.getKey();
- Bubble bubble = getBubbleInStackWithKey(entry.getKey());
- if (bubble != null) {
- bubble.setEntry(entry);
- } else {
- bubble = getOverflowBubbleWithKey(key);
- if (bubble != null) {
- moveOverflowBubbleToPending(bubble);
- bubble.setEntry(entry);
- return bubble;
- }
- // Check for it in pending
- for (int i = 0; i < mPendingBubbles.size(); i++) {
- Bubble b = mPendingBubbles.get(i);
- if (b.getKey().equals(entry.getKey())) {
- b.setEntry(entry);
- return b;
- }
+ Bubble getOrCreateBubble(NotificationEntry entry, Bubble persistedBubble) {
+ String key = entry != null ? entry.getKey() : persistedBubble.getKey();
+ Bubble bubbleToReturn = getBubbleInStackWithKey(key);
+
+ if (bubbleToReturn == null) {
+ bubbleToReturn = getOverflowBubbleWithKey(key);
+ if (bubbleToReturn != null) {
+ // Promoting from overflow
+ mOverflowBubbles.remove(bubbleToReturn);
+ } else if (mPendingBubbles.containsKey(key)) {
+ // Update while it was pending
+ bubbleToReturn = mPendingBubbles.get(key);
+ } else if (entry != null) {
+ // New bubble
+ bubbleToReturn = new Bubble(entry, mSuppressionListener);
+ } else {
+ // Persisted bubble being promoted
+ bubbleToReturn = persistedBubble;
}
- bubble = new Bubble(entry, mSuppressionListener);
- mPendingBubbles.add(bubble);
}
- return bubble;
+
+ if (entry != null) {
+ bubbleToReturn.setEntry(entry);
+ }
+ mPendingBubbles.put(key, bubbleToReturn);
+ return bubbleToReturn;
}
/**
@@ -270,7 +254,7 @@ public class BubbleData {
if (DEBUG_BUBBLE_DATA) {
Log.d(TAG, "notificationEntryUpdated: " + bubble);
}
- mPendingBubbles.remove(bubble); // No longer pending once we're here
+ mPendingBubbles.remove(bubble.getKey()); // No longer pending once we're here
Bubble prevBubble = getBubbleInStackWithKey(bubble.getKey());
suppressFlyout |= bubble.getEntry() == null
|| !bubble.getEntry().getRanking().visuallyInterruptive();
@@ -408,10 +392,8 @@ public class BubbleData {
Log.d(TAG, "doRemove: " + key);
}
// If it was pending remove it
- for (int i = 0; i < mPendingBubbles.size(); i++) {
- if (mPendingBubbles.get(i).getKey().equals(key)) {
- mPendingBubbles.remove(mPendingBubbles.get(i));
- }
+ if (mPendingBubbles.containsKey(key)) {
+ mPendingBubbles.remove(key);
}
int indexToRemove = indexForKey(key);
if (indexToRemove == -1) {
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleDataRepository.kt b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleDataRepository.kt
index c2b9195c8ba3..d20f40559b5d 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleDataRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleDataRepository.kt
@@ -77,7 +77,8 @@ internal class BubbleDataRepository @Inject constructor(
var shortcutId = b.shortcutInfo?.id
if (shortcutId == null) shortcutId = b.entry?.bubbleMetadata?.shortcutId
if (shortcutId == null) return@mapNotNull null
- BubbleEntity(userId, b.packageName, shortcutId, b.key)
+ BubbleEntity(userId, b.packageName, shortcutId, b.key, b.rawDesiredHeight,
+ b.rawDesiredHeightResId)
}
}
@@ -158,7 +159,8 @@ internal class BubbleDataRepository @Inject constructor(
val bubbles = entities.mapNotNull { entity ->
shortcutMap[ShortcutKey(entity.userId, entity.packageName)]
?.first { shortcutInfo -> entity.shortcutId == shortcutInfo.id }
- ?.let { shortcutInfo -> Bubble(entity.key, shortcutInfo) }
+ ?.let { shortcutInfo -> Bubble(entity.key, shortcutInfo, entity.desiredHeight,
+ entity.desiredHeightResId) }
}
uiScope.launch { cb(bubbles) }
}
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedView.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedView.java
index 64dc2ccc8b52..ec875f8f0e1a 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedView.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedView.java
@@ -22,6 +22,7 @@ import static android.content.Intent.FLAG_ACTIVITY_NEW_DOCUMENT;
import static android.graphics.PixelFormat.TRANSPARENT;
import static android.view.Display.INVALID_DISPLAY;
import static android.view.InsetsState.ITYPE_IME;
+import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT;
import static android.view.ViewRootImpl.NEW_INSETS_MODE_FULL;
import static android.view.ViewRootImpl.sNewInsetsMode;
import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS;
@@ -33,7 +34,7 @@ import static com.android.systemui.bubbles.BubbleDebugConfig.DEBUG_BUBBLE_EXPAND
import static com.android.systemui.bubbles.BubbleDebugConfig.TAG_BUBBLES;
import static com.android.systemui.bubbles.BubbleDebugConfig.TAG_WITH_CLASS_NAME;
-import android.annotation.Nullable;
+import android.annotation.SuppressLint;
import android.app.ActivityOptions;
import android.app.ActivityTaskManager;
import android.app.ActivityView;
@@ -41,10 +42,12 @@ import android.app.PendingIntent;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
+import android.content.res.Configuration;
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.graphics.Color;
import android.graphics.Insets;
+import android.graphics.Outline;
import android.graphics.Point;
import android.graphics.Rect;
import android.graphics.drawable.ShapeDrawable;
@@ -54,12 +57,19 @@ import android.os.RemoteException;
import android.util.AttributeSet;
import android.util.Log;
import android.view.Gravity;
+import android.view.SurfaceControl;
+import android.view.SurfaceView;
import android.view.View;
+import android.view.ViewGroup;
+import android.view.ViewOutlineProvider;
import android.view.WindowInsets;
import android.view.WindowManager;
import android.view.accessibility.AccessibilityNodeInfo;
+import android.widget.FrameLayout;
import android.widget.LinearLayout;
+import androidx.annotation.Nullable;
+
import com.android.internal.policy.ScreenDecorationsUtils;
import com.android.systemui.Dependency;
import com.android.systemui.R;
@@ -87,6 +97,7 @@ public class BubbleExpandedView extends LinearLayout {
// The triangle pointing to the expanded view
private View mPointerView;
private int mPointerMargin;
+ @Nullable private int[] mExpandedViewContainerLocation;
private AlphaOptimizedButton mSettingsIcon;
@@ -120,6 +131,16 @@ public class BubbleExpandedView extends LinearLayout {
private View mVirtualImeView;
private WindowManager mVirtualDisplayWindowManager;
private boolean mImeShowing = false;
+ private float mCornerRadius = 0f;
+
+ /**
+ * Container for the ActivityView that has a solid, round-rect background that shows if the
+ * ActivityView hasn't loaded.
+ */
+ private FrameLayout mActivityViewContainer = new FrameLayout(getContext());
+
+ /** The SurfaceView that the ActivityView draws to. */
+ @Nullable private SurfaceView mActivitySurface;
private ActivityView.StateCallback mStateCallback = new ActivityView.StateCallback() {
@Override
@@ -239,6 +260,7 @@ public class BubbleExpandedView extends LinearLayout {
mPointerMargin = res.getDimensionPixelSize(R.dimen.bubble_pointer_margin);
}
+ @SuppressLint("ClickableViewAccessibility")
@Override
protected void onFinishInflate() {
super.onFinishInflate();
@@ -253,8 +275,6 @@ public class BubbleExpandedView extends LinearLayout {
mPointerDrawable = new ShapeDrawable(TriangleShape.create(
mPointerWidth, mPointerHeight, true /* pointUp */));
- mPointerDrawable.setTint(Color.WHITE);
- mPointerView.setBackground(mPointerDrawable);
mPointerView.setVisibility(INVISIBLE);
mSettingsIconHeight = getContext().getResources().getDimensionPixelSize(
@@ -262,11 +282,33 @@ public class BubbleExpandedView extends LinearLayout {
mSettingsIcon = findViewById(R.id.settings_button);
mActivityView = new ActivityView(mContext, null /* attrs */, 0 /* defStyle */,
- true /* singleTaskInstance */);
+ true /* singleTaskInstance */, false /* usePublicVirtualDisplay*/,
+ true /* disableSurfaceViewBackgroundLayer */);
// Set ActivityView's alpha value as zero, since there is no view content to be shown.
setContentVisibility(false);
- addView(mActivityView);
+
+ mActivityViewContainer.setBackgroundColor(Color.WHITE);
+ mActivityViewContainer.setOutlineProvider(new ViewOutlineProvider() {
+ @Override
+ public void getOutline(View view, Outline outline) {
+ outline.setRoundRect(0, 0, view.getWidth(), view.getHeight(), mCornerRadius);
+ }
+ });
+ mActivityViewContainer.setClipToOutline(true);
+ mActivityViewContainer.addView(mActivityView);
+ mActivityViewContainer.setLayoutParams(
+ new ViewGroup.LayoutParams(WRAP_CONTENT, WRAP_CONTENT));
+ addView(mActivityViewContainer);
+
+ if (mActivityView != null
+ && mActivityView.getChildCount() > 0
+ && mActivityView.getChildAt(0) instanceof SurfaceView) {
+ // Retrieve the surface from the ActivityView so we can screenshot it and change its
+ // z-ordering. This should always be possible, since ActivityView's constructor adds the
+ // SurfaceView as its first child.
+ mActivitySurface = (SurfaceView) mActivityView.getChildAt(0);
+ }
// Expanded stack layout, top to bottom:
// Expanded view container
@@ -290,12 +332,73 @@ public class BubbleExpandedView extends LinearLayout {
}
return view.onApplyWindowInsets(insets);
});
+
+ final int expandedViewPadding =
+ res.getDimensionPixelSize(R.dimen.bubble_expanded_view_padding);
+
+ setPadding(
+ expandedViewPadding, expandedViewPadding, expandedViewPadding, expandedViewPadding);
+ setOnTouchListener((view, motionEvent) -> {
+ if (!usingActivityView()) {
+ return false;
+ }
+
+ final Rect avBounds = new Rect();
+ mActivityView.getBoundsOnScreen(avBounds);
+
+ // Consume and ignore events on the expanded view padding that are within the
+ // ActivityView's vertical bounds. These events are part of a back gesture, and so they
+ // should not collapse the stack (which all other touches on areas around the AV would
+ // do).
+ if (motionEvent.getRawY() >= avBounds.top && motionEvent.getRawY() <= avBounds.bottom) {
+ return true;
+ }
+
+ return false;
+ });
+
+ // BubbleStackView is forced LTR, but we want to respect the locale for expanded view layout
+ // so the Manage button appears on the right.
+ setLayoutDirection(LAYOUT_DIRECTION_LOCALE);
}
private String getBubbleKey() {
return mBubble != null ? mBubble.getKey() : "null";
}
+ /**
+ * Asks the ActivityView's surface to draw on top of all other views in the window. This is
+ * useful for ordering surfaces during animations, but should otherwise be set to false so that
+ * bubbles and menus can draw over the ActivityView.
+ */
+ void setSurfaceZOrderedOnTop(boolean onTop) {
+ if (mActivitySurface == null) {
+ return;
+ }
+
+ mActivitySurface.setZOrderedOnTop(onTop, true);
+ }
+
+ /** Return a GraphicBuffer with the contents of the ActivityView's underlying surface. */
+ @Nullable SurfaceControl.ScreenshotGraphicBuffer snapshotActivitySurface() {
+ if (mActivitySurface == null) {
+ return null;
+ }
+
+ return SurfaceControl.captureLayers(
+ mActivitySurface.getSurfaceControl(),
+ new Rect(0, 0, mActivityView.getWidth(), mActivityView.getHeight()),
+ 1 /* scale */);
+ }
+
+ int[] getActivityViewLocationOnScreen() {
+ if (mActivityView != null) {
+ return mActivityView.getLocationOnScreen();
+ } else {
+ return new int[]{0, 0};
+ }
+ }
+
void setManageClickListener(OnClickListener manageClickListener) {
findViewById(R.id.settings_button).setOnClickListener(manageClickListener);
}
@@ -314,18 +417,40 @@ public class BubbleExpandedView extends LinearLayout {
void applyThemeAttrs() {
final TypedArray ta = mContext.obtainStyledAttributes(
new int[] {android.R.attr.dialogCornerRadius});
- float cornerRadius = ta.getDimensionPixelSize(0, 0);
+ mCornerRadius = ta.getDimensionPixelSize(0, 0);
ta.recycle();
if (mActivityView != null && ScreenDecorationsUtils.supportsRoundedCornersOnWindows(
mContext.getResources())) {
- mActivityView.setCornerRadius(cornerRadius);
+ mActivityView.setCornerRadius(mCornerRadius);
+ }
+
+ final int mode =
+ getResources().getConfiguration().uiMode & Configuration.UI_MODE_NIGHT_MASK;
+ switch (mode) {
+ case Configuration.UI_MODE_NIGHT_NO:
+ mPointerDrawable.setTint(getResources().getColor(R.color.bubbles_pointer_light));
+ break;
+ case Configuration.UI_MODE_NIGHT_YES:
+ mPointerDrawable.setTint(getResources().getColor(R.color.bubbles_pointer_dark));
+ break;
+ }
+ mPointerView.setBackground(mPointerDrawable);
+ }
+
+ /**
+ * Hides the IME if it's showing. This is currently done by dispatching a back press to the AV.
+ */
+ void hideImeIfVisible() {
+ if (mKeyboardVisible) {
+ performBackPressIfNeeded();
}
}
@Override
protected void onDetachedFromWindow() {
super.onDetachedFromWindow();
+ hideImeIfVisible();
mKeyboardVisible = false;
mNeedsNewHeight = false;
if (mActivityView != null) {
@@ -357,6 +482,7 @@ public class BubbleExpandedView extends LinearLayout {
mPointerView.setAlpha(alpha);
if (mActivityView != null) {
mActivityView.setAlpha(alpha);
+ mActivityView.bringToFront();
}
}
@@ -449,7 +575,7 @@ public class BubbleExpandedView extends LinearLayout {
if (DEBUG_BUBBLE_EXPANDED_VIEW) {
Log.d(TAG, "update: bubble=" + (bubble != null ? bubble.getKey() : "null"));
}
- boolean isNew = mBubble == null;
+ boolean isNew = mBubble == null || didBackingContentChange(bubble);
if (isNew || bubble != null && bubble.getKey().equals(mBubble.getKey())) {
mBubble = bubble;
mSettingsIcon.setContentDescription(getResources().getString(
@@ -482,6 +608,12 @@ public class BubbleExpandedView extends LinearLayout {
}
}
+ private boolean didBackingContentChange(Bubble newBubble) {
+ boolean prevWasIntentBased = mBubble != null && mPendingIntent != null;
+ boolean newIsIntentBased = newBubble.getBubbleIntent() != null;
+ return prevWasIntentBased != newIsIntentBased;
+ }
+
/**
* Lets activity view know it should be shown / populated with activity content.
*/
@@ -510,6 +642,11 @@ public class BubbleExpandedView extends LinearLayout {
if (DEBUG_BUBBLE_EXPANDED_VIEW) {
Log.d(TAG, "updateHeight: bubble=" + getBubbleKey());
}
+
+ if (mExpandedViewContainerLocation == null) {
+ return;
+ }
+
if (usingActivityView()) {
float desiredHeight = mOverflowHeight;
if (!mIsOverflow) {
@@ -517,7 +654,7 @@ public class BubbleExpandedView extends LinearLayout {
}
float height = Math.min(desiredHeight, getMaxExpandedHeight());
height = Math.max(height, mIsOverflow? mOverflowHeight : mMinHeight);
- LayoutParams lp = (LayoutParams) mActivityView.getLayoutParams();
+ ViewGroup.LayoutParams lp = mActivityView.getLayoutParams();
mNeedsNewHeight = lp.height != height;
if (!mKeyboardVisible) {
// If the keyboard is visible... don't adjust the height because that will cause
@@ -527,7 +664,8 @@ public class BubbleExpandedView extends LinearLayout {
mNeedsNewHeight = false;
}
if (DEBUG_BUBBLE_EXPANDED_VIEW) {
- Log.d(TAG, "updateHeight: bubble=" + getBubbleKey() + " height=" + height
+ Log.d(TAG, "updateHeight: bubble=" + getBubbleKey()
+ + " height=" + height
+ " mNeedsNewHeight=" + mNeedsNewHeight);
}
}
@@ -535,28 +673,40 @@ public class BubbleExpandedView extends LinearLayout {
private int getMaxExpandedHeight() {
mWindowManager.getDefaultDisplay().getRealSize(mDisplaySize);
- int[] windowLocation = mActivityView.getLocationOnScreen();
int bottomInset = getRootWindowInsets() != null
? getRootWindowInsets().getStableInsetBottom()
: 0;
- return mDisplaySize.y - windowLocation[1] - mSettingsIconHeight - mPointerHeight
+
+ return mDisplaySize.y
+ - mExpandedViewContainerLocation[1]
+ - getPaddingTop()
+ - getPaddingBottom()
+ - mSettingsIconHeight
+ - mPointerHeight
- mPointerMargin - bottomInset;
}
/**
* Update appearance of the expanded view being displayed.
+ *
+ * @param containerLocationOnScreen The location on-screen of the container the expanded view is
+ * added to. This allows us to calculate max height without
+ * waiting for layout.
*/
- public void updateView() {
+ public void updateView(int[] containerLocationOnScreen) {
if (DEBUG_BUBBLE_EXPANDED_VIEW) {
Log.d(TAG, "updateView: bubble="
+ getBubbleKey());
}
+
+ mExpandedViewContainerLocation = containerLocationOnScreen;
+
if (usingActivityView()
&& mActivityView.getVisibility() == VISIBLE
&& mActivityView.isAttachedToWindow()) {
mActivityView.onLocationChanged();
+ updateHeight();
}
- updateHeight();
}
/**
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleFlyoutView.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleFlyoutView.java
index e12b325f5d05..8c76cda3290f 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleFlyoutView.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleFlyoutView.java
@@ -186,6 +186,9 @@ public class BubbleFlyoutView extends FrameLayout {
}
});
+ // Use locale direction so the text is aligned correctly.
+ setLayoutDirection(LAYOUT_DIRECTION_LOCALE);
+
mBgPaint.setColor(mFloatingBackgroundColor);
mLeftTriangleShape =
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleManageEducationView.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleManageEducationView.java
index f4d64322c7ff..47120124a55f 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleManageEducationView.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleManageEducationView.java
@@ -17,10 +17,8 @@
package com.android.systemui.bubbles;
import android.content.Context;
-import android.content.res.Resources;
import android.content.res.TypedArray;
import android.graphics.Color;
-import android.graphics.drawable.ShapeDrawable;
import android.util.AttributeSet;
import android.view.View;
import android.widget.LinearLayout;
@@ -28,7 +26,6 @@ import android.widget.TextView;
import com.android.internal.util.ContrastColorUtil;
import com.android.systemui.R;
-import com.android.systemui.recents.TriangleShape;
/**
* Educational view to highlight the manage button that allows a user to configure the settings
@@ -36,7 +33,6 @@ import com.android.systemui.recents.TriangleShape;
*/
public class BubbleManageEducationView extends LinearLayout {
- private View mPointerView;
private View mManageView;
public BubbleManageEducationView(Context context) {
@@ -70,26 +66,8 @@ public class BubbleManageEducationView extends LinearLayout {
ta.recycle();
textColor = ContrastColorUtil.ensureTextContrast(textColor, bgColor, true);
+ ((TextView) findViewById(R.id.user_education_title)).setTextColor(textColor);
((TextView) findViewById(R.id.user_education_description)).setTextColor(textColor);
-
- final Resources res = getResources();
- final int pointerWidth = res.getDimensionPixelSize(R.dimen.bubble_pointer_width);
- final int pointerHeight = res.getDimensionPixelSize(R.dimen.bubble_pointer_height);
-
- ShapeDrawable triangleShape =
- new ShapeDrawable(TriangleShape.create(
- pointerWidth, pointerHeight, false /* isPointingUp */));
- triangleShape.setTint(bgColor);
-
- mPointerView = findViewById(R.id.user_education_pointer);
- mPointerView.setBackground(triangleShape);
- }
-
- /**
- * Specifies the x value this pointer should point to.
- */
- public void setPointerPosition(int x) {
- mPointerView.setTranslationX(x - (mPointerView.getWidth() / 2));
}
/**
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleOverflow.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleOverflow.java
index b77e2261e39b..0c62e9f9f548 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleOverflow.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleOverflow.java
@@ -62,13 +62,12 @@ public class BubbleOverflow implements BubbleViewProvider {
void setUpOverflow(ViewGroup parentViewGroup, BubbleStackView stackView) {
updateDimensions();
-
mExpandedView = (BubbleExpandedView) mInflater.inflate(
R.layout.bubble_expanded_view, parentViewGroup /* root */,
false /* attachToRoot */);
mExpandedView.setOverflow(true);
mExpandedView.setStackView(stackView);
-
+ mExpandedView.applyThemeAttrs();
updateIcon(mContext, parentViewGroup);
}
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleOverflowActivity.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleOverflowActivity.java
index bea4ba776beb..b4672c14b49a 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleOverflowActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleOverflowActivity.java
@@ -22,6 +22,7 @@ import static com.android.systemui.bubbles.BubbleDebugConfig.TAG_WITH_CLASS_NAME
import android.app.Activity;
import android.content.Context;
+import android.content.pm.ShortcutInfo;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.content.res.TypedArray;
@@ -74,6 +75,20 @@ public class BubbleOverflowActivity extends Activity {
}
return false;
}
+
+ @Override
+ public int getColumnCountForAccessibility(RecyclerView.Recycler recycler,
+ RecyclerView.State state) {
+ int bubbleCount = state.getItemCount();
+ int columnCount = super.getColumnCountForAccessibility(recycler, state);
+ if (bubbleCount < columnCount) {
+ // If there are 4 columns and bubbles <= 3,
+ // TalkBack says "AppName 1 of 4 in list 4 items"
+ // This is a workaround until TalkBack bug is fixed for GridLayoutManager
+ return bubbleCount;
+ }
+ return columnCount;
+ }
}
@Inject
@@ -204,6 +219,8 @@ public class BubbleOverflowActivity extends Activity {
}
class BubbleOverflowAdapter extends RecyclerView.Adapter<BubbleOverflowAdapter.ViewHolder> {
+ private static final String TAG = TAG_WITH_CLASS_NAME ? "BubbleOverflowAdapter" : TAG_BUBBLES;
+
private Context mContext;
private Consumer<Bubble> mPromoteBubbleFromOverflow;
private List<Bubble> mBubbles;
@@ -282,11 +299,19 @@ class BubbleOverflowAdapter extends RecyclerView.Adapter<BubbleOverflowAdapter.V
}
});
- Bubble.FlyoutMessage message = b.getFlyoutMessage();
- if (message != null && message.senderName != null) {
- vh.textView.setText(message.senderName.toString());
+ // If the bubble was persisted, the entry is null but it should have shortcut info
+ ShortcutInfo info = b.getEntry() == null
+ ? b.getShortcutInfo()
+ : b.getEntry().getRanking().getShortcutInfo();
+ if (info == null) {
+ Log.d(TAG, "ShortcutInfo required to bubble but none found for " + b);
} else {
- vh.textView.setText(b.getAppName());
+ CharSequence label = info.getLabel();
+ if (label == null) {
+ vh.textView.setText(b.getAppName());
+ } else {
+ vh.textView.setText(label.toString());
+ }
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java
index 239132ea292b..1437501a9ea1 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java
@@ -47,6 +47,7 @@ import android.graphics.PointF;
import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.Region;
+import android.graphics.drawable.TransitionDrawable;
import android.os.Bundle;
import android.provider.Settings;
import android.util.Log;
@@ -55,6 +56,8 @@ import android.view.DisplayCutout;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.MotionEvent;
+import android.view.SurfaceControl;
+import android.view.SurfaceView;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewOutlineProvider;
@@ -78,9 +81,10 @@ import androidx.dynamicanimation.animation.SpringForce;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.ContrastColorUtil;
-import com.android.internal.widget.ViewClippingUtil;
+import com.android.systemui.Interpolators;
import com.android.systemui.Prefs;
import com.android.systemui.R;
+import com.android.systemui.bubbles.animation.AnimatableScaleMatrix;
import com.android.systemui.bubbles.animation.ExpandedAnimationController;
import com.android.systemui.bubbles.animation.PhysicsAnimationLayout;
import com.android.systemui.bubbles.animation.StackAnimationController;
@@ -88,6 +92,7 @@ import com.android.systemui.model.SysUiState;
import com.android.systemui.shared.system.QuickStepContract;
import com.android.systemui.shared.system.SysUiStatsLog;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
+import com.android.systemui.statusbar.phone.CollapsedStatusBarFragment;
import com.android.systemui.statusbar.phone.NotificationShadeWindowController;
import com.android.systemui.util.DismissCircleView;
import com.android.systemui.util.FloatingContentCoordinator;
@@ -133,6 +138,9 @@ public class BubbleStackView extends FrameLayout
/** Percent to darken the bubbles when they're in the dismiss target. */
private static final float DARKEN_PERCENT = 0.3f;
+ /** Duration of the dismiss scrim fading in/out. */
+ private static final int DISMISS_TRANSITION_DURATION_MS = 200;
+
/** How long to wait, in milliseconds, before hiding the flyout. */
@VisibleForTesting
static final int FLYOUT_HIDE_AFTER = 5000;
@@ -142,6 +150,16 @@ public class BubbleStackView extends FrameLayout
StackAnimationController.IME_ANIMATION_STIFFNESS,
StackAnimationController.DEFAULT_BOUNCINESS);
+ private final PhysicsAnimator.SpringConfig mScaleInSpringConfig =
+ new PhysicsAnimator.SpringConfig(300f, 0.9f);
+
+ private final PhysicsAnimator.SpringConfig mScaleOutSpringConfig =
+ new PhysicsAnimator.SpringConfig(900f, 1f);
+
+ private final PhysicsAnimator.SpringConfig mTranslateSpringConfig =
+ new PhysicsAnimator.SpringConfig(
+ SpringForce.STIFFNESS_LOW, SpringForce.DAMPING_RATIO_NO_BOUNCY);
+
/**
* Interface to synchronize {@link View} state and the screen.
*
@@ -181,8 +199,6 @@ public class BubbleStackView extends FrameLayout
private Point mDisplaySize;
- private final SpringAnimation mExpandedViewXAnim;
- private final SpringAnimation mExpandedViewYAnim;
private final BubbleData mBubbleData;
private final ValueAnimator mDesaturateAndDarkenAnimator;
@@ -194,6 +210,24 @@ public class BubbleStackView extends FrameLayout
private FrameLayout mExpandedViewContainer;
+ /** Matrix used to scale the expanded view container with a given pivot point. */
+ private final AnimatableScaleMatrix mExpandedViewContainerMatrix = new AnimatableScaleMatrix();
+
+ /**
+ * SurfaceView that we draw screenshots of animating-out bubbles into. This allows us to animate
+ * between bubble activities without needing both to be alive at the same time.
+ */
+ private SurfaceView mAnimatingOutSurfaceView;
+
+ /** Container for the animating-out SurfaceView. */
+ private FrameLayout mAnimatingOutSurfaceContainer;
+
+ /**
+ * Buffer containing a screenshot of the animating-out bubble. This is drawn into the
+ * SurfaceView during animations.
+ */
+ private SurfaceControl.ScreenshotGraphicBuffer mAnimatingOutBubbleBuffer;
+
private BubbleFlyoutView mFlyout;
/** Runnable that fades out the flyout and then sets it to GONE. */
private Runnable mHideFlyout = () -> animateFlyoutCollapsed(true, 0 /* velX */);
@@ -225,8 +259,7 @@ public class BubbleStackView extends FrameLayout
private int mBubblePaddingTop;
private int mBubbleTouchPadding;
private int mExpandedViewPadding;
- private int mExpandedAnimateXDistance;
- private int mExpandedAnimateYDistance;
+ private int mCornerRadius;
private int mPointerHeight;
private int mStatusBarHeight;
private int mImeOffset;
@@ -239,6 +272,9 @@ public class BubbleStackView extends FrameLayout
/** Whether a touch gesture, such as a stack/bubble drag or flyout drag, is in progress. */
private boolean mIsGestureInProgress = false;
+ /** Whether or not the stack is temporarily invisible off the side of the screen. */
+ private boolean mTemporarilyInvisible = false;
+
/** Description of current animation controller state. */
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
pw.println("Stack view state:");
@@ -261,7 +297,7 @@ public class BubbleStackView extends FrameLayout
private boolean mShowingDismiss = false;
/** The view to desaturate/darken when magneted to the dismiss target. */
- private View mDesaturateAndDarkenTargetView;
+ @Nullable private View mDesaturateAndDarkenTargetView;
private LayoutInflater mInflater;
@@ -283,20 +319,6 @@ public class BubbleStackView extends FrameLayout
private ViewTreeObserver.OnDrawListener mSystemGestureExcludeUpdater =
this::updateSystemGestureExcludeRects;
- private ViewClippingUtil.ClippingParameters mClippingParameters =
- new ViewClippingUtil.ClippingParameters() {
-
- @Override
- public boolean shouldFinish(View view) {
- return false;
- }
-
- @Override
- public boolean isClippingEnablingAllowed(View view) {
- return !mIsExpanded;
- }
- };
-
/** Float property that 'drags' the flyout. */
private final FloatPropertyCompat mFlyoutCollapseProperty =
new FloatPropertyCompat("FlyoutCollapseSpring") {
@@ -339,7 +361,11 @@ public class BubbleStackView extends FrameLayout
@NonNull
private final SurfaceSynchronizer mSurfaceSynchronizer;
- private final NotificationShadeWindowController mNotificationShadeWindowController;
+ /**
+ * Callback to run when the IME visibility changes - BubbleController uses this to update the
+ * Bubbles window focusability flags with the WindowManager.
+ */
+ public final Consumer<Boolean> mOnImeVisibilityChanged;
/**
* The currently magnetized object, which is being dragged and will be attracted to the magnetic
@@ -637,6 +663,7 @@ public class BubbleStackView extends FrameLayout
}
};
+ private View mDismissTargetCircle;
private ViewGroup mDismissTargetContainer;
private PhysicsAnimator<View> mDismissTargetAnimator;
private PhysicsAnimator.SpringConfig mDismissTargetSpring = new PhysicsAnimator.SpringConfig(
@@ -666,15 +693,14 @@ public class BubbleStackView extends FrameLayout
@Nullable SurfaceSynchronizer synchronizer,
FloatingContentCoordinator floatingContentCoordinator,
SysUiState sysUiState,
- NotificationShadeWindowController notificationShadeWindowController,
- Runnable allBubblesAnimatedOutAction) {
+ Runnable allBubblesAnimatedOutAction,
+ Consumer<Boolean> onImeVisibilityChanged) {
super(context);
mBubbleData = data;
mInflater = LayoutInflater.from(context);
mSysUiState = sysUiState;
- mNotificationShadeWindowController = notificationShadeWindowController;
Resources res = getResources();
mMaxBubbles = res.getInteger(R.integer.bubbles_max_rendered);
@@ -682,10 +708,6 @@ public class BubbleStackView extends FrameLayout
mBubbleElevation = res.getDimensionPixelSize(R.dimen.bubble_elevation);
mBubblePaddingTop = res.getDimensionPixelSize(R.dimen.bubble_padding_top);
mBubbleTouchPadding = res.getDimensionPixelSize(R.dimen.bubble_touch_padding);
- mExpandedAnimateXDistance =
- res.getDimensionPixelSize(R.dimen.bubble_expanded_animate_x_distance);
- mExpandedAnimateYDistance =
- res.getDimensionPixelSize(R.dimen.bubble_expanded_animate_y_distance);
mPointerHeight = res.getDimensionPixelSize(R.dimen.bubble_pointer_height);
mStatusBarHeight =
@@ -700,6 +722,11 @@ public class BubbleStackView extends FrameLayout
mExpandedViewPadding = res.getDimensionPixelSize(R.dimen.bubble_expanded_view_padding);
int elevation = res.getDimensionPixelSize(R.dimen.bubble_elevation);
+ final TypedArray ta = mContext.obtainStyledAttributes(
+ new int[] {android.R.attr.dialogCornerRadius});
+ mCornerRadius = ta.getDimensionPixelSize(0, 0);
+ ta.recycle();
+
final Runnable onBubbleAnimatedOut = () -> {
if (getBubbleCount() == 0) {
allBubblesAnimatedOutAction.run();
@@ -716,6 +743,12 @@ public class BubbleStackView extends FrameLayout
setUpUserEducation();
+ // Force LTR by default since most of the Bubbles UI is positioned manually by the user, or
+ // is centered. It greatly simplifies translation positioning/animations. Views that will
+ // actually lay out differently in RTL, such as the flyout and expanded view, will set their
+ // layout direction to LOCALE.
+ setLayoutDirection(LAYOUT_DIRECTION_LTR);
+
mBubbleContainer = new PhysicsAnimationLayout(context);
mBubbleContainer.setActiveController(mStackAnimationController);
mBubbleContainer.setElevation(elevation);
@@ -724,11 +757,27 @@ public class BubbleStackView extends FrameLayout
mExpandedViewContainer = new FrameLayout(context);
mExpandedViewContainer.setElevation(elevation);
- mExpandedViewContainer.setPadding(mExpandedViewPadding, mExpandedViewPadding,
- mExpandedViewPadding, mExpandedViewPadding);
mExpandedViewContainer.setClipChildren(false);
addView(mExpandedViewContainer);
+ mAnimatingOutSurfaceContainer = new FrameLayout(getContext());
+ mAnimatingOutSurfaceContainer.setLayoutParams(
+ new ViewGroup.LayoutParams(WRAP_CONTENT, WRAP_CONTENT));
+ addView(mAnimatingOutSurfaceContainer);
+
+ mAnimatingOutSurfaceView = new SurfaceView(getContext());
+ mAnimatingOutSurfaceView.setUseAlpha();
+ mAnimatingOutSurfaceView.setZOrderOnTop(true);
+ mAnimatingOutSurfaceView.setCornerRadius(mCornerRadius);
+ mAnimatingOutSurfaceView.setLayoutParams(new ViewGroup.LayoutParams(0, 0));
+ mAnimatingOutSurfaceContainer.addView(mAnimatingOutSurfaceView);
+
+ mAnimatingOutSurfaceContainer.setPadding(
+ mExpandedViewPadding,
+ mExpandedViewPadding,
+ mExpandedViewPadding,
+ mExpandedViewPadding);
+
setUpManageMenu();
setUpFlyout();
@@ -738,25 +787,32 @@ public class BubbleStackView extends FrameLayout
mFlyoutTransitionSpring.addEndListener(mAfterFlyoutTransitionSpring);
final int targetSize = res.getDimensionPixelSize(R.dimen.dismiss_circle_size);
- final View targetView = new DismissCircleView(context);
+ mDismissTargetCircle = new DismissCircleView(context);
final FrameLayout.LayoutParams newParams =
new FrameLayout.LayoutParams(targetSize, targetSize);
- newParams.gravity = Gravity.CENTER;
- targetView.setLayoutParams(newParams);
- mDismissTargetAnimator = PhysicsAnimator.getInstance(targetView);
+ newParams.gravity = Gravity.BOTTOM | Gravity.CENTER_HORIZONTAL;
+ mDismissTargetCircle.setLayoutParams(newParams);
+ mDismissTargetAnimator = PhysicsAnimator.getInstance(mDismissTargetCircle);
mDismissTargetContainer = new FrameLayout(context);
mDismissTargetContainer.setLayoutParams(new FrameLayout.LayoutParams(
MATCH_PARENT,
getResources().getDimensionPixelSize(R.dimen.floating_dismiss_gradient_height),
Gravity.BOTTOM));
+
+ final int bottomMargin =
+ getResources().getDimensionPixelSize(R.dimen.floating_dismiss_bottom_margin);
+ mDismissTargetContainer.setPadding(0, 0, 0, bottomMargin);
+ mDismissTargetContainer.setClipToPadding(false);
mDismissTargetContainer.setClipChildren(false);
- mDismissTargetContainer.addView(targetView);
+ mDismissTargetContainer.addView(mDismissTargetCircle);
mDismissTargetContainer.setVisibility(View.INVISIBLE);
+ mDismissTargetContainer.setBackgroundResource(
+ R.drawable.floating_dismiss_gradient_transition);
addView(mDismissTargetContainer);
// Start translated down so the target springs up.
- targetView.setTranslationY(
+ mDismissTargetCircle.setTranslationY(
getResources().getDimensionPixelSize(R.dimen.floating_dismiss_gradient_height));
final ContentResolver contentResolver = getContext().getContentResolver();
@@ -765,27 +821,7 @@ public class BubbleStackView extends FrameLayout
// Save the MagneticTarget instance for the newly set up view - we'll add this to the
// MagnetizedObjects.
- mMagneticTarget = new MagnetizedObject.MagneticTarget(targetView, dismissRadius);
-
- mExpandedViewXAnim =
- new SpringAnimation(mExpandedViewContainer, DynamicAnimation.TRANSLATION_X);
- mExpandedViewXAnim.setSpring(
- new SpringForce()
- .setStiffness(SpringForce.STIFFNESS_LOW)
- .setDampingRatio(SpringForce.DAMPING_RATIO_LOW_BOUNCY));
-
- mExpandedViewYAnim =
- new SpringAnimation(mExpandedViewContainer, DynamicAnimation.TRANSLATION_Y);
- mExpandedViewYAnim.setSpring(
- new SpringForce()
- .setStiffness(SpringForce.STIFFNESS_LOW)
- .setDampingRatio(SpringForce.DAMPING_RATIO_LOW_BOUNCY));
- mExpandedViewYAnim.addEndListener((anim, cancelled, value, velocity) -> {
- if (mIsExpanded && mExpandedBubble != null
- && mExpandedBubble.getExpandedView() != null) {
- mExpandedBubble.getExpandedView().updateView();
- }
- });
+ mMagneticTarget = new MagnetizedObject.MagneticTarget(mDismissTargetCircle, dismissRadius);
setClipChildren(false);
setFocusable(true);
@@ -793,7 +829,11 @@ public class BubbleStackView extends FrameLayout
setUpOverflow();
+ mOnImeVisibilityChanged = onImeVisibilityChanged;
+
setOnApplyWindowInsetsListener((View view, WindowInsets insets) -> {
+ onImeVisibilityChanged.accept(insets.getInsets(WindowInsets.Type.ime()).bottom > 0);
+
if (!mIsExpanded || mIsExpansionAnimating) {
return view.onApplyWindowInsets(insets);
}
@@ -817,7 +857,7 @@ public class BubbleStackView extends FrameLayout
if (mIsExpanded) {
mExpandedViewContainer.setTranslationY(getExpandedViewY());
if (mExpandedBubble != null && mExpandedBubble.getExpandedView() != null) {
- mExpandedBubble.getExpandedView().updateView();
+ mExpandedBubble.getExpandedView().updateView(getLocationOnScreen());
}
}
@@ -877,7 +917,10 @@ public class BubbleStackView extends FrameLayout
// Update the paint and apply it to the bubble container.
mDesaturateAndDarkenPaint.setColorFilter(new ColorMatrixColorFilter(animatedMatrix));
- mDesaturateAndDarkenTargetView.setLayerPaint(mDesaturateAndDarkenPaint);
+
+ if (mDesaturateAndDarkenTargetView != null) {
+ mDesaturateAndDarkenTargetView.setLayerPaint(mDesaturateAndDarkenPaint);
+ }
});
// If the stack itself is touched, it means none of its touchable views (bubbles, flyouts,
@@ -893,6 +936,38 @@ public class BubbleStackView extends FrameLayout
return true;
});
+
+ animate()
+ .setInterpolator(Interpolators.PANEL_CLOSE_ACCELERATED)
+ .setDuration(CollapsedStatusBarFragment.FADE_IN_DURATION);
+ }
+
+ /**
+ * Sets whether or not the stack should become temporarily invisible by moving off the side of
+ * the screen.
+ *
+ * If a flyout comes in while it's invisible, it will animate back in while the flyout is
+ * showing but disappear again when the flyout is gone.
+ */
+ public void setTemporarilyInvisible(boolean invisible) {
+ mTemporarilyInvisible = invisible;
+ animateTemporarilyInvisible();
+ }
+
+ /**
+ * Animates onto or off the screen depending on whether we're temporarily invisible, and whether
+ * a flyout is visible.
+ */
+ private void animateTemporarilyInvisible() {
+ if (mTemporarilyInvisible && mFlyout.getVisibility() != View.VISIBLE) {
+ if (mStackAnimationController.isStackOnLeftSide()) {
+ animate().translationX(-mBubbleSize).start();
+ } else {
+ animate().translationX(mBubbleSize).start();
+ }
+ } else {
+ animate().translationX(0).start();
+ }
}
private void setUpManageMenu() {
@@ -906,15 +981,10 @@ public class BubbleStackView extends FrameLayout
PhysicsAnimator.getInstance(mManageMenu).setDefaultSpringConfig(mManageSpringConfig);
- final TypedArray ta = mContext.obtainStyledAttributes(
- new int[] {android.R.attr.dialogCornerRadius});
- final int menuCornerRadius = ta.getDimensionPixelSize(0, 0);
- ta.recycle();
-
mManageMenu.setOutlineProvider(new ViewOutlineProvider() {
@Override
public void getOutline(View view, Outline outline) {
- outline.setRoundRect(0, 0, view.getWidth(), view.getHeight(), menuCornerRadius);
+ outline.setRoundRect(0, 0, view.getWidth(), view.getHeight(), mCornerRadius);
}
});
mManageMenu.setClipToOutline(true);
@@ -952,6 +1022,9 @@ public class BubbleStackView extends FrameLayout
mManageSettingsIcon = mManageMenu.findViewById(R.id.bubble_manage_menu_settings_icon);
mManageSettingsText = mManageMenu.findViewById(R.id.bubble_manage_menu_settings_name);
+
+ // The menu itself should respect locale direction so the icons are on the correct side.
+ mManageMenu.setLayoutDirection(LAYOUT_DIRECTION_LOCALE);
addView(mManageMenu);
}
@@ -1027,13 +1100,11 @@ public class BubbleStackView extends FrameLayout
mBubbleOverflow.setUpOverflow(mBubbleContainer, this);
} else {
mBubbleContainer.removeView(mBubbleOverflow.getBtn());
- mBubbleOverflow.updateDimensions();
- mBubbleOverflow.updateIcon(mContext,this);
+ mBubbleOverflow.setUpOverflow(mBubbleContainer, this);
overflowBtnIndex = mBubbleContainer.getChildCount();
}
mBubbleContainer.addView(mBubbleOverflow.getBtn(), overflowBtnIndex,
new FrameLayout.LayoutParams(WRAP_CONTENT, WRAP_CONTENT));
-
mBubbleOverflow.getBtn().setOnClickListener(v -> setSelectedBubble(mBubbleOverflow));
}
/**
@@ -1044,6 +1115,7 @@ public class BubbleStackView extends FrameLayout
setUpOverflow();
setUpUserEducation();
setUpManageMenu();
+ updateExpandedViewTheme();
}
/** Respond to the phone being rotated by repositioning the stack and hiding any flyouts. */
@@ -1075,6 +1147,16 @@ public class BubbleStackView extends FrameLayout
mShowingManage = false;
}
+ /** Tells the views with locale-dependent layout direction to resolve the new direction. */
+ public void onLayoutDirectionChanged() {
+ mManageMenu.resolveLayoutDirection();
+ mFlyout.resolveLayoutDirection();
+
+ if (mExpandedBubble != null && mExpandedBubble.getExpandedView() != null) {
+ mExpandedBubble.getExpandedView().resolveLayoutDirection();
+ }
+ }
+
/** Respond to the display size change by recalculating view size and location. */
public void onDisplaySizeChanged() {
setUpOverflow();
@@ -1095,6 +1177,13 @@ public class BubbleStackView extends FrameLayout
}
mExpandedAnimationController.updateResources(mOrientation, mDisplaySize);
mStackAnimationController.updateResources(mOrientation);
+
+ final int targetSize = res.getDimensionPixelSize(R.dimen.dismiss_circle_size);
+ mDismissTargetCircle.getLayoutParams().width = targetSize;
+ mDismissTargetCircle.getLayoutParams().height = targetSize;
+ mDismissTargetCircle.requestLayout();
+
+ mMagneticTarget.setMagneticFieldRadiusPx(mBubbleSize * 2);
}
@Override
@@ -1128,6 +1217,18 @@ public class BubbleStackView extends FrameLayout
setupLocalMenu(info);
}
+ void updateExpandedViewTheme() {
+ final List<Bubble> bubbles = mBubbleData.getBubbles();
+ if (bubbles.isEmpty()) {
+ return;
+ }
+ bubbles.forEach(bubble -> {
+ if (bubble.getExpandedView() != null) {
+ bubble.getExpandedView().applyThemeAttrs();
+ }
+ });
+ }
+
void setupLocalMenu(AccessibilityNodeInfo info) {
Resources res = mContext.getResources();
@@ -1312,7 +1413,6 @@ public class BubbleStackView extends FrameLayout
mBubbleContainer.addView(bubble.getIconView(), 0,
new FrameLayout.LayoutParams(WRAP_CONTENT, WRAP_CONTENT));
- ViewClippingUtil.setClippingDeactivated(bubble.getIconView(), true, mClippingParameters);
animateInFlyoutForBubble(bubble);
requestUpdate();
logBubbleEvent(bubble, SysUiStatsLog.BUBBLE_UICHANGED__ACTION__POSTED);
@@ -1380,6 +1480,31 @@ public class BubbleStackView extends FrameLayout
mBubbleData.setShowingOverflow(true);
}
+ // If we're expanded, screenshot the currently expanded bubble (before expanding the newly
+ // selected bubble) so we can animate it out.
+ if (mIsExpanded && mExpandedBubble != null && mExpandedBubble.getExpandedView() != null) {
+ if (mExpandedBubble != null && mExpandedBubble.getExpandedView() != null) {
+ // Before screenshotting, have the real ActivityView show on top of other surfaces
+ // so that the screenshot doesn't flicker on top of it.
+ mExpandedBubble.getExpandedView().setSurfaceZOrderedOnTop(true);
+ }
+
+ try {
+ screenshotAnimatingOutBubbleIntoSurface((success) -> {
+ mAnimatingOutSurfaceContainer.setVisibility(
+ success ? View.VISIBLE : View.INVISIBLE);
+ showNewlySelectedBubble(bubbleToSelect);
+ });
+ } catch (Exception e) {
+ showNewlySelectedBubble(bubbleToSelect);
+ e.printStackTrace();
+ }
+ } else {
+ showNewlySelectedBubble(bubbleToSelect);
+ }
+ }
+
+ private void showNewlySelectedBubble(BubbleViewProvider bubbleToSelect) {
final BubbleViewProvider previouslySelected = mExpandedBubble;
mExpandedBubble = bubbleToSelect;
updatePointerPosition();
@@ -1507,12 +1632,19 @@ public class BubbleStackView extends FrameLayout
final int inset = getResources().getDimensionPixelSize(
R.dimen.bubbles_manage_education_top_inset);
mManageEducationView.bringToFront();
- mManageEducationView.setManageViewPosition(mTempRect.left,
- mTempRect.top - viewHeight + inset);
- mManageEducationView.setPointerPosition(mTempRect.centerX() - mTempRect.left);
+ mManageEducationView.setManageViewPosition(0, mTempRect.top - viewHeight + inset);
mManageEducationView.animate()
.setDuration(ANIMATE_STACK_USER_EDUCATION_DURATION)
.setInterpolator(FAST_OUT_SLOW_IN).alpha(1);
+ mManageEducationView.findViewById(R.id.manage).setOnClickListener(view -> {
+ mExpandedBubble.getExpandedView().findViewById(R.id.settings_button)
+ .performClick();
+ maybeShowManageEducation(false);
+ });
+ mManageEducationView.findViewById(R.id.got_it).setOnClickListener(view ->
+ maybeShowManageEducation(false));
+ mManageEducationView.setOnClickListener(view ->
+ maybeShowManageEducation(false));
});
Prefs.putBoolean(getContext(), HAS_SEEN_BUBBLES_MANAGE_EDUCATION, true);
} else if (!show
@@ -1569,84 +1701,224 @@ public class BubbleStackView extends FrameLayout
}
}
+ void hideImeFromExpandedBubble() {
+ if (mExpandedBubble != null && mExpandedBubble.getExpandedView() != null) {
+ // Hide the currently expanded bubble's IME if it's visible before switching to a new
+ // bubble.
+ mExpandedBubble.getExpandedView().hideImeIfVisible();
+ }
+ }
+
private void beforeExpandedViewAnimation() {
+ mIsExpansionAnimating = true;
hideFlyoutImmediate();
updateExpandedBubble();
updateExpandedView();
- mIsExpansionAnimating = true;
}
private void afterExpandedViewAnimation() {
- updateExpandedView();
mIsExpansionAnimating = false;
+ updateExpandedView();
requestUpdate();
}
+ private void animateExpansion() {
+ mIsExpanded = true;
+ hideStackUserEducation(true /* fromExpansion */);
+ beforeExpandedViewAnimation();
+
+ mBubbleContainer.setActiveController(mExpandedAnimationController);
+ updateOverflowVisibility();
+ updatePointerPosition();
+ mExpandedAnimationController.expandFromStack(() -> {
+ afterExpandedViewAnimation();
+ maybeShowManageEducation(true);
+ } /* after */);
+
+ mExpandedViewContainer.setTranslationX(0);
+ mExpandedViewContainer.setTranslationY(getExpandedViewY());
+ mExpandedViewContainer.setAlpha(1f);
+
+ // X-value of the bubble we're expanding, once it's settled in its row.
+ final float bubbleWillBeAtX =
+ mExpandedAnimationController.getBubbleLeft(
+ mBubbleData.getBubbles().indexOf(mExpandedBubble));
+
+ // How far horizontally the bubble will be animating. We'll wait a bit longer for bubbles
+ // that are animating farther, so that the expanded view doesn't move as much.
+ final float horizontalDistanceAnimated =
+ Math.abs(bubbleWillBeAtX
+ - mStackAnimationController.getStackPosition().x);
+
+ // Wait for the path animation target to reach its end, and add a small amount of extra time
+ // if the bubble is moving a lot horizontally.
+ long startDelay = 0L;
+
+ // Should not happen since we lay out before expanding, but just in case...
+ if (getWidth() > 0) {
+ startDelay = (long)
+ (ExpandedAnimationController.EXPAND_COLLAPSE_TARGET_ANIM_DURATION
+ + (horizontalDistanceAnimated / getWidth()) * 30);
+ }
+
+ // Set the pivot point for the scale, so the expanded view animates out from the bubble.
+ mExpandedViewContainerMatrix.setScale(
+ 0f, 0f,
+ bubbleWillBeAtX + mBubbleSize / 2f, getExpandedViewY());
+ mExpandedViewContainer.setAnimationMatrix(mExpandedViewContainerMatrix);
+
+ if (mExpandedBubble != null && mExpandedBubble.getExpandedView() != null) {
+ mExpandedBubble.getExpandedView().setSurfaceZOrderedOnTop(false);
+ }
+
+ postDelayed(() -> PhysicsAnimator.getInstance(mExpandedViewContainerMatrix)
+ .spring(AnimatableScaleMatrix.SCALE_X,
+ AnimatableScaleMatrix.getAnimatableValueForScaleFactor(1f),
+ mScaleInSpringConfig)
+ .spring(AnimatableScaleMatrix.SCALE_Y,
+ AnimatableScaleMatrix.getAnimatableValueForScaleFactor(1f),
+ mScaleInSpringConfig)
+ .addUpdateListener((target, values) -> {
+ mExpandedViewContainerMatrix.postTranslate(
+ mExpandedBubble.getIconView().getTranslationX()
+ - bubbleWillBeAtX,
+ 0);
+ mExpandedViewContainer.setAnimationMatrix(mExpandedViewContainerMatrix);
+ })
+ .withEndActions(() -> {
+ if (mExpandedBubble != null && mExpandedBubble.getExpandedView() != null) {
+ mExpandedBubble.getExpandedView().setSurfaceZOrderedOnTop(false);
+ }
+ })
+ .start(), startDelay);
+
+ }
+
private void animateCollapse() {
// Hide the menu if it's visible.
showManageMenu(false);
mIsExpanded = false;
- final BubbleViewProvider previouslySelected = mExpandedBubble;
- beforeExpandedViewAnimation();
- maybeShowManageEducation(false);
- if (DEBUG_BUBBLE_STACK_VIEW) {
- Log.d(TAG, "animateCollapse");
- Log.d(TAG, BubbleDebugConfig.formatBubblesString(getBubblesOnScreen(),
- mExpandedBubble));
- }
- updateOverflowVisibility();
mBubbleContainer.cancelAllAnimations();
- mExpandedAnimationController.collapseBackToStack(
+
+ // If we were in the middle of swapping, the animating-out surface would have been scaling
+ // to zero - finish it off.
+ PhysicsAnimator.getInstance(mAnimatingOutSurfaceContainer).cancel();
+ mAnimatingOutSurfaceContainer.setScaleX(0f);
+ mAnimatingOutSurfaceContainer.setScaleY(0f);
+
+ if (mExpandedBubble != null && mExpandedBubble.getExpandedView() != null) {
+ mExpandedBubble.getExpandedView().hideImeIfVisible();
+ }
+
+ final long startDelay =
+ (long) (ExpandedAnimationController.EXPAND_COLLAPSE_TARGET_ANIM_DURATION * 0.6f);
+ postDelayed(() -> mExpandedAnimationController.collapseBackToStack(
mStackAnimationController.getStackPositionAlongNearestHorizontalEdge()
/* collapseTo */,
() -> {
mBubbleContainer.setActiveController(mStackAnimationController);
+ }), startDelay);
+
+ // We want to visually collapse into this bubble during the animation.
+ final View expandingFromBubble = mExpandedBubble.getIconView();
+
+ // X-value the bubble is animating from (back into the stack).
+ final float expandingFromBubbleAtX =
+ mExpandedAnimationController.getBubbleLeft(
+ mBubbleData.getBubbles().indexOf(mExpandedBubble));
+
+ // Set the pivot point.
+ mExpandedViewContainerMatrix.setScale(
+ 1f, 1f,
+ expandingFromBubbleAtX + mBubbleSize / 2f,
+ getExpandedViewY());
+
+ PhysicsAnimator.getInstance(mExpandedViewContainerMatrix).cancel();
+ PhysicsAnimator.getInstance(mExpandedViewContainerMatrix)
+ .spring(AnimatableScaleMatrix.SCALE_X, 0f, mScaleOutSpringConfig)
+ .spring(AnimatableScaleMatrix.SCALE_Y, 0f, mScaleOutSpringConfig)
+ .addUpdateListener((target, values) -> {
+ if (expandingFromBubble != null) {
+ // Follow the bubble as it translates!
+ mExpandedViewContainerMatrix.postTranslate(
+ expandingFromBubble.getTranslationX()
+ - expandingFromBubbleAtX, 0f);
+ }
+
+ mExpandedViewContainer.setAnimationMatrix(mExpandedViewContainerMatrix);
+
+ // Hide early so we don't have a tiny little expanded view still visible at the
+ // end of the scale animation.
+ if (mExpandedViewContainerMatrix.getScaleX() < 0.05f) {
+ mExpandedViewContainer.setVisibility(View.INVISIBLE);
+ }
+ })
+ .withEndActions(() -> {
+ final BubbleViewProvider previouslySelected = mExpandedBubble;
+ beforeExpandedViewAnimation();
+ maybeShowManageEducation(false);
+
+ if (DEBUG_BUBBLE_STACK_VIEW) {
+ Log.d(TAG, "animateCollapse");
+ Log.d(TAG, BubbleDebugConfig.formatBubblesString(getBubblesOnScreen(),
+ mExpandedBubble));
+ }
+ updateOverflowVisibility();
+
afterExpandedViewAnimation();
previouslySelected.setContentVisibility(false);
- });
-
- mExpandedViewXAnim.animateToFinalPosition(getCollapsedX());
- mExpandedViewYAnim.animateToFinalPosition(getCollapsedY());
- mExpandedViewContainer.animate()
- .setDuration(100)
- .alpha(0f);
+ })
+ .start();
}
- private void animateExpansion() {
- mIsExpanded = true;
- hideStackUserEducation(true /* fromExpansion */);
- beforeExpandedViewAnimation();
+ private void animateSwitchBubbles() {
+ // The surface contains a screenshot of the animating out bubble, so we just need to animate
+ // it out (and then release the GraphicBuffer).
+ PhysicsAnimator.getInstance(mAnimatingOutSurfaceContainer).cancel();
+ PhysicsAnimator.getInstance(mAnimatingOutSurfaceContainer)
+ .spring(DynamicAnimation.SCALE_X, 0f, mScaleOutSpringConfig)
+ .spring(DynamicAnimation.SCALE_Y, 0f, mScaleOutSpringConfig)
+ .spring(DynamicAnimation.TRANSLATION_Y,
+ mAnimatingOutSurfaceContainer.getTranslationY() - mBubbleSize * 2,
+ mTranslateSpringConfig)
+ .withEndActions(this::releaseAnimatingOutBubbleBuffer)
+ .start();
- mBubbleContainer.setActiveController(mExpandedAnimationController);
- updateOverflowVisibility();
- mExpandedAnimationController.expandFromStack(() -> {
- updatePointerPosition();
- afterExpandedViewAnimation();
- maybeShowManageEducation(true);
- } /* after */);
+ float expandingFromBubbleDestinationX =
+ mExpandedAnimationController.getBubbleLeft(
+ mBubbleData.getBubbles().indexOf(mExpandedBubble));
- mExpandedViewContainer.setTranslationX(getCollapsedX());
- mExpandedViewContainer.setTranslationY(getCollapsedY());
- mExpandedViewContainer.setAlpha(0f);
+ mExpandedViewContainer.setAlpha(1f);
+ mExpandedViewContainer.setVisibility(View.VISIBLE);
- mExpandedViewXAnim.animateToFinalPosition(0f);
- mExpandedViewYAnim.animateToFinalPosition(getExpandedViewY());
- mExpandedViewContainer.animate()
- .setDuration(100)
- .alpha(1f);
- }
+ mExpandedViewContainerMatrix.setScale(
+ 0f, 0f, expandingFromBubbleDestinationX + mBubbleSize / 2f, getExpandedViewY());
+ mExpandedViewContainer.setAnimationMatrix(mExpandedViewContainerMatrix);
- private float getCollapsedX() {
- return mStackAnimationController.getStackPosition().x < getWidth() / 2
- ? -mExpandedAnimateXDistance
- : mExpandedAnimateXDistance;
- }
+ mExpandedViewContainer.postDelayed(() -> {
+ if (!mIsExpanded) {
+ return;
+ }
- private float getCollapsedY() {
- return Math.min(mStackAnimationController.getStackPosition().y,
- mExpandedAnimateYDistance);
+ PhysicsAnimator.getInstance(mExpandedViewContainerMatrix)
+ .spring(AnimatableScaleMatrix.SCALE_X,
+ AnimatableScaleMatrix.getAnimatableValueForScaleFactor(1f),
+ mScaleInSpringConfig)
+ .spring(AnimatableScaleMatrix.SCALE_Y,
+ AnimatableScaleMatrix.getAnimatableValueForScaleFactor(1f),
+ mScaleInSpringConfig)
+ .addUpdateListener((target, values) -> {
+ mExpandedViewContainer.setAnimationMatrix(mExpandedViewContainerMatrix);
+ })
+ .withEndActions(() -> {
+ if (mExpandedBubble != null && mExpandedBubble.getExpandedView() != null) {
+ mExpandedBubble.getExpandedView().setSurfaceZOrderedOnTop(false);
+ }
+ })
+ .start();
+ }, 25);
}
private void notifyExpansionChanged(BubbleViewProvider bubble, boolean expanded) {
@@ -1713,9 +1985,13 @@ public class BubbleStackView extends FrameLayout
*/
@Override
public void subtractObscuredTouchableRegion(Region touchableRegion, View view) {
- // If the notification shade is expanded, or the manage menu is open, we shouldn't let the
- // ActivityView steal any touch events from any location.
- if (mNotificationShadeWindowController.getPanelExpanded() || mShowingManage) {
+ // If the notification shade is expanded, or the manage menu is open, or we are showing
+ // manage bubbles user education, we shouldn't let the ActivityView steal any touch events
+ // from any location.
+ if (!mIsExpanded
+ || mShowingManage
+ || (mManageEducationView != null
+ && mManageEducationView.getVisibility() == VISIBLE)) {
touchableRegion.setEmpty();
}
}
@@ -1818,6 +2094,10 @@ public class BubbleStackView extends FrameLayout
private void animateDesaturateAndDarken(View targetView, boolean desaturateAndDarken) {
mDesaturateAndDarkenTargetView = targetView;
+ if (mDesaturateAndDarkenTargetView == null) {
+ return;
+ }
+
if (desaturateAndDarken) {
// Use the animated paint for the bubbles.
mDesaturateAndDarkenTargetView.setLayerType(
@@ -1839,9 +2119,14 @@ public class BubbleStackView extends FrameLayout
}
private void resetDesaturationAndDarken() {
+
mDesaturateAndDarkenAnimator.removeAllListeners();
mDesaturateAndDarkenAnimator.cancel();
- mDesaturateAndDarkenTargetView.setLayerType(View.LAYER_TYPE_NONE, null);
+
+ if (mDesaturateAndDarkenTargetView != null) {
+ mDesaturateAndDarkenTargetView.setLayerType(View.LAYER_TYPE_NONE, null);
+ mDesaturateAndDarkenTargetView = null;
+ }
}
/** Animates in the dismiss target. */
@@ -1856,6 +2141,9 @@ public class BubbleStackView extends FrameLayout
mDismissTargetContainer.setZ(Short.MAX_VALUE - 1);
mDismissTargetContainer.setVisibility(VISIBLE);
+ ((TransitionDrawable) mDismissTargetContainer.getBackground()).startTransition(
+ DISMISS_TRANSITION_DURATION_MS);
+
mDismissTargetAnimator.cancel();
mDismissTargetAnimator
.spring(DynamicAnimation.TRANSLATION_Y, 0f, mDismissTargetSpring)
@@ -1873,6 +2161,9 @@ public class BubbleStackView extends FrameLayout
mShowingDismiss = false;
+ ((TransitionDrawable) mDismissTargetContainer.getBackground()).reverseTransition(
+ DISMISS_TRANSITION_DURATION_MS);
+
mDismissTargetAnimator
.spring(DynamicAnimation.TRANSLATION_Y, mDismissTargetContainer.getHeight(),
mDismissTargetSpring)
@@ -1944,6 +2235,9 @@ public class BubbleStackView extends FrameLayout
// Stop suppressing the dot now that the flyout has morphed into the dot.
bubbleView.removeDotSuppressionFlag(
BadgedImageView.SuppressionFlag.FLYOUT_VISIBLE);
+
+ mFlyout.setVisibility(INVISIBLE);
+ animateTemporarilyInvisible();
};
mFlyout.setVisibility(INVISIBLE);
@@ -1961,6 +2255,7 @@ public class BubbleStackView extends FrameLayout
final Runnable expandFlyoutAfterDelay = () -> {
mAnimateInFlyout = () -> {
mFlyout.setVisibility(VISIBLE);
+ animateTemporarilyInvisible();
mFlyoutDragDeltaX =
mStackAnimationController.isStackOnLeftSide()
? -mFlyout.getWidth()
@@ -2086,16 +2381,21 @@ public class BubbleStackView extends FrameLayout
mExpandedBubble.getExpandedView().getManageButtonBoundsOnScreen(mTempRect);
- // When the menu is open, it should be at these coordinates. This will make the menu's
- // bottom left corner match up with the button's bottom left corner.
- final float targetX = mTempRect.left;
+ final boolean isLtr =
+ getResources().getConfiguration().getLayoutDirection() == LAYOUT_DIRECTION_LTR;
+
+ // When the menu is open, it should be at these coordinates. The menu pops out to the right
+ // in LTR and to the left in RTL.
+ final float targetX = isLtr ? mTempRect.left : mTempRect.right - mManageMenu.getWidth();
final float targetY = mTempRect.bottom - mManageMenu.getHeight();
+ final float xOffsetForAnimation = (isLtr ? 1 : -1) * mManageMenu.getWidth() / 4f;
+
if (show) {
mManageMenu.setScaleX(0.5f);
mManageMenu.setScaleY(0.5f);
- mManageMenu.setTranslationX(targetX - mManageMenu.getWidth() / 4);
- mManageMenu.setTranslationY(targetY + mManageMenu.getHeight() / 4);
+ mManageMenu.setTranslationX(targetX - xOffsetForAnimation);
+ mManageMenu.setTranslationY(targetY + mManageMenu.getHeight() / 4f);
mManageMenu.setAlpha(0f);
PhysicsAnimator.getInstance(mManageMenu)
@@ -2112,8 +2412,8 @@ public class BubbleStackView extends FrameLayout
.spring(DynamicAnimation.ALPHA, 0f)
.spring(DynamicAnimation.SCALE_X, 0.5f)
.spring(DynamicAnimation.SCALE_Y, 0.5f)
- .spring(DynamicAnimation.TRANSLATION_X, targetX - mManageMenu.getWidth() / 4)
- .spring(DynamicAnimation.TRANSLATION_Y, targetY + mManageMenu.getHeight() / 4)
+ .spring(DynamicAnimation.TRANSLATION_X, targetX - xOffsetForAnimation)
+ .spring(DynamicAnimation.TRANSLATION_Y, targetY + mManageMenu.getHeight() / 4f)
.withEndActions(() -> mManageMenu.setVisibility(View.INVISIBLE))
.start();
}
@@ -2126,15 +2426,121 @@ public class BubbleStackView extends FrameLayout
if (DEBUG_BUBBLE_STACK_VIEW) {
Log.d(TAG, "updateExpandedBubble()");
}
+
+ hideImeFromExpandedBubble();
+
mExpandedViewContainer.removeAllViews();
if (mIsExpanded && mExpandedBubble != null
&& mExpandedBubble.getExpandedView() != null) {
BubbleExpandedView bev = mExpandedBubble.getExpandedView();
+ bev.setContentVisibility(false);
+ mExpandedViewContainerMatrix.setScaleX(0f);
+ mExpandedViewContainerMatrix.setScaleY(0f);
+ mExpandedViewContainer.setVisibility(View.INVISIBLE);
+ mExpandedViewContainer.setAlpha(0f);
mExpandedViewContainer.addView(bev);
bev.setManageClickListener((view) -> showManageMenu(!mShowingManage));
bev.populateExpandedView();
- mExpandedViewContainer.setVisibility(VISIBLE);
- mExpandedViewContainer.setAlpha(1.0f);
+
+ if (!mIsExpansionAnimating) {
+ mSurfaceSynchronizer.syncSurfaceAndRun(() -> {
+ post(this::animateSwitchBubbles);
+ });
+ }
+ }
+ }
+
+ /**
+ * Requests a snapshot from the currently expanded bubble's ActivityView and displays it in a
+ * SurfaceView. This allows us to load a newly expanded bubble's Activity into the ActivityView,
+ * while animating the (screenshot of the) previously selected bubble's content away.
+ *
+ * @param onComplete Callback to run once we're done here - called with 'false' if something
+ * went wrong, or 'true' if the SurfaceView is now showing a screenshot of the
+ * expanded bubble.
+ */
+ private void screenshotAnimatingOutBubbleIntoSurface(Consumer<Boolean> onComplete) {
+ if (mExpandedBubble == null || mExpandedBubble.getExpandedView() == null) {
+ // You can't animate null.
+ onComplete.accept(false);
+ return;
+ }
+
+ final BubbleExpandedView animatingOutExpandedView = mExpandedBubble.getExpandedView();
+
+ // Release the previous screenshot if it hasn't been released already.
+ if (mAnimatingOutBubbleBuffer != null) {
+ releaseAnimatingOutBubbleBuffer();
+ }
+
+ try {
+ mAnimatingOutBubbleBuffer = animatingOutExpandedView.snapshotActivitySurface();
+ } catch (Exception e) {
+ // If we fail for any reason, print the stack trace and then notify the callback of our
+ // failure. This is not expected to occur, but it's not worth crashing over.
+ Log.wtf(TAG, e);
+ onComplete.accept(false);
+ }
+
+ if (mAnimatingOutBubbleBuffer == null
+ || mAnimatingOutBubbleBuffer.getGraphicBuffer() == null) {
+ // While no exception was thrown, we were unable to get a snapshot.
+ onComplete.accept(false);
+ return;
+ }
+
+ // Make sure the surface container's properties have been reset.
+ PhysicsAnimator.getInstance(mAnimatingOutSurfaceContainer).cancel();
+ mAnimatingOutSurfaceContainer.setScaleX(1f);
+ mAnimatingOutSurfaceContainer.setScaleY(1f);
+ mAnimatingOutSurfaceContainer.setTranslationX(0);
+ mAnimatingOutSurfaceContainer.setTranslationY(0);
+
+ final int[] activityViewLocation =
+ mExpandedBubble.getExpandedView().getActivityViewLocationOnScreen();
+ final int[] surfaceViewLocation = mAnimatingOutSurfaceView.getLocationOnScreen();
+
+ // Translate the surface to overlap the real ActivityView.
+ mAnimatingOutSurfaceContainer.setTranslationY(
+ activityViewLocation[1] - surfaceViewLocation[1]);
+
+ // Set the width/height of the SurfaceView to match the snapshot.
+ mAnimatingOutSurfaceView.getLayoutParams().width =
+ mAnimatingOutBubbleBuffer.getGraphicBuffer().getWidth();
+ mAnimatingOutSurfaceView.getLayoutParams().height =
+ mAnimatingOutBubbleBuffer.getGraphicBuffer().getHeight();
+ mAnimatingOutSurfaceView.requestLayout();
+
+ // Post to wait for layout.
+ post(() -> {
+ // The buffer might have been destroyed if the user is mashing on bubbles, that's okay.
+ if (mAnimatingOutBubbleBuffer.getGraphicBuffer().isDestroyed()) {
+ onComplete.accept(false);
+ return;
+ }
+
+ if (!mIsExpanded) {
+ onComplete.accept(false);
+ return;
+ }
+
+ // Attach the buffer! We're now displaying the snapshot.
+ mAnimatingOutSurfaceView.getHolder().getSurface().attachAndQueueBufferWithColorSpace(
+ mAnimatingOutBubbleBuffer.getGraphicBuffer(),
+ mAnimatingOutBubbleBuffer.getColorSpace());
+
+ mSurfaceSynchronizer.syncSurfaceAndRun(() -> post(() -> onComplete.accept(true)));
+ });
+ }
+
+ /**
+ * Releases the buffer containing the screenshot of the animating-out bubble, if it exists and
+ * isn't yet destroyed.
+ */
+ private void releaseAnimatingOutBubbleBuffer() {
+ if (mAnimatingOutBubbleBuffer != null
+ && !mAnimatingOutBubbleBuffer.getGraphicBuffer().isDestroyed()) {
+ mAnimatingOutBubbleBuffer.getGraphicBuffer().destroy();
}
}
@@ -2144,19 +2550,10 @@ public class BubbleStackView extends FrameLayout
}
mExpandedViewContainer.setVisibility(mIsExpanded ? VISIBLE : GONE);
- if (mIsExpanded) {
- final float y = getExpandedViewY();
- if (!mExpandedViewYAnim.isRunning()) {
- // We're not animating so set the value
- mExpandedViewContainer.setTranslationY(y);
- if (mExpandedBubble != null && mExpandedBubble.getExpandedView() != null) {
- mExpandedBubble.getExpandedView().updateView();
- }
- } else {
- // We are animating so update the value; there is an end listener on the animator
- // that will ensure expandedeView.updateView gets called.
- mExpandedViewYAnim.animateToFinalPosition(y);
- }
+ if (mExpandedBubble != null && mExpandedBubble.getExpandedView() != null) {
+ mExpandedViewContainer.setTranslationY(getExpandedViewY());
+ mExpandedBubble.getExpandedView().updateView(
+ mExpandedViewContainer.getLocationOnScreen());
}
mStackOnLeftOrWillBe = mStackAnimationController.isStackOnLeftSide();
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/animation/AnimatableScaleMatrix.java b/packages/SystemUI/src/com/android/systemui/bubbles/animation/AnimatableScaleMatrix.java
new file mode 100644
index 000000000000..ae7833634794
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/animation/AnimatableScaleMatrix.java
@@ -0,0 +1,137 @@
+/*
+ * 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.bubbles.animation;
+
+import android.graphics.Matrix;
+
+import androidx.dynamicanimation.animation.DynamicAnimation;
+import androidx.dynamicanimation.animation.FloatPropertyCompat;
+
+/**
+ * Matrix whose scale properties can be animated using physics animations, via the {@link #SCALE_X}
+ * and {@link #SCALE_Y} FloatProperties.
+ *
+ * This is useful when you need to perform a scale animation with a pivot point, since pivot points
+ * are not supported by standard View scale operations but are supported by matrices.
+ *
+ * NOTE: DynamicAnimation assumes that all custom properties are denominated in pixels, and thus
+ * considers 1 to be the smallest user-visible change for custom properties. This means that if you
+ * animate {@link #SCALE_X} and {@link #SCALE_Y} to 3f, for example, the animation would have only
+ * three frames.
+ *
+ * To work around this, whenever animating to a desired scale value, animate to the value returned
+ * by {@link #getAnimatableValueForScaleFactor} instead. The SCALE_X and SCALE_Y properties will
+ * convert that (larger) value into the appropriate scale factor when scaling the matrix.
+ */
+public class AnimatableScaleMatrix extends Matrix {
+
+ /**
+ * The X value of the scale.
+ *
+ * NOTE: This must be set or animated to the value returned by
+ * {@link #getAnimatableValueForScaleFactor}, not the desired scale factor itself.
+ */
+ public static final FloatPropertyCompat<AnimatableScaleMatrix> SCALE_X =
+ new FloatPropertyCompat<AnimatableScaleMatrix>("matrixScaleX") {
+ @Override
+ public float getValue(AnimatableScaleMatrix object) {
+ return getAnimatableValueForScaleFactor(object.mScaleX);
+ }
+
+ @Override
+ public void setValue(AnimatableScaleMatrix object, float value) {
+ object.setScaleX(value * DynamicAnimation.MIN_VISIBLE_CHANGE_SCALE);
+ }
+ };
+
+ /**
+ * The Y value of the scale.
+ *
+ * NOTE: This must be set or animated to the value returned by
+ * {@link #getAnimatableValueForScaleFactor}, not the desired scale factor itself.
+ */
+ public static final FloatPropertyCompat<AnimatableScaleMatrix> SCALE_Y =
+ new FloatPropertyCompat<AnimatableScaleMatrix>("matrixScaleY") {
+ @Override
+ public float getValue(AnimatableScaleMatrix object) {
+ return getAnimatableValueForScaleFactor(object.mScaleY);
+ }
+
+ @Override
+ public void setValue(AnimatableScaleMatrix object, float value) {
+ object.setScaleY(value * DynamicAnimation.MIN_VISIBLE_CHANGE_SCALE);
+ }
+ };
+
+ private float mScaleX = 1f;
+ private float mScaleY = 1f;
+
+ private float mPivotX = 0f;
+ private float mPivotY = 0f;
+
+ /**
+ * Return the value to animate SCALE_X or SCALE_Y to in order to achieve the desired scale
+ * factor.
+ */
+ public static float getAnimatableValueForScaleFactor(float scale) {
+ return scale * (1f / DynamicAnimation.MIN_VISIBLE_CHANGE_SCALE);
+ }
+
+ @Override
+ public void setScale(float sx, float sy, float px, float py) {
+ mScaleX = sx;
+ mScaleY = sy;
+ mPivotX = px;
+ mPivotY = py;
+ super.setScale(mScaleX, mScaleY, mPivotX, mPivotY);
+ }
+
+ public void setScaleX(float scaleX) {
+ mScaleX = scaleX;
+ super.setScale(mScaleX, mScaleY, mPivotX, mPivotY);
+ }
+
+ public void setScaleY(float scaleY) {
+ mScaleY = scaleY;
+ super.setScale(mScaleX, mScaleY, mPivotX, mPivotY);
+ }
+
+ public void setPivotX(float pivotX) {
+ mPivotX = pivotX;
+ super.setScale(mScaleX, mScaleY, mPivotX, mPivotY);
+ }
+
+ public void setPivotY(float pivotY) {
+ mPivotY = pivotY;
+ super.setScale(mScaleX, mScaleY, mPivotX, mPivotY);
+ }
+
+ public float getScaleX() {
+ return mScaleX;
+ }
+
+ public float getScaleY() {
+ return mScaleY;
+ }
+
+ public float getPivotX() {
+ return mPivotX;
+ }
+
+ public float getPivotY() {
+ return mPivotY;
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/animation/ExpandedAnimationController.java b/packages/SystemUI/src/com/android/systemui/bubbles/animation/ExpandedAnimationController.java
index 76ff1afef3f7..86fe10dddc2c 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/animation/ExpandedAnimationController.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/animation/ExpandedAnimationController.java
@@ -56,7 +56,7 @@ public class ExpandedAnimationController
private static final int ANIMATE_TRANSLATION_FACTOR = 4;
/** Duration of the expand/collapse target path animation. */
- private static final int EXPAND_COLLAPSE_TARGET_ANIM_DURATION = 175;
+ public static final int EXPAND_COLLAPSE_TARGET_ANIM_DURATION = 175;
/** Stiffness for the expand/collapse path-following animation. */
private static final int EXPAND_COLLAPSE_ANIM_STIFFNESS = 1000;
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/animation/StackAnimationController.java b/packages/SystemUI/src/com/android/systemui/bubbles/animation/StackAnimationController.java
index fd1f879e7f4b..3ef20444cb52 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/animation/StackAnimationController.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/animation/StackAnimationController.java
@@ -1034,13 +1034,13 @@ public class StackAnimationController extends
mMagnetizedStack.getFlingToTargetMinVelocity() /* default */);
final float maxVelocity = Settings.Secure.getFloat(contentResolver,
"bubble_dismiss_stick_max_velocity",
- mMagnetizedStack.getStickToTargetMaxVelocity() /* default */);
+ mMagnetizedStack.getStickToTargetMaxXVelocity() /* default */);
final float targetWidth = Settings.Secure.getFloat(contentResolver,
"bubble_dismiss_target_width_percent",
mMagnetizedStack.getFlingToTargetWidthPercent() /* default */);
mMagnetizedStack.setFlingToTargetMinVelocity(minVelocity);
- mMagnetizedStack.setStickToTargetMaxVelocity(maxVelocity);
+ mMagnetizedStack.setStickToTargetMaxXVelocity(maxVelocity);
mMagnetizedStack.setFlingToTargetWidthPercent(targetWidth);
return mMagnetizedStack;
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/dagger/BubbleModule.java b/packages/SystemUI/src/com/android/systemui/bubbles/dagger/BubbleModule.java
index d1d07f6ba4ce..097932e5f447 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/dagger/BubbleModule.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/dagger/BubbleModule.java
@@ -20,6 +20,7 @@ import android.app.INotificationManager;
import android.content.Context;
import android.view.WindowManager;
+import com.android.internal.statusbar.IStatusBarService;
import com.android.systemui.bubbles.BubbleController;
import com.android.systemui.bubbles.BubbleData;
import com.android.systemui.bubbles.BubbleDataRepository;
@@ -70,6 +71,7 @@ public interface BubbleModule {
BubbleDataRepository bubbleDataRepository,
SysUiState sysUiState,
INotificationManager notifManager,
+ IStatusBarService statusBarService,
WindowManager windowManager) {
return new BubbleController(
context,
@@ -91,6 +93,7 @@ public interface BubbleModule {
bubbleDataRepository,
sysUiState,
notifManager,
+ statusBarService,
windowManager);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/storage/BubbleEntity.kt b/packages/SystemUI/src/com/android/systemui/bubbles/storage/BubbleEntity.kt
index 43482616da2c..355c4b115c8d 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/storage/BubbleEntity.kt
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/storage/BubbleEntity.kt
@@ -15,11 +15,14 @@
*/
package com.android.systemui.bubbles.storage
+import android.annotation.DimenRes
import android.annotation.UserIdInt
data class BubbleEntity(
@UserIdInt val userId: Int,
val packageName: String,
val shortcutId: String,
- val key: String
+ val key: String,
+ val desiredHeight: Int,
+ @DimenRes val desiredHeightResId: Int
)
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/storage/BubblePersistentRepository.kt b/packages/SystemUI/src/com/android/systemui/bubbles/storage/BubblePersistentRepository.kt
index 7c3271e4b76c..5b4d8c71e5c0 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/storage/BubblePersistentRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/storage/BubblePersistentRepository.kt
@@ -54,6 +54,7 @@ class BubblePersistentRepository @Inject constructor(
fun readFromDisk(): List<BubbleEntity> {
synchronized(bubbleFile) {
+ if (!bubbleFile.exists()) return emptyList()
try { return bubbleFile.openRead().use(::readXml) } catch (e: Throwable) {
Log.e(TAG, "Failed to open bubble file", e)
}
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/storage/BubbleXmlHelper.kt b/packages/SystemUI/src/com/android/systemui/bubbles/storage/BubbleXmlHelper.kt
index 1df9f72022f0..a8faf258da07 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/storage/BubbleXmlHelper.kt
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/storage/BubbleXmlHelper.kt
@@ -31,6 +31,8 @@ private const val ATTR_USER_ID = "uid"
private const val ATTR_PACKAGE = "pkg"
private const val ATTR_SHORTCUT_ID = "sid"
private const val ATTR_KEY = "key"
+private const val ATTR_DESIRED_HEIGHT = "h"
+private const val ATTR_DESIRED_HEIGHT_RES_ID = "hid"
/**
* Writes the bubbles in xml format into given output stream.
@@ -59,6 +61,8 @@ private fun writeXmlEntry(serializer: XmlSerializer, bubble: BubbleEntity) {
serializer.attribute(null, ATTR_PACKAGE, bubble.packageName)
serializer.attribute(null, ATTR_SHORTCUT_ID, bubble.shortcutId)
serializer.attribute(null, ATTR_KEY, bubble.key)
+ serializer.attribute(null, ATTR_DESIRED_HEIGHT, bubble.desiredHeight.toString())
+ serializer.attribute(null, ATTR_DESIRED_HEIGHT_RES_ID, bubble.desiredHeightResId.toString())
serializer.endTag(null, TAG_BUBBLE)
} catch (e: IOException) {
throw RuntimeException(e)
@@ -86,7 +90,9 @@ private fun readXmlEntry(parser: XmlPullParser): BubbleEntity? {
parser.getAttributeWithName(ATTR_USER_ID)?.toInt() ?: return null,
parser.getAttributeWithName(ATTR_PACKAGE) ?: return null,
parser.getAttributeWithName(ATTR_SHORTCUT_ID) ?: return null,
- parser.getAttributeWithName(ATTR_KEY) ?: return null
+ parser.getAttributeWithName(ATTR_KEY) ?: return null,
+ parser.getAttributeWithName(ATTR_DESIRED_HEIGHT)?.toInt() ?: return null,
+ parser.getAttributeWithName(ATTR_DESIRED_HEIGHT_RES_ID)?.toInt() ?: return null
)
}
diff --git a/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsController.kt b/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsController.kt
index 07319207d9ab..45ba1e6012fe 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsController.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsController.kt
@@ -190,11 +190,6 @@ interface ControlsController : UserAwareController {
fun countFavoritesForComponent(componentName: ComponentName): Int
/**
- * TEMPORARY for testing
- */
- fun resetFavorites()
-
- /**
* Interface for structure to pass data to [ControlsFavoritingActivity].
*/
interface LoadData {
diff --git a/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsControllerImpl.kt b/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsControllerImpl.kt
index fd9fda3662a3..ebdcdccead90 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsControllerImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsControllerImpl.kt
@@ -44,6 +44,7 @@ import com.android.systemui.controls.management.ControlsListingController
import com.android.systemui.controls.ui.ControlsUiController
import com.android.systemui.dagger.qualifiers.Background
import com.android.systemui.dump.DumpManager
+import com.android.systemui.globalactions.GlobalActionsDialog
import com.android.systemui.util.concurrency.DelayableExecutor
import java.io.FileDescriptor
import java.io.PrintWriter
@@ -79,6 +80,7 @@ class ControlsControllerImpl @Inject constructor (
}
private var userChanging: Boolean = true
+ private var userStructure: UserStructure
private var seedingInProgress = false
private val seedingCallbacks = mutableListOf<Consumer<Boolean>>()
@@ -97,7 +99,7 @@ class ControlsControllerImpl @Inject constructor (
internal var auxiliaryPersistenceWrapper: AuxiliaryPersistenceWrapper
init {
- val userStructure = UserStructure(context, currentUser)
+ userStructure = UserStructure(context, currentUser)
persistenceWrapper = optionalWrapper.orElseGet {
ControlsFavoritePersistenceWrapper(
@@ -116,7 +118,7 @@ class ControlsControllerImpl @Inject constructor (
private fun setValuesForUser(newUser: UserHandle) {
Log.d(TAG, "Changing to user: $newUser")
currentUser = newUser
- val userStructure = UserStructure(context, currentUser)
+ userStructure = UserStructure(context, currentUser)
persistenceWrapper.changeFileAndBackupManager(
userStructure.file,
BackupManager(userStructure.userContext)
@@ -192,6 +194,16 @@ class ControlsControllerImpl @Inject constructor (
it.componentName
}.toSet()
+ // When a component is uninstalled, allow seeding to happen again if the user
+ // reinstalls the app
+ val prefs = userStructure.userContext.getSharedPreferences(
+ GlobalActionsDialog.PREFS_CONTROLS_FILE, Context.MODE_PRIVATE)
+ val completedSeedingPackageSet = prefs.getStringSet(
+ GlobalActionsDialog.PREFS_CONTROLS_SEEDING_COMPLETED, mutableSetOf<String>())
+ val favoritePackageSet = favoriteComponentSet.map { it.packageName }
+ prefs.edit().putStringSet(GlobalActionsDialog.PREFS_CONTROLS_SEEDING_COMPLETED,
+ completedSeedingPackageSet.intersect(favoritePackageSet)).apply()
+
var changed = false
favoriteComponentSet.subtract(serviceInfoSet).forEach {
changed = true
@@ -512,13 +524,6 @@ class ControlsControllerImpl @Inject constructor (
}
}
- override fun resetFavorites() {
- executor.execute {
- Favorites.clear()
- persistenceWrapper.storeFavorites(Favorites.getAllStructures())
- }
- }
-
override fun refreshStatus(componentName: ComponentName, control: Control) {
if (!confirmAvailability()) {
Log.d(TAG, "Controls not available")
diff --git a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlActionCoordinator.kt b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlActionCoordinator.kt
index 3fab4c868314..429f67fdc706 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlActionCoordinator.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlActionCoordinator.kt
@@ -55,6 +55,28 @@ interface ControlActionCoordinator {
fun drag(isEdge: Boolean)
/**
+ * Send a request to update the value of a device using the [FloatAction].
+ *
+ * @param cvh [ControlViewHolder] for the control
+ * @param templateId id of the control's template, as given by the service
+ * @param newValue value to set for the device
+ */
+ fun setValue(cvh: ControlViewHolder, templateId: String, newValue: Float)
+
+ /**
+ * Actions may have been put on hold while the device is unlocked. Invoke this action if
+ * present.
+ */
+ fun runPendingAction(controlId: String)
+
+ /**
+ * User interaction with a control may be blocked for a period of time while actions are being
+ * executed by the application. When the response returns, run this method to enable further
+ * user interaction.
+ */
+ fun enableActionOnTouch(controlId: String)
+
+ /**
* All long presses will be shown in a 3/4 height bottomsheet panel, in order for the user to
* retain context with their favorited controls in the power menu.
*/
diff --git a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlActionCoordinatorImpl.kt b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlActionCoordinatorImpl.kt
index 10e913743224..d2501fa8a66b 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlActionCoordinatorImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlActionCoordinatorImpl.kt
@@ -21,11 +21,13 @@ import android.content.Context
import android.content.Intent
import android.content.pm.PackageManager
import android.content.pm.ResolveInfo
+import android.annotation.MainThread
import android.os.Vibrator
import android.os.VibrationEffect
import android.service.controls.Control
import android.service.controls.actions.BooleanAction
import android.service.controls.actions.CommandAction
+import android.service.controls.actions.FloatAction
import android.util.Log
import android.view.HapticFeedbackConstants
import com.android.systemui.dagger.qualifiers.Main
@@ -49,7 +51,12 @@ class ControlActionCoordinatorImpl @Inject constructor(
) : ControlActionCoordinator {
private var dialog: Dialog? = null
private val vibrator = context.getSystemService(Context.VIBRATOR_SERVICE) as Vibrator
- private var lastAction: (() -> Unit)? = null
+ private var pendingAction: Action? = null
+ private var actionsInProgress = mutableSetOf<String>()
+
+ companion object {
+ private const val RESPONSE_TIMEOUT_IN_MILLIS = 3000L
+ }
override fun closeDialogs() {
dialog?.dismiss()
@@ -57,56 +64,84 @@ class ControlActionCoordinatorImpl @Inject constructor(
}
override fun toggle(cvh: ControlViewHolder, templateId: String, isChecked: Boolean) {
- bouncerOrRun {
- val effect = if (!isChecked) Vibrations.toggleOnEffect else Vibrations.toggleOffEffect
- vibrate(effect)
+ bouncerOrRun(Action(cvh.cws.ci.controlId, {
+ cvh.layout.performHapticFeedback(HapticFeedbackConstants.CONTEXT_CLICK)
cvh.action(BooleanAction(templateId, !isChecked))
- }
+ }, true /* blockable */))
}
override fun touch(cvh: ControlViewHolder, templateId: String, control: Control) {
- vibrate(Vibrations.toggleOnEffect)
-
- bouncerOrRun {
+ val blockable = cvh.usePanel()
+ bouncerOrRun(Action(cvh.cws.ci.controlId, {
+ cvh.layout.performHapticFeedback(HapticFeedbackConstants.CONTEXT_CLICK)
if (cvh.usePanel()) {
showDialog(cvh, control.getAppIntent().getIntent())
} else {
cvh.action(CommandAction(templateId))
}
- }
+ }, blockable))
}
override fun drag(isEdge: Boolean) {
- bouncerOrRun {
- if (isEdge) {
- vibrate(Vibrations.rangeEdgeEffect)
- } else {
- vibrate(Vibrations.rangeMiddleEffect)
- }
+ if (isEdge) {
+ vibrate(Vibrations.rangeEdgeEffect)
+ } else {
+ vibrate(Vibrations.rangeMiddleEffect)
}
}
+ override fun setValue(cvh: ControlViewHolder, templateId: String, newValue: Float) {
+ bouncerOrRun(Action(cvh.cws.ci.controlId, {
+ cvh.action(FloatAction(templateId, newValue))
+ }, true /* blockable */))
+ }
+
override fun longPress(cvh: ControlViewHolder) {
- bouncerOrRun {
+ bouncerOrRun(Action(cvh.cws.ci.controlId, {
// Long press snould only be called when there is valid control state, otherwise ignore
cvh.cws.control?.let {
cvh.layout.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS)
showDialog(cvh, it.getAppIntent().getIntent())
}
+ }, false /* blockable */))
+ }
+
+ override fun runPendingAction(controlId: String) {
+ if (pendingAction?.controlId == controlId) {
+ pendingAction?.invoke()
+ pendingAction = null
}
}
- private fun bouncerOrRun(f: () -> Unit) {
+ @MainThread
+ override fun enableActionOnTouch(controlId: String) {
+ actionsInProgress.remove(controlId)
+ }
+
+ private fun shouldRunAction(controlId: String) =
+ if (actionsInProgress.add(controlId)) {
+ uiExecutor.executeDelayed({
+ actionsInProgress.remove(controlId)
+ }, RESPONSE_TIMEOUT_IN_MILLIS)
+ true
+ } else {
+ false
+ }
+
+ private fun bouncerOrRun(action: Action) {
if (!keyguardStateController.isUnlocked()) {
context.sendBroadcast(Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS))
+
+ // pending actions will only run after the control state has been refreshed
+ pendingAction = action
+
activityStarter.dismissKeyguardThenExecute({
Log.d(ControlsUiController.TAG, "Device unlocked, invoking controls action")
globalActionsComponent.handleShowGlobalActionsMenu()
- f()
true
- }, null, true)
+ }, { pendingAction = null }, true /* afterKeyguardGone */)
} else {
- f()
+ action.invoke()
}
}
@@ -135,4 +170,12 @@ class ControlActionCoordinatorImpl @Inject constructor(
}
}
}
+
+ inner class Action(val controlId: String, val f: () -> Unit, val blockable: Boolean) {
+ fun invoke() {
+ if (!blockable || shouldRunAction(controlId)) {
+ f.invoke()
+ }
+ }
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlViewHolder.kt b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlViewHolder.kt
index f07f3168d246..353367ead7e6 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlViewHolder.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlViewHolder.kt
@@ -87,9 +87,7 @@ class ControlViewHolder(
deviceType: Int
): KClass<out Behavior> {
return when {
- status == Control.STATUS_UNKNOWN -> StatusBehavior::class
- status == Control.STATUS_ERROR -> StatusBehavior::class
- status == Control.STATUS_NOT_FOUND -> StatusBehavior::class
+ status != Control.STATUS_OK -> StatusBehavior::class
deviceType == DeviceTypes.TYPE_CAMERA -> TouchBehavior::class
template is ToggleTemplate -> ToggleBehavior::class
template is StatelessTemplate -> TouchBehavior::class
@@ -118,11 +116,16 @@ class ControlViewHolder(
var behavior: Behavior? = null
var lastAction: ControlAction? = null
var isLoading = false
+ var visibleDialog: Dialog? = null
private var lastChallengeDialog: Dialog? = null
private val onDialogCancel: () -> Unit = { lastChallengeDialog = null }
val deviceType: Int
- get() = cws.control?.let { it.getDeviceType() } ?: cws.ci.deviceType
+ get() = cws.control?.let { it.deviceType } ?: cws.ci.deviceType
+ val controlStatus: Int
+ get() = cws.control?.let { it.status } ?: Control.STATUS_UNKNOWN
+ val controlTemplate: ControlTemplate
+ get() = cws.control?.let { it.controlTemplate } ?: ControlTemplate.NO_TEMPLATE
init {
val ld = layout.getBackground() as LayerDrawable
@@ -139,14 +142,16 @@ class ControlViewHolder(
cancelUpdate?.run()
- val (controlStatus, template) = cws.control?.let {
- title.setText(it.getTitle())
- subtitle.setText(it.getSubtitle())
- Pair(it.status, it.controlTemplate)
- } ?: run {
+ // For the following statuses only, assume the title/subtitle could not be set properly
+ // by the app and instead use the last known information from favorites
+ if (controlStatus == Control.STATUS_UNKNOWN || controlStatus == Control.STATUS_NOT_FOUND) {
title.setText(cws.ci.controlTitle)
subtitle.setText(cws.ci.controlSubtitle)
- Pair(Control.STATUS_UNKNOWN, ControlTemplate.NO_TEMPLATE)
+ } else {
+ cws.control?.let {
+ title.setText(it.title)
+ subtitle.setText(it.subtitle)
+ }
}
cws.control?.let {
@@ -155,14 +160,19 @@ class ControlViewHolder(
controlActionCoordinator.longPress(this@ControlViewHolder)
true
})
+
+ controlActionCoordinator.runPendingAction(cws.ci.controlId)
}
isLoading = false
- behavior = bindBehavior(behavior, findBehaviorClass(controlStatus, template, deviceType))
+ behavior = bindBehavior(behavior,
+ findBehaviorClass(controlStatus, controlTemplate, deviceType))
updateContentDescription()
}
fun actionResponse(@ControlAction.ResponseResult response: Int) {
+ controlActionCoordinator.enableActionOnTouch(cws.ci.controlId)
+
// OK responses signal normal behavior, and the app will provide control updates
val failedAttempt = lastChallengeDialog != null
when (response) {
@@ -197,18 +207,24 @@ class ControlViewHolder(
fun dismiss() {
lastChallengeDialog?.dismiss()
lastChallengeDialog = null
+ visibleDialog?.dismiss()
+ visibleDialog = null
}
fun setTransientStatus(tempStatus: String) {
val previousText = status.getText()
cancelUpdate = uiExecutor.executeDelayed({
- setStatusText(previousText)
- updateContentDescription()
+ animateStatusChange(/* animated */ true, {
+ setStatusText(previousText, /* immediately */ true)
+ updateContentDescription()
+ })
}, UPDATE_DELAY_IN_MILLIS)
- setStatusText(tempStatus)
- updateContentDescription()
+ animateStatusChange(/* animated */ true, {
+ setStatusText(tempStatus, /* immediately */ true)
+ updateContentDescription()
+ })
}
private fun updateContentDescription() =
@@ -245,7 +261,13 @@ class ControlViewHolder(
}
internal fun applyRenderInfo(enabled: Boolean, offset: Int, animated: Boolean = true) {
- val ri = RenderInfo.lookup(context, cws.componentName, deviceType, offset)
+ val deviceTypeOrError = if (controlStatus == Control.STATUS_OK ||
+ controlStatus == Control.STATUS_UNKNOWN) {
+ deviceType
+ } else {
+ RenderInfo.ERROR_ICON
+ }
+ val ri = RenderInfo.lookup(context, cws.componentName, deviceTypeOrError, offset)
val fg = context.resources.getColorStateList(ri.foreground, context.theme)
val newText = nextStatusText
nextStatusText = ""
diff --git a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiControllerImpl.kt b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiControllerImpl.kt
index 35ebac5b1ed5..0f5aef7eeec1 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiControllerImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiControllerImpl.kt
@@ -19,16 +19,13 @@ package com.android.systemui.controls.ui
import android.animation.Animator
import android.animation.AnimatorListenerAdapter
import android.animation.ObjectAnimator
-import android.app.AlertDialog
import android.content.ComponentName
import android.content.Context
-import android.content.DialogInterface
import android.content.Intent
import android.content.SharedPreferences
import android.content.res.Configuration
import android.graphics.drawable.Drawable
import android.graphics.drawable.LayerDrawable
-import android.os.Process
import android.service.controls.Control
import android.util.Log
import android.util.TypedValue
@@ -36,7 +33,6 @@ import android.view.ContextThemeWrapper
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
-import android.view.WindowManager
import android.view.animation.AccelerateInterpolator
import android.view.animation.DecelerateInterpolator
import android.widget.AdapterView
@@ -129,7 +125,10 @@ class ControlsUiControllerImpl @Inject constructor (
SelectionItem(it.loadLabel(), "", it.loadIcon(), it.componentName)
}
uiExecutor.execute {
- onResult(lastItems)
+ parent.removeAllViews()
+ if (lastItems.size > 0) {
+ onResult(lastItems)
+ }
}
}
}
@@ -189,8 +188,6 @@ class ControlsUiControllerImpl @Inject constructor (
}
private fun showSeedingView(items: List<SelectionItem>) {
- parent.removeAllViews()
-
val inflater = LayoutInflater.from(context)
inflater.inflate(R.layout.controls_no_favorites, parent, true)
val subtitle = parent.requireViewById<TextView>(R.id.controls_subtitle)
@@ -198,8 +195,6 @@ class ControlsUiControllerImpl @Inject constructor (
}
private fun showInitialSetupView(items: List<SelectionItem>) {
- parent.removeAllViews()
-
val inflater = LayoutInflater.from(context)
inflater.inflate(R.layout.controls_no_favorites, parent, true)
@@ -263,7 +258,6 @@ class ControlsUiControllerImpl @Inject constructor (
}
private fun showControlsView(items: List<SelectionItem>) {
- parent.removeAllViews()
controlViewsById.clear()
createListView()
@@ -274,8 +268,7 @@ class ControlsUiControllerImpl @Inject constructor (
private fun createMenu() {
val items = arrayOf(
context.resources.getString(R.string.controls_menu_add),
- context.resources.getString(R.string.controls_menu_edit),
- "Reset"
+ context.resources.getString(R.string.controls_menu_edit)
)
var adapter = ArrayAdapter<String>(context, R.layout.controls_more_item, items)
@@ -300,10 +293,6 @@ class ControlsUiControllerImpl @Inject constructor (
0 -> startFavoritingActivity(view.context, selectedStructure)
// 1: Edit controls
1 -> startEditingActivity(view.context, selectedStructure)
- // 2: TEMPORARY for reset controls
- 2 -> showResetConfirmation()
- else -> Log.w(ControlsUiController.TAG,
- "Unsupported index ($pos) on 'more' menu selection")
}
dismiss()
}
@@ -314,39 +303,6 @@ class ControlsUiControllerImpl @Inject constructor (
})
}
- private fun showResetConfirmation() {
- val builder = AlertDialog.Builder(
- context,
- android.R.style.Theme_DeviceDefault_Dialog_Alert
- ).apply {
- setMessage("For testing purposes: Would you like to " +
- "reset your favorited device controls?")
- setPositiveButton(
- android.R.string.ok,
- DialogInterface.OnClickListener { dialog, _ ->
- val userHandle = Process.myUserHandle()
- val userContext = context.createContextAsUser(userHandle, 0)
- val prefs = userContext.getSharedPreferences(
- "controls_prefs", Context.MODE_PRIVATE)
- prefs.edit().remove("SeedingCompleted").apply()
- controlsController.get().resetFavorites()
- dialog.dismiss()
- context.sendBroadcast(Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS))
- })
- setNegativeButton(
- android.R.string.cancel,
- DialogInterface.OnClickListener {
- dialog, _ -> dialog.cancel()
- }
- )
- }
- builder.create().apply {
- getWindow().apply {
- setType(WindowManager.LayoutParams.TYPE_VOLUME_OVERLAY)
- }
- }.show()
- }
-
private fun createDropDown(items: List<SelectionItem>) {
items.forEach {
RenderInfo.registerComponentIcon(it.componentName, it.icon)
diff --git a/packages/SystemUI/src/com/android/systemui/controls/ui/DetailDialog.kt b/packages/SystemUI/src/com/android/systemui/controls/ui/DetailDialog.kt
index f97015282222..9ec14523a809 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/ui/DetailDialog.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/ui/DetailDialog.kt
@@ -64,6 +64,10 @@ class DetailDialog(
}
override fun onActivityViewDestroyed(view: ActivityView) {}
+
+ override fun onTaskRemovalStarted(taskId: Int) {
+ dismiss()
+ }
}
init {
diff --git a/packages/SystemUI/src/com/android/systemui/controls/ui/RenderInfo.kt b/packages/SystemUI/src/com/android/systemui/controls/ui/RenderInfo.kt
index 09d41bdd6927..3f17a4fefd7e 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/ui/RenderInfo.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/ui/RenderInfo.kt
@@ -35,6 +35,7 @@ data class RenderInfo(
) {
companion object {
const val APP_ICON_ID = -1
+ const val ERROR_ICON = -1000
private val iconMap = SparseArray<Drawable>()
private val appIconMap = ArrayMap<ComponentName, Drawable>()
@@ -156,7 +157,8 @@ private val deviceIconMap = mapOf<Int, Int>(
DeviceTypes.TYPE_CURTAIN to R.drawable.ic_device_blinds,
DeviceTypes.TYPE_DOOR to R.drawable.ic_device_door,
DeviceTypes.TYPE_SHUTTER to R.drawable.ic_device_window,
- DeviceTypes.TYPE_HEATER to R.drawable.ic_device_thermostat
+ DeviceTypes.TYPE_HEATER to R.drawable.ic_device_thermostat,
+ RenderInfo.ERROR_ICON to R.drawable.ic_error_outline
).withDefault {
R.drawable.ic_device_unknown
}
diff --git a/packages/SystemUI/src/com/android/systemui/controls/ui/StatusBehavior.kt b/packages/SystemUI/src/com/android/systemui/controls/ui/StatusBehavior.kt
index bf3835dba4fd..dac55378daca 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/ui/StatusBehavior.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/ui/StatusBehavior.kt
@@ -16,7 +16,14 @@
package com.android.systemui.controls.ui
+import android.app.AlertDialog
+import android.app.PendingIntent
+import android.content.DialogInterface
+import android.content.Intent
+import android.content.pm.PackageManager
import android.service.controls.Control
+import android.view.View
+import android.view.WindowManager
import com.android.systemui.R
@@ -31,7 +38,17 @@ class StatusBehavior : Behavior {
val status = cws.control?.status ?: Control.STATUS_UNKNOWN
val msg = when (status) {
Control.STATUS_ERROR -> R.string.controls_error_generic
- Control.STATUS_NOT_FOUND -> R.string.controls_error_removed
+ Control.STATUS_DISABLED -> R.string.controls_error_timeout
+ Control.STATUS_NOT_FOUND -> {
+ cvh.layout.setOnClickListener(View.OnClickListener() {
+ showNotFoundDialog(cvh, cws)
+ })
+ cvh.layout.setOnLongClickListener(View.OnLongClickListener() {
+ showNotFoundDialog(cvh, cws)
+ true
+ })
+ R.string.controls_error_removed
+ }
else -> {
cvh.isLoading = true
com.android.internal.R.string.loading
@@ -40,4 +57,43 @@ class StatusBehavior : Behavior {
cvh.setStatusText(cvh.context.getString(msg))
cvh.applyRenderInfo(false, colorOffset)
}
+
+ private fun showNotFoundDialog(cvh: ControlViewHolder, cws: ControlWithState) {
+ val pm = cvh.context.getPackageManager()
+ val ai = pm.getApplicationInfo(cws.componentName.packageName, PackageManager.GET_META_DATA)
+ val appLabel = pm.getApplicationLabel(ai)
+ val builder = AlertDialog.Builder(
+ cvh.context,
+ android.R.style.Theme_DeviceDefault_Dialog_Alert
+ ).apply {
+ val res = cvh.context.resources
+ setTitle(res.getString(R.string.controls_error_removed_title))
+ setMessage(res.getString(
+ R.string.controls_error_removed_message, cvh.title.getText(), appLabel))
+ setPositiveButton(
+ R.string.controls_open_app,
+ DialogInterface.OnClickListener { dialog, _ ->
+ try {
+ cws.control?.getAppIntent()?.send()
+ context.sendBroadcast(Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS))
+ } catch (e: PendingIntent.CanceledException) {
+ cvh.setTransientStatus(
+ cvh.context.resources.getString(R.string.controls_error_failed))
+ }
+ dialog.dismiss()
+ })
+ setNegativeButton(
+ android.R.string.cancel,
+ DialogInterface.OnClickListener { dialog, _ ->
+ dialog.cancel()
+ }
+ )
+ }
+ cvh.visibleDialog = builder.create().apply {
+ getWindow().apply {
+ setType(WindowManager.LayoutParams.TYPE_VOLUME_OVERLAY)
+ show()
+ }
+ }
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/controls/ui/ToggleRangeBehavior.kt b/packages/SystemUI/src/com/android/systemui/controls/ui/ToggleRangeBehavior.kt
index 1f0ca9be2ecc..02f80e842516 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/ui/ToggleRangeBehavior.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/ui/ToggleRangeBehavior.kt
@@ -24,7 +24,6 @@ import android.graphics.drawable.Drawable
import android.graphics.drawable.LayerDrawable
import android.os.Bundle
import android.service.controls.Control
-import android.service.controls.actions.FloatAction
import android.service.controls.templates.ControlTemplate
import android.service.controls.templates.RangeTemplate
import android.service.controls.templates.TemperatureControlTemplate
@@ -231,9 +230,11 @@ class ToggleRangeBehavior : Behavior {
rangeAnimator?.cancel()
if (isDragging) {
- clipLayer.level = newLevel
val isEdge = newLevel == MIN_LEVEL || newLevel == MAX_LEVEL
- cvh.controlActionCoordinator.drag(isEdge)
+ if (clipLayer.level != newLevel) {
+ cvh.controlActionCoordinator.drag(isEdge)
+ clipLayer.level = newLevel
+ }
} else if (newLevel != clipLayer.level) {
rangeAnimator = ValueAnimator.ofInt(cvh.clipLayer.level, newLevel).apply {
addUpdateListener {
@@ -266,7 +267,7 @@ class ToggleRangeBehavior : Behavior {
private fun format(primaryFormat: String, backupFormat: String, value: Float): String {
return try {
- String.format(primaryFormat, value)
+ String.format(primaryFormat, findNearestStep(value))
} catch (e: IllegalFormatException) {
Log.w(ControlsUiController.TAG, "Illegal format in range template", e)
if (backupFormat == "") {
@@ -291,8 +292,8 @@ class ToggleRangeBehavior : Behavior {
cvh.setStatusTextSize(context.getResources()
.getDimensionPixelSize(R.dimen.control_status_normal).toFloat())
cvh.setStatusText("$currentStatusText $currentRangeValue", /* immediately */ true)
- cvh.action(FloatAction(rangeTemplate.getTemplateId(),
- findNearestStep(levelToRangeValue(clipLayer.getLevel()))))
+ cvh.controlActionCoordinator.setValue(cvh, rangeTemplate.getTemplateId(),
+ findNearestStep(levelToRangeValue(clipLayer.getLevel())))
}
fun findNearestStep(value: Float): Float {
diff --git a/packages/SystemUI/src/com/android/systemui/controls/ui/Vibrations.kt b/packages/SystemUI/src/com/android/systemui/controls/ui/Vibrations.kt
index c0f6aabe2427..29b7e985fabc 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/ui/Vibrations.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/ui/Vibrations.kt
@@ -20,35 +20,9 @@ import android.os.VibrationEffect
import android.os.VibrationEffect.Composition.PRIMITIVE_TICK
object Vibrations {
- private const val TOGGLE_TICK_COUNT = 40
-
- val toggleOnEffect = initToggleOnEffect()
- val toggleOffEffect = initToggleOffEffect()
val rangeEdgeEffect = initRangeEdgeEffect()
val rangeMiddleEffect = initRangeMiddleEffect()
- private fun initToggleOnEffect(): VibrationEffect {
- val composition = VibrationEffect.startComposition()
- composition.addPrimitive(PRIMITIVE_TICK, 0.05f, 200)
- var i = 0
- while (i++ < TOGGLE_TICK_COUNT) {
- composition.addPrimitive(PRIMITIVE_TICK, 0.05f, 0)
- }
- composition.addPrimitive(PRIMITIVE_TICK, 0.5f, 100)
- return composition.compose()
- }
-
- private fun initToggleOffEffect(): VibrationEffect {
- val composition = VibrationEffect.startComposition()
- composition.addPrimitive(PRIMITIVE_TICK, 0.5f, 0)
- composition.addPrimitive(PRIMITIVE_TICK, 0.05f, 100)
- var i = 0
- while (i++ < TOGGLE_TICK_COUNT) {
- composition.addPrimitive(PRIMITIVE_TICK, 0.05f, 0)
- }
- return composition.compose()
- }
-
private fun initRangeEdgeEffect(): VibrationEffect {
val composition = VibrationEffect.startComposition()
composition.addPrimitive(VibrationEffect.Composition.PRIMITIVE_TICK, 0.5f)
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/DefaultActivityBinder.java b/packages/SystemUI/src/com/android/systemui/dagger/DefaultActivityBinder.java
index 91f032d86a94..28bcf3a35117 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/DefaultActivityBinder.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/DefaultActivityBinder.java
@@ -24,6 +24,8 @@ import com.android.systemui.keyguard.WorkLockActivity;
import com.android.systemui.screenrecord.ScreenRecordDialog;
import com.android.systemui.settings.BrightnessDialog;
import com.android.systemui.tuner.TunerActivity;
+import com.android.systemui.usb.UsbDebuggingActivity;
+import com.android.systemui.usb.UsbDebuggingSecondaryUserActivity;
import dagger.Binds;
import dagger.Module;
@@ -70,4 +72,17 @@ public abstract class DefaultActivityBinder {
@IntoMap
@ClassKey(BubbleOverflowActivity.class)
public abstract Activity bindBubbleOverflowActivity(BubbleOverflowActivity activity);
+
+ /** Inject into UsbDebuggingActivity. */
+ @Binds
+ @IntoMap
+ @ClassKey(UsbDebuggingActivity.class)
+ public abstract Activity bindUsbDebuggingActivity(UsbDebuggingActivity activity);
+
+ /** Inject into UsbDebuggingSecondaryUserActivity. */
+ @Binds
+ @IntoMap
+ @ClassKey(UsbDebuggingSecondaryUserActivity.class)
+ public abstract Activity bindUsbDebuggingSecondaryUserActivity(
+ UsbDebuggingSecondaryUserActivity activity);
}
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeFactory.java b/packages/SystemUI/src/com/android/systemui/doze/DozeFactory.java
index 95a9006c854a..951dc9936e1c 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeFactory.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeFactory.java
@@ -71,7 +71,7 @@ public class DozeFactory {
DockManager dockManager, @Nullable IWallpaperManager wallpaperManager,
ProximitySensor proximitySensor,
DelayedWakeLock.Builder delayedWakeLockBuilder, @Main Handler handler,
- DelayableExecutor delayableExecutor,
+ @Main DelayableExecutor delayableExecutor,
BiometricUnlockController biometricUnlockController,
BroadcastDispatcher broadcastDispatcher, DozeHost dozeHost) {
mFalsingManager = falsingManager;
diff --git a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java
index 1b13d4a49fec..bc95a2514c0b 100644
--- a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java
@@ -175,7 +175,7 @@ public class GlobalActionsDialog implements DialogInterface.OnDismissListener,
private static final String GLOBAL_ACTION_KEY_SILENT = "silent";
private static final String GLOBAL_ACTION_KEY_USERS = "users";
private static final String GLOBAL_ACTION_KEY_SETTINGS = "settings";
- private static final String GLOBAL_ACTION_KEY_LOCKDOWN = "lockdown";
+ static final String GLOBAL_ACTION_KEY_LOCKDOWN = "lockdown";
private static final String GLOBAL_ACTION_KEY_VOICEASSIST = "voiceassist";
private static final String GLOBAL_ACTION_KEY_ASSIST = "assist";
static final String GLOBAL_ACTION_KEY_RESTART = "restart";
@@ -183,8 +183,8 @@ public class GlobalActionsDialog implements DialogInterface.OnDismissListener,
static final String GLOBAL_ACTION_KEY_EMERGENCY = "emergency";
static final String GLOBAL_ACTION_KEY_SCREENSHOT = "screenshot";
- private static final String PREFS_CONTROLS_SEEDING_COMPLETED = "SeedingCompleted";
- private static final String PREFS_CONTROLS_FILE = "controls_prefs";
+ public static final String PREFS_CONTROLS_SEEDING_COMPLETED = "SeedingCompleted";
+ public static final String PREFS_CONTROLS_FILE = "controls_prefs";
private static final int SEEDING_MAX = 2;
private final Context mContext;
@@ -213,7 +213,9 @@ public class GlobalActionsDialog implements DialogInterface.OnDismissListener,
@VisibleForTesting
protected final ArrayList<Action> mItems = new ArrayList<>();
@VisibleForTesting
- final ArrayList<Action> mOverflowItems = new ArrayList<>();
+ protected final ArrayList<Action> mOverflowItems = new ArrayList<>();
+ @VisibleForTesting
+ protected final ArrayList<Action> mPowerItems = new ArrayList<>();
@VisibleForTesting
protected ActionsDialog mDialog;
@@ -223,6 +225,7 @@ public class GlobalActionsDialog implements DialogInterface.OnDismissListener,
private MyAdapter mAdapter;
private MyOverflowAdapter mOverflowAdapter;
+ private MyPowerOptionsAdapter mPowerAdapter;
private boolean mKeyguardShowing = false;
private boolean mDeviceProvisioned = false;
@@ -391,7 +394,15 @@ public class GlobalActionsDialog implements DialogInterface.OnDismissListener,
if (controlsComponent.getControlsListingController().isPresent()) {
controlsComponent.getControlsListingController().get()
- .addCallback(list -> mControlsServiceInfos = list);
+ .addCallback(list -> {
+ mControlsServiceInfos = list;
+ // This callback may occur after the dialog has been shown.
+ // If so, add controls into the already visible space
+ if (mDialog != null && !mDialog.isShowingControls()
+ && shouldShowControls()) {
+ mDialog.showControls(mControlsUiControllerOptional.get());
+ }
+ });
}
// Need to be user-specific with the context to make sure we read the correct prefs
@@ -576,14 +587,19 @@ public class GlobalActionsDialog implements DialogInterface.OnDismissListener,
mItems.clear();
mOverflowItems.clear();
-
+ mPowerItems.clear();
String[] defaultActions = getDefaultActions();
+
+ ShutDownAction shutdownAction = new ShutDownAction();
+ RestartAction restartAction = new RestartAction();
+ ArraySet<String> addedKeys = new ArraySet<String>();
+
// make sure emergency affordance action is first, if needed
if (mEmergencyAffordanceManager.needsEmergencyAffordance()) {
addActionItem(new EmergencyAffordanceAction());
+ addedKeys.add(GLOBAL_ACTION_KEY_EMERGENCY);
}
- ArraySet<String> addedKeys = new ArraySet<String>();
for (int i = 0; i < defaultActions.length; i++) {
String actionKey = defaultActions[i];
if (addedKeys.contains(actionKey)) {
@@ -591,7 +607,7 @@ public class GlobalActionsDialog implements DialogInterface.OnDismissListener,
continue;
}
if (GLOBAL_ACTION_KEY_POWER.equals(actionKey)) {
- addActionItem(new PowerAction());
+ addActionItem(shutdownAction);
} else if (GLOBAL_ACTION_KEY_AIRPLANE.equals(actionKey)) {
addActionItem(mAirplaneModeOn);
} else if (GLOBAL_ACTION_KEY_BUGREPORT.equals(actionKey)) {
@@ -610,10 +626,7 @@ public class GlobalActionsDialog implements DialogInterface.OnDismissListener,
} else if (GLOBAL_ACTION_KEY_SETTINGS.equals(actionKey)) {
addActionItem(getSettingsAction());
} else if (GLOBAL_ACTION_KEY_LOCKDOWN.equals(actionKey)) {
- int userId = getCurrentUser().id;
- if (Settings.Secure.getIntForUser(mContentResolver,
- Settings.Secure.LOCKDOWN_IN_POWER_MENU, 0, userId) != 0
- && shouldDisplayLockdown(userId)) {
+ if (shouldDisplayLockdown(getCurrentUser())) {
addActionItem(getLockdownAction());
}
} else if (GLOBAL_ACTION_KEY_VOICEASSIST.equals(actionKey)) {
@@ -621,7 +634,7 @@ public class GlobalActionsDialog implements DialogInterface.OnDismissListener,
} else if (GLOBAL_ACTION_KEY_ASSIST.equals(actionKey)) {
addActionItem(getAssistAction());
} else if (GLOBAL_ACTION_KEY_RESTART.equals(actionKey)) {
- addActionItem(new RestartAction());
+ addActionItem(restartAction);
} else if (GLOBAL_ACTION_KEY_SCREENSHOT.equals(actionKey)) {
addActionItem(new ScreenshotAction());
} else if (GLOBAL_ACTION_KEY_LOGOUT.equals(actionKey)) {
@@ -630,15 +643,32 @@ public class GlobalActionsDialog implements DialogInterface.OnDismissListener,
addActionItem(new LogoutAction());
}
} else if (GLOBAL_ACTION_KEY_EMERGENCY.equals(actionKey)) {
- if (!mEmergencyAffordanceManager.needsEmergencyAffordance()) {
- addActionItem(new EmergencyDialerAction());
- }
+ addActionItem(new EmergencyDialerAction());
} else {
Log.e(TAG, "Invalid global action key " + actionKey);
}
// Add here so we don't add more than one.
addedKeys.add(actionKey);
}
+
+ // replace power and restart with a single power options action, if needed
+ if (mItems.contains(shutdownAction) && mItems.contains(restartAction)
+ && mOverflowItems.size() > 0) {
+ // transfer shutdown and restart to their own list of power actions
+ mItems.remove(shutdownAction);
+ mItems.remove(restartAction);
+ mPowerItems.add(shutdownAction);
+ mPowerItems.add(restartAction);
+
+ // add the PowerOptionsAction after Emergency, if present
+ int powerIndex = addedKeys.contains(GLOBAL_ACTION_KEY_EMERGENCY) ? 1 : 0;
+ mItems.add(powerIndex, new PowerOptionsAction());
+
+ // transfer the first overflow action to the main set of items
+ Action firstOverflowAction = mOverflowItems.get(0);
+ mOverflowItems.remove(0);
+ mItems.add(firstOverflowAction);
+ }
}
private void onRotate() {
@@ -656,6 +686,7 @@ public class GlobalActionsDialog implements DialogInterface.OnDismissListener,
mAdapter = new MyAdapter();
mOverflowAdapter = new MyOverflowAdapter();
+ mPowerAdapter = new MyPowerOptionsAdapter();
mDepthController.setShowingHomeControls(true);
GlobalActionsPanelPlugin.PanelViewController walletViewController =
@@ -668,7 +699,7 @@ public class GlobalActionsDialog implements DialogInterface.OnDismissListener,
walletViewController, mDepthController, mSysuiColorExtractor,
mStatusBarService, mNotificationShadeWindowController,
controlsAvailable(), uiController,
- mSysUiState, this::onRotate, mKeyguardShowing);
+ mSysUiState, this::onRotate, mKeyguardShowing, mPowerAdapter);
boolean walletViewAvailable = walletViewController != null
&& walletViewController.getPanelContent() != null;
if (shouldShowLockMessage(walletViewAvailable)) {
@@ -681,7 +712,20 @@ public class GlobalActionsDialog implements DialogInterface.OnDismissListener,
return dialog;
}
- private boolean shouldDisplayLockdown(int userId) {
+ @VisibleForTesting
+ protected boolean shouldDisplayLockdown(UserInfo user) {
+ if (user == null) {
+ return false;
+ }
+
+ int userId = user.id;
+
+ // No lockdown option if it's not turned on in Settings
+ if (Settings.Secure.getIntForUser(mContentResolver,
+ Settings.Secure.LOCKDOWN_IN_POWER_MENU, 0, userId) == 0) {
+ return false;
+ }
+
// Lockdown is meaningless without a place to go.
if (!mKeyguardStateController.isMethodSecure()) {
return false;
@@ -732,8 +776,33 @@ public class GlobalActionsDialog implements DialogInterface.OnDismissListener,
mActivityStarter.startPendingIntentDismissingKeyguard(pendingIntent);
}
- private final class PowerAction extends SinglePressAction implements LongPressAction {
- private PowerAction() {
+ @VisibleForTesting
+ protected final class PowerOptionsAction extends SinglePressAction {
+ private PowerOptionsAction() {
+ super(com.android.systemui.R.drawable.ic_settings_power,
+ R.string.global_action_power_options);
+ }
+
+ @Override
+ public boolean showDuringKeyguard() {
+ return true;
+ }
+
+ @Override
+ public boolean showBeforeProvisioning() {
+ return true;
+ }
+
+ @Override
+ public void onPress() {
+ if (mDialog != null) {
+ mDialog.showPowerOptionsMenu();
+ }
+ }
+ }
+
+ private final class ShutDownAction extends SinglePressAction implements LongPressAction {
+ private ShutDownAction() {
super(R.drawable.ic_lock_power_off,
R.string.global_action_power_off);
}
@@ -764,7 +833,8 @@ public class GlobalActionsDialog implements DialogInterface.OnDismissListener,
}
}
- private abstract class EmergencyAction extends SinglePressAction {
+ @VisibleForTesting
+ protected abstract class EmergencyAction extends SinglePressAction {
EmergencyAction(int iconResId, int messageResId) {
super(iconResId, messageResId);
}
@@ -1309,7 +1379,10 @@ public class GlobalActionsDialog implements DialogInterface.OnDismissListener,
Action item = mAdapter.getItem(position);
if (!(item instanceof SilentModeTriStateAction)) {
if (mDialog != null) {
- mDialog.dismiss();
+ // don't dismiss the dialog if we're opening the power options menu
+ if (!(item instanceof PowerOptionsAction)) {
+ mDialog.dismiss();
+ }
} else {
Log.w(TAG, "Action clicked while mDialog is null.");
}
@@ -1326,6 +1399,70 @@ public class GlobalActionsDialog implements DialogInterface.OnDismissListener,
/**
* The adapter used for items in the overflow menu.
*/
+ public class MyPowerOptionsAdapter extends BaseAdapter {
+ @Override
+ public int getCount() {
+ return mPowerItems.size();
+ }
+
+ @Override
+ public Action getItem(int position) {
+ return mPowerItems.get(position);
+ }
+
+ @Override
+ public long getItemId(int position) {
+ return position;
+ }
+
+ @Override
+ public View getView(int position, View convertView, ViewGroup parent) {
+ Action action = getItem(position);
+ if (action == null) {
+ Log.w(TAG, "No power options action found at position: " + position);
+ return null;
+ }
+ int viewLayoutResource = com.android.systemui.R.layout.controls_more_item;
+ View view = convertView != null ? convertView
+ : LayoutInflater.from(mContext).inflate(viewLayoutResource, parent, false);
+ TextView textView = (TextView) view;
+ if (action.getMessageResId() != 0) {
+ textView.setText(action.getMessageResId());
+ } else {
+ textView.setText(action.getMessage());
+ }
+ return textView;
+ }
+
+ private boolean onLongClickItem(int position) {
+ final Action action = getItem(position);
+ if (action instanceof LongPressAction) {
+ if (mDialog != null) {
+ mDialog.dismiss();
+ } else {
+ Log.w(TAG, "Action long-clicked while mDialog is null.");
+ }
+ return ((LongPressAction) action).onLongPress();
+ }
+ return false;
+ }
+
+ private void onClickItem(int position) {
+ Action item = getItem(position);
+ if (!(item instanceof SilentModeTriStateAction)) {
+ if (mDialog != null) {
+ mDialog.dismiss();
+ } else {
+ Log.w(TAG, "Action clicked while mDialog is null.");
+ }
+ item.onPress();
+ }
+ }
+ }
+
+ /**
+ * The adapter used for items in the power options menu, triggered by the PowerOptionsAction.
+ */
public class MyOverflowAdapter extends BaseAdapter {
@Override
public int getCount() {
@@ -1365,7 +1502,6 @@ public class GlobalActionsDialog implements DialogInterface.OnDismissListener,
final Action action = getItem(position);
if (action instanceof LongPressAction) {
if (mDialog != null) {
- mDialog.hidePowerOverflowMenu();
mDialog.dismiss();
} else {
Log.w(TAG, "Action long-clicked while mDialog is null.");
@@ -1379,7 +1515,6 @@ public class GlobalActionsDialog implements DialogInterface.OnDismissListener,
Action item = getItem(position);
if (!(item instanceof SilentModeTriStateAction)) {
if (mDialog != null) {
- mDialog.hidePowerOverflowMenu();
mDialog.dismiss();
} else {
Log.w(TAG, "Action clicked while mDialog is null.");
@@ -1487,7 +1622,6 @@ public class GlobalActionsDialog implements DialogInterface.OnDismissListener,
}
}
-
public int getMessageResId() {
return mMessageResId;
}
@@ -1838,6 +1972,8 @@ public class GlobalActionsDialog implements DialogInterface.OnDismissListener,
mAirplaneState = inAirplaneMode ? ToggleState.On : ToggleState.Off;
mAirplaneModeOn.updateState(mAirplaneState);
mAdapter.notifyDataSetChanged();
+ mOverflowAdapter.notifyDataSetChanged();
+ mPowerAdapter.notifyDataSetChanged();
}
};
@@ -1920,6 +2056,7 @@ public class GlobalActionsDialog implements DialogInterface.OnDismissListener,
private final Context mContext;
private final MyAdapter mAdapter;
private final MyOverflowAdapter mOverflowAdapter;
+ private final MyPowerOptionsAdapter mPowerOptionsAdapter;
private final IStatusBarService mStatusBarService;
private final IBinder mToken = new Binder();
private MultiListLayout mGlobalActionsLayout;
@@ -1935,6 +2072,7 @@ public class GlobalActionsDialog implements DialogInterface.OnDismissListener,
private final NotificationShadeDepthController mDepthController;
private final SysUiState mSysUiState;
private ListPopupWindow mOverflowPopup;
+ private ListPopupWindow mPowerOptionsPopup;
private final Runnable mOnRotateCallback;
private final boolean mControlsAvailable;
@@ -1950,11 +2088,13 @@ public class GlobalActionsDialog implements DialogInterface.OnDismissListener,
SysuiColorExtractor sysuiColorExtractor, IStatusBarService statusBarService,
NotificationShadeWindowController notificationShadeWindowController,
boolean controlsAvailable, @Nullable ControlsUiController controlsUiController,
- SysUiState sysuiState, Runnable onRotateCallback, boolean keyguardShowing) {
+ SysUiState sysuiState, Runnable onRotateCallback, boolean keyguardShowing,
+ MyPowerOptionsAdapter powerAdapter) {
super(context, com.android.systemui.R.style.Theme_SystemUI_Dialog_GlobalActions);
mContext = context;
mAdapter = adapter;
mOverflowAdapter = overflowAdapter;
+ mPowerOptionsAdapter = powerAdapter;
mDepthController = depthController;
mColorExtractor = sysuiColorExtractor;
mStatusBarService = statusBarService;
@@ -2068,6 +2208,21 @@ public class GlobalActionsDialog implements DialogInterface.OnDismissListener,
}
}
+ private ListPopupWindow createPowerOptionsPopup() {
+ GlobalActionsPopupMenu popup = new GlobalActionsPopupMenu(
+ new ContextThemeWrapper(
+ mContext,
+ com.android.systemui.R.style.Control_ListPopupWindow
+ ), false /* isDropDownMode */);
+ popup.setOnItemClickListener(
+ (parent, view, position, id) -> mPowerOptionsAdapter.onClickItem(position));
+ popup.setOnItemLongClickListener(
+ (parent, view, position, id) -> mPowerOptionsAdapter.onLongClickItem(position));
+ popup.setAnchorView(mGlobalActionsLayout);
+ popup.setAdapter(mPowerOptionsAdapter);
+ return popup;
+ }
+
private ListPopupWindow createPowerOverflowPopup() {
GlobalActionsPopupMenu popup = new GlobalActionsPopupMenu(
new ContextThemeWrapper(
@@ -2085,16 +2240,16 @@ public class GlobalActionsDialog implements DialogInterface.OnDismissListener,
return popup;
}
+ public void showPowerOptionsMenu() {
+ mPowerOptionsPopup = createPowerOptionsPopup();
+ mPowerOptionsPopup.show();
+ }
+
private void showPowerOverflowMenu() {
mOverflowPopup = createPowerOverflowPopup();
mOverflowPopup.show();
}
- private void hidePowerOverflowMenu() {
- mOverflowPopup.dismiss();
- mOverflowPopup = null;
- }
-
private void initializeLayout() {
setContentView(com.android.systemui.R.layout.global_actions_grid_v2);
fixNavBarClipping();
@@ -2270,6 +2425,7 @@ public class GlobalActionsDialog implements DialogInterface.OnDismissListener,
// close first, as popup windows will not fade during the animation
dismissOverflow(false);
+ dismissPowerOptions(false);
if (mControlsUiController != null) mControlsUiController.closeDialogs(false);
});
}
@@ -2294,6 +2450,7 @@ public class GlobalActionsDialog implements DialogInterface.OnDismissListener,
resetOrientation();
dismissWallet();
dismissOverflow(true);
+ dismissPowerOptions(true);
if (mControlsUiController != null) mControlsUiController.hide();
mNotificationShadeWindowController.setForceHasTopUi(mHadTopUi);
mDepthController.updateGlobalDialogVisibility(0, null /* view */);
@@ -2318,6 +2475,16 @@ public class GlobalActionsDialog implements DialogInterface.OnDismissListener,
}
}
+ private void dismissPowerOptions(boolean immediate) {
+ if (mPowerOptionsPopup != null) {
+ if (immediate) {
+ mPowerOptionsPopup.dismissImmediate();
+ } else {
+ mPowerOptionsPopup.dismiss();
+ }
+ }
+ }
+
private void setRotationSuggestionsEnabled(boolean enabled) {
try {
final int userId = Binder.getCallingUserHandle().getIdentifier();
@@ -2361,6 +2528,7 @@ public class GlobalActionsDialog implements DialogInterface.OnDismissListener,
// ensure dropdown menus are dismissed before re-initializing the dialog
dismissWallet();
dismissOverflow(true);
+ dismissPowerOptions(true);
if (mControlsUiController != null) {
mControlsUiController.hide();
}
diff --git a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsPopupMenu.java b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsPopupMenu.java
index 6b71f1e9d86f..1dbbb4d69493 100644
--- a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsPopupMenu.java
+++ b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsPopupMenu.java
@@ -19,6 +19,7 @@ import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.Context;
import android.content.res.Resources;
+import android.util.LayoutDirection;
import android.view.View;
import android.view.View.MeasureSpec;
import android.view.WindowManager;
@@ -106,7 +107,11 @@ public class GlobalActionsPopupMenu extends ListPopupWindow {
listView.setPadding(0, mMenuVerticalPadding, 0, mMenuVerticalPadding);
setWidth(width);
- setHorizontalOffset(getAnchorView().getWidth() - mGlobalActionsSidePadding - width);
+ if (getAnchorView().getLayoutDirection() == LayoutDirection.LTR) {
+ setHorizontalOffset(getAnchorView().getWidth() - mGlobalActionsSidePadding - width);
+ } else {
+ setHorizontalOffset(mGlobalActionsSidePadding);
+ }
}
super.show();
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaControlPanel.java b/packages/SystemUI/src/com/android/systemui/media/MediaControlPanel.java
index 5595201a670f..f039fc2d84ae 100644
--- a/packages/SystemUI/src/com/android/systemui/media/MediaControlPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaControlPanel.java
@@ -17,12 +17,8 @@
package com.android.systemui.media;
import android.app.PendingIntent;
-import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
-import android.content.SharedPreferences;
-import android.content.pm.PackageManager;
-import android.content.pm.ResolveInfo;
import android.content.res.ColorStateList;
import android.graphics.Bitmap;
import android.graphics.Canvas;
@@ -35,7 +31,6 @@ import android.graphics.drawable.RippleDrawable;
import android.media.session.MediaController;
import android.media.session.MediaSession;
import android.media.session.PlaybackState;
-import android.service.media.MediaBrowserService;
import android.util.Log;
import android.view.View;
import android.widget.ImageButton;
@@ -54,16 +49,17 @@ import com.android.settingslib.Utils;
import com.android.settingslib.media.MediaOutputSliceConstants;
import com.android.settingslib.widget.AdaptiveIcon;
import com.android.systemui.R;
+import com.android.systemui.dagger.qualifiers.Background;
import com.android.systemui.plugins.ActivityStarter;
-import com.android.systemui.qs.QSMediaBrowser;
import com.android.systemui.util.animation.TransitionLayout;
-import com.android.systemui.util.concurrency.DelayableExecutor;
import org.jetbrains.annotations.NotNull;
import java.util.List;
import java.util.concurrent.Executor;
+import javax.inject.Inject;
+
/**
* A view controller used for Media Playback.
*/
@@ -81,7 +77,6 @@ public class MediaControlPanel {
private final SeekBarViewModel mSeekBarViewModel;
private SeekBarObserver mSeekBarObserver;
- private final Executor mForegroundExecutor;
protected final Executor mBackgroundExecutor;
private final ActivityStarter mActivityStarter;
@@ -91,51 +86,23 @@ public class MediaControlPanel {
private MediaSession.Token mToken;
private MediaController mController;
private int mBackgroundColor;
- protected ComponentName mServiceComponent;
- private boolean mIsRegistered = false;
- private String mKey;
private int mAlbumArtSize;
private int mAlbumArtRadius;
- private int mViewWidth;
-
- public static final String MEDIA_PREFERENCES = "media_control_prefs";
- public static final String MEDIA_PREFERENCE_KEY = "browser_components";
- private SharedPreferences mSharedPrefs;
- private boolean mCheckedForResumption = false;
- private QSMediaBrowser mQSMediaBrowser;
-
- private final MediaController.Callback mSessionCallback = new MediaController.Callback() {
- @Override
- public void onSessionDestroyed() {
- Log.d(TAG, "session destroyed");
- mController.unregisterCallback(mSessionCallback);
- clearControls();
- }
- @Override
- public void onPlaybackStateChanged(PlaybackState state) {
- final int s = state != null ? state.getState() : PlaybackState.STATE_NONE;
- if (s == PlaybackState.STATE_NONE) {
- Log.d(TAG, "playback state change will trigger resumption, state=" + state);
- clearControls();
- }
- }
- };
/**
* Initialize a new control panel
* @param context
- * @param foregroundExecutor foreground executor
* @param backgroundExecutor background executor, used for processing artwork
* @param activityStarter activity starter
*/
- public MediaControlPanel(Context context, Executor foregroundExecutor,
- DelayableExecutor backgroundExecutor, ActivityStarter activityStarter,
- MediaHostStatesManager mediaHostStatesManager) {
+ @Inject
+ public MediaControlPanel(Context context, @Background Executor backgroundExecutor,
+ ActivityStarter activityStarter, MediaHostStatesManager mediaHostStatesManager,
+ SeekBarViewModel seekBarViewModel) {
mContext = context;
- mForegroundExecutor = foregroundExecutor;
mBackgroundExecutor = backgroundExecutor;
mActivityStarter = activityStarter;
- mSeekBarViewModel = new SeekBarViewModel(backgroundExecutor);
+ mSeekBarViewModel = seekBarViewModel;
mMediaViewController = new MediaViewController(context, mediaHostStatesManager);
loadDimens();
}
@@ -214,45 +181,18 @@ public class MediaControlPanel {
MediaSession.Token token = data.getToken();
mBackgroundColor = data.getBackgroundColor();
if (mToken == null || !mToken.equals(token)) {
- if (mQSMediaBrowser != null) {
- Log.d(TAG, "Disconnecting old media browser");
- mQSMediaBrowser.disconnect();
- mQSMediaBrowser = null;
- }
mToken = token;
- mServiceComponent = null;
- mCheckedForResumption = false;
}
- mController = new MediaController(mContext, mToken);
+ if (mToken != null) {
+ mController = new MediaController(mContext, mToken);
+ } else {
+ mController = null;
+ }
ConstraintSet expandedSet = mMediaViewController.getExpandedLayout();
ConstraintSet collapsedSet = mMediaViewController.getCollapsedLayout();
- // Try to find a browser service component for this app
- // TODO also check for a media button receiver intended for restarting (b/154127084)
- // Only check if we haven't tried yet or the session token changed
- final String pkgName = data.getPackageName();
- if (mServiceComponent == null && !mCheckedForResumption) {
- Log.d(TAG, "Checking for service component");
- PackageManager pm = mContext.getPackageManager();
- Intent resumeIntent = new Intent(MediaBrowserService.SERVICE_INTERFACE);
- List<ResolveInfo> resumeInfo = pm.queryIntentServices(resumeIntent, 0);
- // TODO: look into this resumption
- if (resumeInfo != null) {
- for (ResolveInfo inf : resumeInfo) {
- if (inf.serviceInfo.packageName.equals(mController.getPackageName())) {
- mBackgroundExecutor.execute(() ->
- tryUpdateResumptionList(inf.getComponentInfo().getComponentName()));
- break;
- }
- }
- }
- mCheckedForResumption = true;
- }
-
- mController.registerCallback(mSessionCallback);
-
mViewHolder.getPlayer().setBackgroundTintList(
ColorStateList.valueOf(mBackgroundColor));
@@ -267,12 +207,22 @@ public class MediaControlPanel {
ImageView albumView = mViewHolder.getAlbumView();
// TODO: migrate this to a view with rounded corners instead of baking the rounding
// into the bitmap
- Drawable artwork = createRoundedBitmap(data.getArtwork());
- albumView.setImageDrawable(artwork);
+ boolean hasArtwork = data.getArtwork() != null;
+ if (hasArtwork) {
+ Drawable artwork = createRoundedBitmap(data.getArtwork());
+ albumView.setImageDrawable(artwork);
+ }
+ setVisibleAndAlpha(collapsedSet, R.id.album_art, hasArtwork);
+ setVisibleAndAlpha(expandedSet, R.id.album_art, hasArtwork);
// App icon
ImageView appIcon = mViewHolder.getAppIcon();
- appIcon.setImageDrawable(data.getAppIcon());
+ if (data.getAppIcon() != null) {
+ appIcon.setImageDrawable(data.getAppIcon());
+ } else {
+ Drawable iconDrawable = mContext.getDrawable(R.drawable.ic_music_note);
+ appIcon.setImageDrawable(iconDrawable);
+ }
// Song name
TextView titleText = mViewHolder.getTitleText();
@@ -294,7 +244,7 @@ public class MediaControlPanel {
final Intent intent = new Intent()
.setAction(MediaOutputSliceConstants.ACTION_MEDIA_OUTPUT)
.putExtra(MediaOutputSliceConstants.EXTRA_PACKAGE_NAME,
- mController.getPackageName())
+ data.getPackageName())
.putExtra(MediaOutputSliceConstants.KEY_MEDIA_SESSION_TOKEN, mToken);
mActivityStarter.startActivity(intent, false, true /* dismissShade */,
Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
@@ -350,15 +300,11 @@ public class MediaControlPanel {
MediaAction mediaAction = actionIcons.get(i);
button.setImageDrawable(mediaAction.getDrawable());
button.setContentDescription(mediaAction.getContentDescription());
- PendingIntent actionIntent = mediaAction.getIntent();
+ Runnable action = mediaAction.getAction();
button.setOnClickListener(v -> {
- if (actionIntent != null) {
- try {
- actionIntent.send();
- } catch (PendingIntent.CanceledException e) {
- e.printStackTrace();
- }
+ if (action != null) {
+ action.run();
}
});
boolean visibleInCompat = actionsWhenCollapsed.contains(i);
@@ -444,14 +390,6 @@ public class MediaControlPanel {
}
/**
- * Return the original notification's key
- * @return The notification key
- */
- public String getKey() {
- return mKey;
- }
-
- /**
* Check whether this player has an attached media session.
* @return whether there is a controller with a current media session.
*/
@@ -485,150 +423,8 @@ public class MediaControlPanel {
return (state.getState() == PlaybackState.STATE_PLAYING);
}
- /**
- * Puts controls into a resumption state if possible, or calls removePlayer if no component was
- * found that could resume playback
- */
- public void clearControls() {
- Log.d(TAG, "clearControls to resumption state package=" + getMediaPlayerPackage());
- if (mServiceComponent == null) {
- // If we don't have a way to resume, just remove the player altogether
- Log.d(TAG, "Removing unresumable controls");
- removePlayer();
- return;
- }
- resetButtons();
- }
-
- /**
- * Hide the media buttons and show only a restart button
- */
- protected void resetButtons() {
- if (mViewHolder == null) {
- return;
- }
- // Hide all the old buttons
-
- ConstraintSet expandedSet = mMediaViewController.getExpandedLayout();
- ConstraintSet collapsedSet = mMediaViewController.getCollapsedLayout();
- for (int i = 1; i < ACTION_IDS.length; i++) {
- setVisibleAndAlpha(expandedSet, ACTION_IDS[i], false /*visible */);
- setVisibleAndAlpha(collapsedSet, ACTION_IDS[i], false /*visible */);
- }
-
- // Add a restart button
- ImageButton btn = mViewHolder.getAction0();
- btn.setOnClickListener(v -> {
- Log.d(TAG, "Attempting to restart session");
- if (mQSMediaBrowser != null) {
- mQSMediaBrowser.disconnect();
- }
- mQSMediaBrowser = new QSMediaBrowser(mContext, new QSMediaBrowser.Callback(){
- @Override
- public void onConnected() {
- Log.d(TAG, "Successfully restarted");
- }
- @Override
- public void onError() {
- Log.e(TAG, "Error restarting");
- mQSMediaBrowser.disconnect();
- mQSMediaBrowser = null;
- }
- }, mServiceComponent);
- mQSMediaBrowser.restart();
- });
- btn.setImageDrawable(mContext.getResources().getDrawable(R.drawable.lb_ic_play));
- setVisibleAndAlpha(expandedSet, ACTION_IDS[0], true /*visible */);
- setVisibleAndAlpha(collapsedSet, ACTION_IDS[0], true /*visible */);
-
- mSeekBarViewModel.clearController();
- // TODO: fix guts
- // View guts = mMediaNotifView.findViewById(R.id.media_guts);
- View options = mViewHolder.getOptions();
-
- mViewHolder.getPlayer().setOnLongClickListener(v -> {
- // Replace player view with close/cancel view
-// guts.setVisibility(View.GONE);
- options.setVisibility(View.VISIBLE);
- return true; // consumed click
- });
- mMediaViewController.refreshState();
- }
-
private void setVisibleAndAlpha(ConstraintSet set, int actionId, boolean visible) {
set.setVisibility(actionId, visible? ConstraintSet.VISIBLE : ConstraintSet.GONE);
set.setAlpha(actionId, visible ? 1.0f : 0.0f);
}
-
- /**
- * Verify that we can connect to the given component with a MediaBrowser, and if so, add that
- * component to the list of resumption components
- */
- private void tryUpdateResumptionList(ComponentName componentName) {
- Log.d(TAG, "Testing if we can connect to " + componentName);
- if (mQSMediaBrowser != null) {
- mQSMediaBrowser.disconnect();
- }
- mQSMediaBrowser = new QSMediaBrowser(mContext,
- new QSMediaBrowser.Callback() {
- @Override
- public void onConnected() {
- Log.d(TAG, "yes we can resume with " + componentName);
- mServiceComponent = componentName;
- updateResumptionList(componentName);
- mQSMediaBrowser.disconnect();
- mQSMediaBrowser = null;
- }
-
- @Override
- public void onError() {
- Log.d(TAG, "Cannot resume with " + componentName);
- mServiceComponent = null;
- if (!hasMediaSession()) {
- // If it's not active and we can't resume, remove
- removePlayer();
- }
- mQSMediaBrowser.disconnect();
- mQSMediaBrowser = null;
- }
- },
- componentName);
- mQSMediaBrowser.testConnection();
- }
-
- /**
- * Add the component to the saved list of media browser services, checking for duplicates and
- * removing older components that exceed the maximum limit
- * @param componentName
- */
- private synchronized void updateResumptionList(ComponentName componentName) {
- // Add to front of saved list
- if (mSharedPrefs == null) {
- mSharedPrefs = mContext.getSharedPreferences(MEDIA_PREFERENCES, 0);
- }
- String componentString = componentName.flattenToString();
- String listString = mSharedPrefs.getString(MEDIA_PREFERENCE_KEY, null);
- if (listString == null) {
- listString = componentString;
- } else {
- String[] components = listString.split(QSMediaBrowser.DELIMITER);
- StringBuilder updated = new StringBuilder(componentString);
- int nBrowsers = 1;
- for (int i = 0; i < components.length
- && nBrowsers < QSMediaBrowser.MAX_RESUMPTION_CONTROLS; i++) {
- if (componentString.equals(components[i])) {
- continue;
- }
- updated.append(QSMediaBrowser.DELIMITER).append(components[i]);
- nBrowsers++;
- }
- listString = updated.toString();
- }
- mSharedPrefs.edit().putString(MEDIA_PREFERENCE_KEY, listString).apply();
- }
-
- /**
- * Called when a player can't be resumed to give it an opportunity to hide or remove itself
- */
- protected void removePlayer() { }
}
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaData.kt b/packages/SystemUI/src/com/android/systemui/media/MediaData.kt
index a94f6a87d58a..5d28178a3b1b 100644
--- a/packages/SystemUI/src/com/android/systemui/media/MediaData.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaData.kt
@@ -32,17 +32,19 @@ data class MediaData(
val artwork: Icon?,
val actions: List<MediaAction>,
val actionsToShowInCompact: List<Int>,
- val packageName: String?,
+ val packageName: String,
val token: MediaSession.Token?,
val clickIntent: PendingIntent?,
val device: MediaDeviceData?,
- val notificationKey: String = "INVALID"
+ var resumeAction: Runnable?,
+ val notificationKey: String = "INVALID",
+ var hasCheckedForResume: Boolean = false
)
/** State of a media action. */
data class MediaAction(
val drawable: Drawable?,
- val intent: PendingIntent?,
+ val action: Runnable?,
val contentDescription: CharSequence?
)
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaDataCombineLatest.kt b/packages/SystemUI/src/com/android/systemui/media/MediaDataCombineLatest.kt
index cce9838bb8e2..11cbc482459a 100644
--- a/packages/SystemUI/src/com/android/systemui/media/MediaDataCombineLatest.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaDataCombineLatest.kt
@@ -32,9 +32,15 @@ class MediaDataCombineLatest @Inject constructor(
init {
dataSource.addListener(object : MediaDataManager.Listener {
- override fun onMediaDataLoaded(key: String, data: MediaData) {
- entries[key] = data to entries[key]?.second
- update(key)
+ override fun onMediaDataLoaded(key: String, oldKey: String?, data: MediaData) {
+ if (oldKey != null && !oldKey.equals(key)) {
+ val s = entries[oldKey]?.second
+ entries[key] = data to entries[oldKey]?.second
+ entries.remove(oldKey)
+ } else {
+ entries[key] = data to entries[key]?.second
+ }
+ update(key, oldKey)
}
override fun onMediaDataRemoved(key: String) {
remove(key)
@@ -43,7 +49,7 @@ class MediaDataCombineLatest @Inject constructor(
deviceSource.addListener(object : MediaDeviceManager.Listener {
override fun onMediaDeviceChanged(key: String, data: MediaDeviceData?) {
entries[key] = entries[key]?.first to data
- update(key)
+ update(key, key)
}
override fun onKeyRemoved(key: String) {
remove(key)
@@ -61,19 +67,21 @@ class MediaDataCombineLatest @Inject constructor(
*/
fun removeListener(listener: MediaDataManager.Listener) = listeners.remove(listener)
- private fun update(key: String) {
+ private fun update(key: String, oldKey: String?) {
val (entry, device) = entries[key] ?: null to null
if (entry != null && device != null) {
val data = entry.copy(device = device)
- listeners.forEach {
- it.onMediaDataLoaded(key, data)
+ val listenersCopy = listeners.toSet()
+ listenersCopy.forEach {
+ it.onMediaDataLoaded(key, oldKey, data)
}
}
}
private fun remove(key: String) {
entries.remove(key)?.let {
- listeners.forEach {
+ val listenersCopy = listeners.toSet()
+ listenersCopy.forEach {
it.onMediaDataRemoved(key)
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaDataManager.kt b/packages/SystemUI/src/com/android/systemui/media/MediaDataManager.kt
index d94985703083..094c5bef3c18 100644
--- a/packages/SystemUI/src/com/android/systemui/media/MediaDataManager.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaDataManager.kt
@@ -17,6 +17,7 @@
package com.android.systemui.media
import android.app.Notification
+import android.app.PendingIntent
import android.content.ContentResolver
import android.content.Context
import android.graphics.Bitmap
@@ -25,6 +26,7 @@ import android.graphics.Color
import android.graphics.ImageDecoder
import android.graphics.drawable.Drawable
import android.graphics.drawable.Icon
+import android.media.MediaDescription
import android.media.MediaMetadata
import android.media.session.MediaSession
import android.net.Uri
@@ -32,8 +34,10 @@ import android.service.notification.StatusBarNotification
import android.text.TextUtils
import android.util.Log
import com.android.internal.graphics.ColorUtils
+import com.android.systemui.R
import com.android.systemui.dagger.qualifiers.Background
import com.android.systemui.dagger.qualifiers.Main
+import com.android.systemui.statusbar.NotificationMediaManager
import com.android.systemui.statusbar.notification.MediaNotificationProcessor
import com.android.systemui.statusbar.notification.NotificationEntryManager
import com.android.systemui.statusbar.notification.NotificationEntryManager.UNDEFINED_DISMISS_REASON
@@ -58,7 +62,7 @@ private const val LUMINOSITY_THRESHOLD = 0.05f
private const val SATURATION_MULTIPLIER = 0.8f
private val LOADING = MediaData(false, 0, null, null, null, null, null,
- emptyList(), emptyList(), null, null, null, null)
+ emptyList(), emptyList(), "INVALID", null, null, null, null)
fun isMediaNotification(sbn: StatusBarNotification): Boolean {
if (!sbn.notification.hasMediaSession()) {
@@ -81,34 +85,92 @@ class MediaDataManager @Inject constructor(
private val mediaControllerFactory: MediaControllerFactory,
private val mediaTimeoutListener: MediaTimeoutListener,
private val notificationEntryManager: NotificationEntryManager,
+ private val mediaResumeListener: MediaResumeListener,
@Background private val backgroundExecutor: Executor,
@Main private val foregroundExecutor: Executor
) {
private val listeners: MutableSet<Listener> = mutableSetOf()
private val mediaEntries: LinkedHashMap<String, MediaData> = LinkedHashMap()
+ private val useMediaResumption: Boolean = Utils.useMediaResumption(context)
init {
mediaTimeoutListener.timeoutCallback = { token: String, timedOut: Boolean ->
setTimedOut(token, timedOut) }
addListener(mediaTimeoutListener)
+
+ if (useMediaResumption) {
+ mediaResumeListener.addTrackToResumeCallback = { desc: MediaDescription,
+ resumeAction: Runnable, token: MediaSession.Token, appName: String,
+ appIntent: PendingIntent, packageName: String ->
+ addResumptionControls(desc, resumeAction, token, appName, appIntent, packageName)
+ }
+ mediaResumeListener.resumeComponentFoundCallback = { key: String, action: Runnable? ->
+ mediaEntries.get(key)?.resumeAction = action
+ mediaEntries.get(key)?.hasCheckedForResume = true
+ }
+ addListener(mediaResumeListener)
+ }
}
fun onNotificationAdded(key: String, sbn: StatusBarNotification) {
if (Utils.useQsMediaPlayer(context) && isMediaNotification(sbn)) {
Assert.isMainThread()
- if (!mediaEntries.containsKey(key)) {
- mediaEntries.put(key, LOADING)
+ val oldKey = findExistingEntry(key, sbn.packageName)
+ if (oldKey == null) {
+ val temp = LOADING.copy(packageName = sbn.packageName)
+ mediaEntries.put(key, temp)
+ } else if (oldKey != key) {
+ // Move to new key
+ val oldData = mediaEntries.remove(oldKey)!!
+ mediaEntries.put(key, oldData)
}
- loadMediaData(key, sbn)
+ loadMediaData(key, sbn, oldKey)
} else {
onNotificationRemoved(key)
}
}
- private fun loadMediaData(key: String, sbn: StatusBarNotification) {
+ private fun addResumptionControls(
+ desc: MediaDescription,
+ action: Runnable,
+ token: MediaSession.Token,
+ appName: String,
+ appIntent: PendingIntent,
+ packageName: String
+ ) {
+ // Resume controls don't have a notification key, so store by package name instead
+ if (!mediaEntries.containsKey(packageName)) {
+ val resumeData = LOADING.copy(packageName = packageName, resumeAction = action)
+ mediaEntries.put(packageName, resumeData)
+ }
backgroundExecutor.execute {
- loadMediaDataInBg(key, sbn)
+ loadMediaDataInBg(desc, action, token, appName, appIntent, packageName)
+ }
+ }
+
+ /**
+ * Check if there is an existing entry that matches the key or package name.
+ * Returns the key that matches, or null if not found.
+ */
+ private fun findExistingEntry(key: String, packageName: String): String? {
+ if (mediaEntries.containsKey(key)) {
+ return key
+ }
+ // Check if we already had a resume player
+ if (mediaEntries.containsKey(packageName)) {
+ return packageName
+ }
+ return null
+ }
+
+ private fun loadMediaData(
+ key: String,
+ sbn: StatusBarNotification,
+ oldKey: String?
+ ) {
+ backgroundExecutor.execute {
+ loadMediaDataInBg(key, sbn, oldKey)
}
}
@@ -132,7 +194,50 @@ class MediaDataManager @Inject constructor(
}
}
- private fun loadMediaDataInBg(key: String, sbn: StatusBarNotification) {
+ private fun loadMediaDataInBg(
+ desc: MediaDescription,
+ resumeAction: Runnable,
+ token: MediaSession.Token,
+ appName: String,
+ appIntent: PendingIntent,
+ packageName: String
+ ) {
+ if (resumeAction == null) {
+ Log.e(TAG, "Resume action cannot be null")
+ return
+ }
+
+ if (TextUtils.isEmpty(desc.title)) {
+ Log.e(TAG, "Description incomplete")
+ return
+ }
+
+ Log.d(TAG, "adding track from browser: $desc")
+
+ // Album art
+ var artworkBitmap = desc.iconBitmap
+ if (artworkBitmap == null && desc.iconUri != null) {
+ artworkBitmap = loadBitmapFromUri(desc.iconUri!!)
+ }
+ val artworkIcon = if (artworkBitmap != null) {
+ Icon.createWithBitmap(artworkBitmap)
+ } else {
+ null
+ }
+
+ val mediaAction = getResumeMediaAction(resumeAction)
+ foregroundExecutor.execute {
+ onMediaDataLoaded(packageName, null, MediaData(true, Color.DKGRAY, appName,
+ null, desc.subtitle, desc.title, artworkIcon, listOf(mediaAction), listOf(0),
+ packageName, token, appIntent, null, resumeAction, packageName))
+ }
+ }
+
+ private fun loadMediaDataInBg(
+ key: String,
+ sbn: StatusBarNotification,
+ oldKey: String?
+ ) {
val token = sbn.notification.extras.getParcelable(Notification.EXTRA_MEDIA_SESSION)
as MediaSession.Token?
val metadata = mediaControllerFactory.create(token).metadata
@@ -234,16 +339,23 @@ class MediaDataManager @Inject constructor(
}
val mediaAction = MediaAction(
action.getIcon().loadDrawable(packageContext),
- action.actionIntent,
+ Runnable {
+ try {
+ action.actionIntent.send()
+ } catch (e: PendingIntent.CanceledException) {
+ Log.d(TAG, "Intent canceled", e)
+ }
+ },
action.title)
actionIcons.add(mediaAction)
}
}
+ val resumeAction: Runnable? = mediaEntries.get(key)?.resumeAction
foregroundExecutor.execute {
- onMediaDataLoaded(key, MediaData(true, bgColor, app, smallIconDrawable, artist, song,
- artWorkIcon, actionIcons, actionsToShowCollapsed, sbn.packageName, token,
- notif.contentIntent, null, key))
+ onMediaDataLoaded(key, oldKey, MediaData(true, bgColor, app, smallIconDrawable, artist,
+ song, artWorkIcon, actionIcons, actionsToShowCollapsed, sbn.packageName, token,
+ notif.contentIntent, null, resumeAction, key))
}
}
@@ -257,7 +369,7 @@ class MediaDataManager @Inject constructor(
val albumArt = loadBitmapFromUri(Uri.parse(uriString))
if (albumArt != null) {
Log.d(TAG, "loaded art from $uri")
- break
+ return albumArt
}
}
}
@@ -283,27 +395,52 @@ class MediaDataManager @Inject constructor(
val source = ImageDecoder.createSource(context.getContentResolver(), uri)
return try {
- ImageDecoder.decodeBitmap(source)
+ ImageDecoder.decodeBitmap(source) {
+ decoder, info, source -> decoder.isMutableRequired = true
+ }
} catch (e: IOException) {
e.printStackTrace()
null
}
}
- fun onMediaDataLoaded(key: String, data: MediaData) {
+ private fun getResumeMediaAction(action: Runnable): MediaAction {
+ return MediaAction(
+ context.getDrawable(R.drawable.lb_ic_play),
+ action,
+ context.getString(R.string.controls_media_resume)
+ )
+ }
+
+ fun onMediaDataLoaded(key: String, oldKey: String?, data: MediaData) {
Assert.isMainThread()
if (mediaEntries.containsKey(key)) {
// Otherwise this was removed already
mediaEntries.put(key, data)
val listenersCopy = listeners.toSet()
listenersCopy.forEach {
- it.onMediaDataLoaded(key, data)
+ it.onMediaDataLoaded(key, oldKey, data)
}
}
}
fun onNotificationRemoved(key: String) {
Assert.isMainThread()
+ if (useMediaResumption && mediaEntries.get(key)?.resumeAction != null) {
+ Log.d(TAG, "Not removing $key because resumable")
+ // Move to resume key aka package name
+ val data = mediaEntries.remove(key)!!
+ val resumeAction = getResumeMediaAction(data.resumeAction!!)
+ val updated = data.copy(token = null, actions = listOf(resumeAction),
+ actionsToShowInCompact = listOf(0))
+ mediaEntries.put(data.packageName, updated)
+ // Notify listeners of "new" controls
+ val listenersCopy = listeners.toSet()
+ listenersCopy.forEach {
+ it.onMediaDataLoaded(data.packageName, key, updated)
+ }
+ return
+ }
val removed = mediaEntries.remove(key)
if (removed != null) {
val listenersCopy = listeners.toSet()
@@ -316,19 +453,32 @@ class MediaDataManager @Inject constructor(
/**
* Are there any media notifications active?
*/
- fun hasActiveMedia() = mediaEntries.isNotEmpty()
+ fun hasActiveMedia() = mediaEntries.any({ isActive(it.value) })
- fun hasAnyMedia(): Boolean {
- // TODO: implement this when we implemented resumption
- return hasActiveMedia()
+ fun isActive(data: MediaData): Boolean {
+ if (data.token == null) {
+ return false
+ }
+ val controller = mediaControllerFactory.create(data.token)
+ val state = controller?.playbackState?.state
+ return state != null && NotificationMediaManager.isActiveState(state)
}
+ /**
+ * Are there any media entries, including resume controls?
+ */
+ fun hasAnyMedia() = mediaEntries.isNotEmpty()
+
interface Listener {
/**
- * Called whenever there's new MediaData Loaded for the consumption in views
+ * Called whenever there's new MediaData Loaded for the consumption in views.
+ *
+ * oldKey is provided to check whether the view has changed keys, which can happen when a
+ * player has gone from resume state (key is package name) to active state (key is
+ * notification key) or vice versa.
*/
- fun onMediaDataLoaded(key: String, data: MediaData) {}
+ fun onMediaDataLoaded(key: String, oldKey: String?, data: MediaData) {}
/**
* Called whenever a previously existing Media notification was removed
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaDeviceManager.kt b/packages/SystemUI/src/com/android/systemui/media/MediaDeviceManager.kt
index 552fea63a278..de0af16bc2fa 100644
--- a/packages/SystemUI/src/com/android/systemui/media/MediaDeviceManager.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaDeviceManager.kt
@@ -16,11 +16,8 @@
package com.android.systemui.media
-import android.app.Notification
import android.content.Context
-import android.service.notification.StatusBarNotification
import android.media.MediaRouter2Manager
-import android.media.session.MediaSession
import android.media.session.MediaController
import com.android.settingslib.media.LocalMediaManager
import com.android.settingslib.media.MediaDevice
@@ -37,12 +34,16 @@ class MediaDeviceManager @Inject constructor(
private val context: Context,
private val localMediaManagerFactory: LocalMediaManagerFactory,
private val mr2manager: MediaRouter2Manager,
- private val featureFlag: MediaFeatureFlag,
- @Main private val fgExecutor: Executor
-) {
+ @Main private val fgExecutor: Executor,
+ private val mediaDataManager: MediaDataManager
+) : MediaDataManager.Listener {
private val listeners: MutableSet<Listener> = mutableSetOf()
private val entries: MutableMap<String, Token> = mutableMapOf()
+ init {
+ mediaDataManager.addListener(this)
+ }
+
/**
* Add a listener for changes to the media route (ie. device).
*/
@@ -53,23 +54,24 @@ class MediaDeviceManager @Inject constructor(
*/
fun removeListener(listener: Listener) = listeners.remove(listener)
- fun onNotificationAdded(key: String, sbn: StatusBarNotification) {
- if (featureFlag.enabled && isMediaNotification(sbn)) {
- var tok = entries[key]
- if (tok == null) {
- val token = sbn.notification.extras.getParcelable(Notification.EXTRA_MEDIA_SESSION)
- as MediaSession.Token?
- val controller = MediaController(context, token)
- tok = Token(key, controller, localMediaManagerFactory.create(sbn.packageName))
- entries[key] = tok
- tok.start()
+ override fun onMediaDataLoaded(key: String, oldKey: String?, data: MediaData) {
+ if (oldKey != null && oldKey != key) {
+ val oldEntry = entries.remove(oldKey)
+ oldEntry?.stop()
+ }
+ var entry = entries[key]
+ if (entry == null || entry?.token != data.token) {
+ entry?.stop()
+ val controller = data.token?.let {
+ MediaController(context, it)
}
- } else {
- onNotificationRemoved(key)
+ entry = Token(key, controller, localMediaManagerFactory.create(data.packageName))
+ entries[key] = entry
+ entry.start()
}
}
- fun onNotificationRemoved(key: String) {
+ override fun onMediaDataRemoved(key: String) {
val token = entries.remove(key)
token?.stop()
token?.let {
@@ -96,9 +98,11 @@ class MediaDeviceManager @Inject constructor(
private inner class Token(
val key: String,
- val controller: MediaController,
+ val controller: MediaController?,
val localMediaManager: LocalMediaManager
) : LocalMediaManager.DeviceCallback {
+ val token
+ get() = controller?.sessionToken
private var started = false
private var current: MediaDevice? = null
set(value) {
@@ -128,10 +132,14 @@ class MediaDeviceManager @Inject constructor(
}
private fun updateCurrent() {
val device = localMediaManager.getCurrentConnectedDevice()
- val route = mr2manager.getRoutingSessionForMediaController(controller)
- // If we get a null route, then don't trust the device. Just set to null to disable the
- // output switcher chip.
- current = if (route != null) device else null
+ controller?.let {
+ val route = mr2manager.getRoutingSessionForMediaController(it)
+ // If we get a null route, then don't trust the device. Just set to null to disable the
+ // output switcher chip.
+ current = if (route != null) device else null
+ } ?: run {
+ current = device
+ }
}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaHost.kt b/packages/SystemUI/src/com/android/systemui/media/MediaHost.kt
index e904e935b0e0..2bd8c0cbeab2 100644
--- a/packages/SystemUI/src/com/android/systemui/media/MediaHost.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaHost.kt
@@ -50,7 +50,7 @@ class MediaHost @Inject constructor(
}
private val listener = object : MediaDataManager.Listener {
- override fun onMediaDataLoaded(key: String, data: MediaData) {
+ override fun onMediaDataLoaded(key: String, oldKey: String?, data: MediaData) {
updateViewVisibility()
}
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaResumeListener.kt b/packages/SystemUI/src/com/android/systemui/media/MediaResumeListener.kt
new file mode 100644
index 000000000000..6bbe0d1651dd
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaResumeListener.kt
@@ -0,0 +1,252 @@
+/*
+ * 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
+
+import android.app.PendingIntent
+import android.content.BroadcastReceiver
+import android.content.ComponentName
+import android.content.Context
+import android.content.Intent
+import android.content.IntentFilter
+import android.content.pm.PackageManager
+import android.media.MediaDescription
+import android.media.session.MediaController
+import android.media.session.MediaSession
+import android.os.UserHandle
+import android.service.media.MediaBrowserService
+import android.util.Log
+import com.android.systemui.broadcast.BroadcastDispatcher
+import com.android.systemui.dagger.qualifiers.Background
+import com.android.systemui.util.Utils
+import java.util.concurrent.ConcurrentLinkedQueue
+import java.util.concurrent.Executor
+import javax.inject.Inject
+import javax.inject.Singleton
+
+private const val TAG = "MediaResumeListener"
+
+private const val MEDIA_PREFERENCES = "media_control_prefs"
+private const val MEDIA_PREFERENCE_KEY = "browser_components"
+
+@Singleton
+class MediaResumeListener @Inject constructor(
+ private val context: Context,
+ private val broadcastDispatcher: BroadcastDispatcher,
+ @Background private val backgroundExecutor: Executor
+) : MediaDataManager.Listener {
+
+ private val useMediaResumption: Boolean = Utils.useMediaResumption(context)
+ private val resumeComponents: ConcurrentLinkedQueue<ComponentName> = ConcurrentLinkedQueue()
+
+ lateinit var addTrackToResumeCallback: (
+ MediaDescription,
+ Runnable,
+ MediaSession.Token,
+ String,
+ PendingIntent,
+ String
+ ) -> Unit
+ lateinit var resumeComponentFoundCallback: (String, Runnable?) -> Unit
+
+ private var mediaBrowser: ResumeMediaBrowser? = null
+
+ private val unlockReceiver = object : BroadcastReceiver() {
+ override fun onReceive(context: Context, intent: Intent) {
+ if (Intent.ACTION_USER_UNLOCKED == intent.action) {
+ loadMediaResumptionControls()
+ }
+ }
+ }
+
+ private val mediaBrowserCallback = object : ResumeMediaBrowser.Callback() {
+ override fun addTrack(
+ desc: MediaDescription,
+ component: ComponentName,
+ browser: ResumeMediaBrowser
+ ) {
+ val token = browser.token
+ val appIntent = browser.appIntent
+ val pm = context.getPackageManager()
+ var appName: CharSequence = component.packageName
+ val resumeAction = getResumeAction(component)
+ try {
+ appName = pm.getApplicationLabel(
+ pm.getApplicationInfo(component.packageName, 0))
+ } catch (e: PackageManager.NameNotFoundException) {
+ Log.e(TAG, "Error getting package information", e)
+ }
+
+ Log.d(TAG, "Adding resume controls $desc")
+ addTrackToResumeCallback(desc, resumeAction, token, appName.toString(), appIntent,
+ component.packageName)
+ }
+ }
+
+ init {
+ if (useMediaResumption) {
+ val unlockFilter = IntentFilter()
+ unlockFilter.addAction(Intent.ACTION_USER_UNLOCKED)
+ broadcastDispatcher.registerReceiver(unlockReceiver, unlockFilter, null, UserHandle.ALL)
+ loadSavedComponents()
+ }
+ }
+
+ private fun loadSavedComponents() {
+ val userContext = context.createContextAsUser(context.getUser(), 0)
+ val prefs = userContext.getSharedPreferences(MEDIA_PREFERENCES, Context.MODE_PRIVATE)
+ val listString = prefs.getString(MEDIA_PREFERENCE_KEY, null)
+ val components = listString?.split(ResumeMediaBrowser.DELIMITER.toRegex())
+ ?.dropLastWhile { it.isEmpty() }
+ components?.forEach {
+ val info = it.split("/")
+ val packageName = info[0]
+ val className = info[1]
+ val component = ComponentName(packageName, className)
+ resumeComponents.add(component)
+ }
+ Log.d(TAG, "loaded resume components ${resumeComponents.toArray().contentToString()}")
+ }
+
+ /**
+ * Load controls for resuming media, if available
+ */
+ private fun loadMediaResumptionControls() {
+ if (!useMediaResumption) {
+ return
+ }
+
+ resumeComponents.forEach {
+ val browser = ResumeMediaBrowser(context, mediaBrowserCallback, it)
+ browser.findRecentMedia()
+ }
+ broadcastDispatcher.unregisterReceiver(unlockReceiver) // only need to load once
+ }
+
+ override fun onMediaDataLoaded(key: String, oldKey: String?, data: MediaData) {
+ if (useMediaResumption) {
+ // If this had been started from a resume state, disconnect now that it's live
+ mediaBrowser?.disconnect()
+ // If we don't have a resume action, check if we haven't already
+ if (data.resumeAction == null && !data.hasCheckedForResume) {
+ // TODO also check for a media button receiver intended for restarting (b/154127084)
+ Log.d(TAG, "Checking for service component for " + data.packageName)
+ val pm = context.packageManager
+ val serviceIntent = Intent(MediaBrowserService.SERVICE_INTERFACE)
+ val resumeInfo = pm.queryIntentServices(serviceIntent, 0)
+
+ val inf = resumeInfo?.filter {
+ it.serviceInfo.packageName == data.packageName
+ }
+ if (inf != null && inf.size > 0) {
+ backgroundExecutor.execute {
+ tryUpdateResumptionList(key, inf!!.get(0).componentInfo.componentName)
+ }
+ } else {
+ // No service found
+ resumeComponentFoundCallback(key, null)
+ }
+ }
+ }
+ }
+
+ /**
+ * Verify that we can connect to the given component with a MediaBrowser, and if so, add that
+ * component to the list of resumption components
+ */
+ private fun tryUpdateResumptionList(key: String, componentName: ComponentName) {
+ Log.d(TAG, "Testing if we can connect to $componentName")
+ mediaBrowser?.disconnect()
+ mediaBrowser = ResumeMediaBrowser(context,
+ object : ResumeMediaBrowser.Callback() {
+ override fun onConnected() {
+ Log.d(TAG, "yes we can resume with $componentName")
+ resumeComponentFoundCallback(key, getResumeAction(componentName))
+ updateResumptionList(componentName)
+ mediaBrowser?.disconnect()
+ mediaBrowser = null
+ }
+
+ override fun onError() {
+ Log.e(TAG, "Cannot resume with $componentName")
+ resumeComponentFoundCallback(key, null)
+ mediaBrowser?.disconnect()
+ mediaBrowser = null
+ }
+ },
+ componentName)
+ mediaBrowser?.testConnection()
+ }
+
+ /**
+ * Add the component to the saved list of media browser services, checking for duplicates and
+ * removing older components that exceed the maximum limit
+ * @param componentName
+ */
+ private fun updateResumptionList(componentName: ComponentName) {
+ // Remove if exists
+ resumeComponents.remove(componentName)
+ // Insert at front of queue
+ resumeComponents.add(componentName)
+ // Remove old components if over the limit
+ if (resumeComponents.size > ResumeMediaBrowser.MAX_RESUMPTION_CONTROLS) {
+ resumeComponents.remove()
+ }
+
+ // Save changes
+ val sb = StringBuilder()
+ resumeComponents.forEach {
+ sb.append(it.flattenToString())
+ sb.append(ResumeMediaBrowser.DELIMITER)
+ }
+ val userContext = context.createContextAsUser(context.getUser(), 0)
+ val prefs = userContext.getSharedPreferences(MEDIA_PREFERENCES, Context.MODE_PRIVATE)
+ prefs.edit().putString(MEDIA_PREFERENCE_KEY, sb.toString()).apply()
+ }
+
+ /**
+ * Get a runnable which will resume media playback
+ */
+ private fun getResumeAction(componentName: ComponentName): Runnable {
+ return Runnable {
+ mediaBrowser?.disconnect()
+ mediaBrowser = ResumeMediaBrowser(context,
+ object : ResumeMediaBrowser.Callback() {
+ override fun onConnected() {
+ if (mediaBrowser?.token == null) {
+ Log.e(TAG, "Error after connect")
+ mediaBrowser?.disconnect()
+ mediaBrowser = null
+ return
+ }
+ Log.d(TAG, "Connected for restart $componentName")
+ val controller = MediaController(context, mediaBrowser!!.token)
+ val controls = controller.transportControls
+ controls.prepare()
+ controls.play()
+ }
+
+ override fun onError() {
+ Log.e(TAG, "Resume failed for $componentName")
+ mediaBrowser?.disconnect()
+ mediaBrowser = null
+ }
+ },
+ componentName)
+ mediaBrowser?.restart()
+ }
+ }
+} \ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaTimeoutListener.kt b/packages/SystemUI/src/com/android/systemui/media/MediaTimeoutListener.kt
index 92a1ab1b1871..3c3f4a977ee7 100644
--- a/packages/SystemUI/src/com/android/systemui/media/MediaTimeoutListener.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaTimeoutListener.kt
@@ -45,7 +45,7 @@ class MediaTimeoutListener @Inject constructor(
lateinit var timeoutCallback: (String, Boolean) -> Unit
- override fun onMediaDataLoaded(key: String, data: MediaData) {
+ override fun onMediaDataLoaded(key: String, oldKey: String?, data: MediaData) {
if (mediaListeners.containsKey(key)) {
return
}
@@ -67,27 +67,35 @@ class MediaTimeoutListener @Inject constructor(
var timedOut = false
- private val mediaController = mediaControllerFactory.create(data.token)
+ // Resume controls may have null token
+ private val mediaController = if (data.token != null) {
+ mediaControllerFactory.create(data.token)
+ } else {
+ null
+ }
private var cancellation: Runnable? = null
init {
- mediaController.registerCallback(this)
+ mediaController?.registerCallback(this)
}
fun destroy() {
- mediaController.unregisterCallback(this)
+ mediaController?.unregisterCallback(this)
}
override fun onPlaybackStateChanged(state: PlaybackState?) {
if (DEBUG) {
Log.v(TAG, "onPlaybackStateChanged: $state")
}
- expireMediaTimeout(key, "playback state ativity - $state, $key")
if (state == null || !isPlayingState(state.state)) {
if (DEBUG) {
Log.v(TAG, "schedule timeout for $key")
}
+ if (cancellation != null) {
+ if (DEBUG) Log.d(TAG, "cancellation already exists, continuing.")
+ return
+ }
expireMediaTimeout(key, "PLAYBACK STATE CHANGED - $state")
cancellation = mainExecutor.executeDelayed({
cancellation = null
@@ -98,6 +106,7 @@ class MediaTimeoutListener @Inject constructor(
timeoutCallback(key, timedOut)
}, PAUSED_MEDIA_TIMEOUT)
} else {
+ expireMediaTimeout(key, "playback started - $state, $key")
timedOut = false
timeoutCallback(key, timedOut)
}
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaViewManager.kt b/packages/SystemUI/src/com/android/systemui/media/MediaViewManager.kt
index 8ab30c75c7eb..9b9a6b4b13ab 100644
--- a/packages/SystemUI/src/com/android/systemui/media/MediaViewManager.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaViewManager.kt
@@ -11,16 +11,12 @@ import android.widget.HorizontalScrollView
import android.widget.LinearLayout
import androidx.core.view.GestureDetectorCompat
import com.android.systemui.R
-import com.android.systemui.dagger.qualifiers.Background
-import com.android.systemui.dagger.qualifiers.Main
-import com.android.systemui.plugins.ActivityStarter
import com.android.systemui.qs.PageIndicator
import com.android.systemui.statusbar.notification.VisualStabilityManager
import com.android.systemui.util.animation.UniqueObjectHostView
import com.android.systemui.util.animation.requiresRemeasuring
-import com.android.systemui.util.concurrency.DelayableExecutor
-import java.util.concurrent.Executor
import javax.inject.Inject
+import javax.inject.Provider
import javax.inject.Singleton
private const val FLING_SLOP = 1000000
@@ -32,10 +28,8 @@ private const val FLING_SLOP = 1000000
@Singleton
class MediaViewManager @Inject constructor(
private val context: Context,
- @Main private val foregroundExecutor: Executor,
- @Background private val backgroundExecutor: DelayableExecutor,
+ private val mediaControlPanelFactory: Provider<MediaControlPanel>,
private val visualStabilityManager: VisualStabilityManager,
- private val activityStarter: ActivityStarter,
private val mediaHostStatesManager: MediaHostStatesManager,
mediaManager: MediaDataCombineLatest
) {
@@ -147,8 +141,8 @@ class MediaViewManager @Inject constructor(
visualStabilityManager.addReorderingAllowedCallback(visualStabilityCallback,
true /* persistent */)
mediaManager.addListener(object : MediaDataManager.Listener {
- override fun onMediaDataLoaded(key: String, data: MediaData) {
- updateView(key, data)
+ override fun onMediaDataLoaded(key: String, oldKey: String?, data: MediaData) {
+ updateView(key, oldKey, data)
updatePlayerVisibilities()
mediaCarousel.requiresRemeasuring = true
}
@@ -259,11 +253,16 @@ class MediaViewManager @Inject constructor(
}
}
- private fun updateView(key: String, data: MediaData) {
+ private fun updateView(key: String, oldKey: String?, data: MediaData) {
+ // If the key was changed, update entry
+ val oldData = mediaPlayers[oldKey]
+ if (oldData != null) {
+ val oldData = mediaPlayers.remove(oldKey)
+ mediaPlayers.put(key, oldData!!)
+ }
var existingPlayer = mediaPlayers[key]
if (existingPlayer == null) {
- existingPlayer = MediaControlPanel(context, foregroundExecutor, backgroundExecutor,
- activityStarter, mediaHostStatesManager)
+ existingPlayer = mediaControlPanelFactory.get()
existingPlayer.attach(PlayerViewHolder.create(LayoutInflater.from(context),
mediaContent))
mediaPlayers[key] = existingPlayer
@@ -286,7 +285,7 @@ class MediaViewManager @Inject constructor(
needsReordering = true
}
}
- existingPlayer.bind(data)
+ existingPlayer?.bind(data)
updateMediaPaddings()
updatePageIndicator()
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSMediaBrowser.java b/packages/SystemUI/src/com/android/systemui/media/ResumeMediaBrowser.java
index a5b73dcbd289..1e9a30364607 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSMediaBrowser.java
+++ b/packages/SystemUI/src/com/android/systemui/media/ResumeMediaBrowser.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.systemui.qs;
+package com.android.systemui.media;
import android.app.PendingIntent;
import android.content.ComponentName;
@@ -27,14 +27,17 @@ import android.media.session.MediaController;
import android.media.session.MediaSession;
import android.os.Bundle;
import android.service.media.MediaBrowserService;
+import android.text.TextUtils;
import android.util.Log;
+import com.android.systemui.util.Utils;
+
import java.util.List;
/**
- * Media browser for managing resumption in QS media controls
+ * Media browser for managing resumption in media controls
*/
-public class QSMediaBrowser {
+public class ResumeMediaBrowser {
/** Maximum number of controls to show on boot */
public static final int MAX_RESUMPTION_CONTROLS = 5;
@@ -42,7 +45,8 @@ public class QSMediaBrowser {
/** Delimiter for saved component names */
public static final String DELIMITER = ":";
- private static final String TAG = "QSMediaBrowser";
+ private static final String TAG = "ResumeMediaBrowser";
+ private boolean mIsEnabled = false;
private final Context mContext;
private final Callback mCallback;
private MediaBrowser mMediaBrowser;
@@ -54,21 +58,25 @@ public class QSMediaBrowser {
* @param callback used to report media items found
* @param componentName Component name of the MediaBrowserService this browser will connect to
*/
- public QSMediaBrowser(Context context, Callback callback, ComponentName componentName) {
+ public ResumeMediaBrowser(Context context, Callback callback, ComponentName componentName) {
+ mIsEnabled = Utils.useMediaResumption(context);
mContext = context;
mCallback = callback;
mComponentName = componentName;
}
/**
- * Connects to the MediaBrowserService and looks for valid media. If a media item is returned
- * by the service, QSMediaBrowser.Callback#addTrack will be called with its MediaDescription.
- * QSMediaBrowser.Callback#onConnected and QSMediaBrowser.Callback#onError will also be called
- * when the initial connection is successful, or an error occurs. Note that it is possible for
- * the service to connect but for no playable tracks to be found later.
- * QSMediaBrowser#disconnect will be called automatically with this function.
+ * Connects to the MediaBrowserService and looks for valid media. If a media item is returned,
+ * ResumeMediaBrowser.Callback#addTrack will be called with the MediaDescription.
+ * ResumeMediaBrowser.Callback#onConnected and ResumeMediaBrowser.Callback#onError will also be
+ * called when the initial connection is successful, or an error occurs.
+ * Note that it is possible for the service to connect but for no playable tracks to be found.
+ * ResumeMediaBrowser#disconnect will be called automatically with this function.
*/
public void findRecentMedia() {
+ if (!mIsEnabled) {
+ return;
+ }
Log.d(TAG, "Connecting to " + mComponentName);
disconnect();
Bundle rootHints = new Bundle();
@@ -86,7 +94,7 @@ public class QSMediaBrowser {
public void onChildrenLoaded(String parentId,
List<MediaBrowser.MediaItem> children) {
if (children.size() == 0) {
- Log.e(TAG, "No children found for " + mComponentName);
+ Log.d(TAG, "No children found for " + mComponentName);
return;
}
// We ask apps to return a playable item as the first child when sending
@@ -94,23 +102,24 @@ public class QSMediaBrowser {
MediaBrowser.MediaItem child = children.get(0);
MediaDescription desc = child.getDescription();
if (child.isPlayable()) {
- mCallback.addTrack(desc, mMediaBrowser.getServiceComponent(), QSMediaBrowser.this);
+ mCallback.addTrack(desc, mMediaBrowser.getServiceComponent(),
+ ResumeMediaBrowser.this);
} else {
- Log.e(TAG, "Child found but not playable for " + mComponentName);
+ Log.d(TAG, "Child found but not playable for " + mComponentName);
}
disconnect();
}
@Override
public void onError(String parentId) {
- Log.e(TAG, "Subscribe error for " + mComponentName + ": " + parentId);
+ Log.d(TAG, "Subscribe error for " + mComponentName + ": " + parentId);
mCallback.onError();
disconnect();
}
@Override
public void onError(String parentId, Bundle options) {
- Log.e(TAG, "Subscribe error for " + mComponentName + ": " + parentId
+ Log.d(TAG, "Subscribe error for " + mComponentName + ": " + parentId
+ ", options: " + options);
mCallback.onError();
disconnect();
@@ -149,7 +158,7 @@ public class QSMediaBrowser {
*/
@Override
public void onConnectionFailed() {
- Log.e(TAG, "Connection failed for " + mComponentName);
+ Log.d(TAG, "Connection failed for " + mComponentName);
mCallback.onError();
disconnect();
}
@@ -167,11 +176,15 @@ public class QSMediaBrowser {
}
/**
- * Connects to the MediaBrowserService and starts playback. QSMediaBrowser.Callback#onError or
- * QSMediaBrowser.Callback#onConnected will be called depending on whether it was successful.
- * QSMediaBrowser#disconnect should be called after this to ensure the connection is closed.
+ * Connects to the MediaBrowserService and starts playback.
+ * ResumeMediaBrowser.Callback#onError or ResumeMediaBrowser.Callback#onConnected will be called
+ * depending on whether it was successful.
+ * ResumeMediaBrowser#disconnect should be called after this to ensure the connection is closed.
*/
public void restart() {
+ if (!mIsEnabled) {
+ return;
+ }
disconnect();
Bundle rootHints = new Bundle();
rootHints.putBoolean(MediaBrowserService.BrowserRoot.EXTRA_RECENT, true);
@@ -224,18 +237,21 @@ public class QSMediaBrowser {
/**
* Used to test if SystemUI is allowed to connect to the given component as a MediaBrowser.
- * QSMediaBrowser.Callback#onError or QSMediaBrowser.Callback#onConnected will be called
+ * ResumeMediaBrowser.Callback#onError or ResumeMediaBrowser.Callback#onConnected will be called
* depending on whether it was successful.
- * QSMediaBrowser#disconnect should be called after this to ensure the connection is closed.
+ * ResumeMediaBrowser#disconnect should be called after this to ensure the connection is closed.
*/
public void testConnection() {
+ if (!mIsEnabled) {
+ return;
+ }
disconnect();
final MediaBrowser.ConnectionCallback connectionCallback =
new MediaBrowser.ConnectionCallback() {
@Override
public void onConnected() {
Log.d(TAG, "connected");
- if (mMediaBrowser.getRoot() == null) {
+ if (TextUtils.isEmpty(mMediaBrowser.getRoot())) {
mCallback.onError();
} else {
mCallback.onConnected();
@@ -264,7 +280,7 @@ public class QSMediaBrowser {
}
/**
- * Interface to handle results from QSMediaBrowser
+ * Interface to handle results from ResumeMediaBrowser
*/
public static class Callback {
/**
@@ -286,7 +302,7 @@ public class QSMediaBrowser {
* @param browser reference to the browser
*/
public void addTrack(MediaDescription track, ComponentName component,
- QSMediaBrowser browser) {
+ ResumeMediaBrowser browser) {
}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/media/SeekBarViewModel.kt b/packages/SystemUI/src/com/android/systemui/media/SeekBarViewModel.kt
index 06821cd615a5..efc476d0c86f 100644
--- a/packages/SystemUI/src/com/android/systemui/media/SeekBarViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/SeekBarViewModel.kt
@@ -27,8 +27,10 @@ import androidx.annotation.AnyThread
import androidx.annotation.WorkerThread
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.LiveData
-
-import com.android.systemui.util.concurrency.DelayableExecutor
+import com.android.systemui.dagger.qualifiers.Background
+import com.android.systemui.util.concurrency.RepeatableExecutor
+import java.util.concurrent.Executor
+import javax.inject.Inject
private const val POSITION_UPDATE_INTERVAL_MILLIS = 100L
@@ -65,7 +67,7 @@ private fun PlaybackState.computePosition(duration: Long): Long {
}
/** ViewModel for seek bar in QS media player. */
-class SeekBarViewModel(val bgExecutor: DelayableExecutor) {
+class SeekBarViewModel @Inject constructor(@Background private val bgExecutor: RepeatableExecutor) {
private var _data = Progress(false, false, null, null)
set(value) {
@@ -89,17 +91,25 @@ class SeekBarViewModel(val bgExecutor: DelayableExecutor) {
private var callback = object : MediaController.Callback() {
override fun onPlaybackStateChanged(state: PlaybackState) {
playbackState = state
- if (shouldPollPlaybackPosition()) {
- checkPlaybackPosition()
+ if (PlaybackState.STATE_NONE.equals(playbackState)) {
+ clearController()
+ } else {
+ checkIfPollingNeeded()
}
}
+
+ override fun onSessionDestroyed() {
+ clearController()
+ }
}
+ private var cancel: Runnable? = null
/** Listening state (QS open or closed) is used to control polling of progress. */
var listening = true
- set(value) {
- if (value) {
- checkPlaybackPosition()
+ set(value) = bgExecutor.execute {
+ if (field != value) {
+ field = value
+ checkIfPollingNeeded()
}
}
@@ -131,9 +141,7 @@ class SeekBarViewModel(val bgExecutor: DelayableExecutor) {
playbackState?.getState() == PlaybackState.STATE_NONE ||
(duration != null && duration <= 0)) false else true
_data = Progress(enabled, seekAvailable, position, duration)
- if (shouldPollPlaybackPosition()) {
- checkPlaybackPosition()
- }
+ checkIfPollingNeeded()
}
/**
@@ -145,6 +153,8 @@ class SeekBarViewModel(val bgExecutor: DelayableExecutor) {
fun clearController() = bgExecutor.execute {
controller = null
playbackState = null
+ cancel?.run()
+ cancel = null
_data = _data.copy(enabled = false)
}
@@ -152,26 +162,34 @@ class SeekBarViewModel(val bgExecutor: DelayableExecutor) {
* Call to clean up any resources.
*/
@AnyThread
- fun onDestroy() {
+ fun onDestroy() = bgExecutor.execute {
controller = null
playbackState = null
+ cancel?.run()
+ cancel = null
}
- @AnyThread
- private fun checkPlaybackPosition(): Runnable = bgExecutor.executeDelayed({
+ @WorkerThread
+ private fun checkPlaybackPosition() {
val duration = _data.duration ?: -1
val currentPosition = playbackState?.computePosition(duration.toLong())?.toInt()
if (currentPosition != null && _data.elapsedTime != currentPosition) {
_data = _data.copy(elapsedTime = currentPosition)
}
- if (shouldPollPlaybackPosition()) {
- checkPlaybackPosition()
- }
- }, POSITION_UPDATE_INTERVAL_MILLIS)
+ }
@WorkerThread
- private fun shouldPollPlaybackPosition(): Boolean {
- return listening && playbackState?.isInMotion() ?: false
+ private fun checkIfPollingNeeded() {
+ val needed = listening && playbackState?.isInMotion() ?: false
+ if (needed) {
+ if (cancel == null) {
+ cancel = bgExecutor.executeRepeatedly(this::checkPlaybackPosition, 0L,
+ POSITION_UPDATE_INTERVAL_MILLIS)
+ }
+ } else {
+ cancel?.run()
+ cancel = null
+ }
}
/** Gets a listener to attach to the seek bar to handle seeking. */
@@ -188,7 +206,7 @@ class SeekBarViewModel(val bgExecutor: DelayableExecutor) {
private class SeekBarChangeListener(
val viewModel: SeekBarViewModel,
- val bgExecutor: DelayableExecutor
+ val bgExecutor: Executor
) : SeekBar.OnSeekBarChangeListener {
override fun onProgressChanged(bar: SeekBar, progress: Int, fromUser: Boolean) {
if (fromUser) {
diff --git a/packages/SystemUI/src/com/android/systemui/pip/PipTaskOrganizer.java b/packages/SystemUI/src/com/android/systemui/pip/PipTaskOrganizer.java
index c6f144aa57a1..b93e07e65c73 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/PipTaskOrganizer.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/PipTaskOrganizer.java
@@ -504,8 +504,18 @@ public class PipTaskOrganizer extends TaskOrganizer implements
// this could happen if rotation finishes before the animation
mLastReportedBounds.set(destinationBoundsOut);
scheduleFinishResizePip(mLastReportedBounds);
- } else if (!mLastReportedBounds.isEmpty()) {
- destinationBoundsOut.set(mLastReportedBounds);
+ } else {
+ // There could be an animation on-going. If there is one on-going, last-reported
+ // bounds isn't yet updated. We'll use the animator's bounds instead.
+ if (animator != null && animator.isRunning()) {
+ if (!animator.getDestinationBounds().isEmpty()) {
+ destinationBoundsOut.set(animator.getDestinationBounds());
+ }
+ } else {
+ if (!mLastReportedBounds.isEmpty()) {
+ destinationBoundsOut.set(mLastReportedBounds);
+ }
+ }
}
return;
}
diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivity.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivity.java
index a3185a2ad796..6ab73fcce399 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivity.java
@@ -295,6 +295,14 @@ public class PipMenuActivity extends Activity {
}
@Override
+ public void onTopResumedActivityChanged(boolean isTopResumedActivity) {
+ super.onTopResumedActivityChanged(isTopResumedActivity);
+ if (!isTopResumedActivity && mMenuState != MENU_STATE_NONE) {
+ hideMenu();
+ }
+ }
+
+ @Override
protected void onStop() {
super.onStop();
diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipResizeGestureHandler.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipResizeGestureHandler.java
index 4b23e678b15d..bafbd216b1a2 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipResizeGestureHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipResizeGestureHandler.java
@@ -292,20 +292,29 @@ public class PipResizeGestureHandler {
break;
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_CANCEL:
- mPipTaskOrganizer.scheduleFinishResizePip(mLastResizeBounds, (Rect bounds) -> {
- new Handler(Looper.getMainLooper()).post(() -> {
- mMotionHelper.synchronizePinnedStackBounds();
- mUpdateMovementBoundsRunnable.run();
- mCtrlType = CTRL_NONE;
- mAllowGesture = false;
- mThresholdCrossed = false;
- });
- });
+ if (!mLastResizeBounds.isEmpty()) {
+ mPipTaskOrganizer.scheduleFinishResizePip(mLastResizeBounds,
+ (Rect bounds) -> {
+ new Handler(Looper.getMainLooper()).post(() -> {
+ mMotionHelper.synchronizePinnedStackBounds();
+ mUpdateMovementBoundsRunnable.run();
+ resetState();
+ });
+ });
+ } else {
+ resetState();
+ }
break;
}
}
}
+ private void resetState() {
+ mCtrlType = CTRL_NONE;
+ mAllowGesture = false;
+ mThresholdCrossed = false;
+ }
+
void updateMaxSize(int maxX, int maxY) {
mMaxSize.set(maxX, maxY);
}
diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java
index c274ee96b170..3cc9127068bf 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java
@@ -30,6 +30,7 @@ import android.graphics.PixelFormat;
import android.graphics.Point;
import android.graphics.PointF;
import android.graphics.Rect;
+import android.graphics.drawable.TransitionDrawable;
import android.os.Handler;
import android.os.RemoteException;
import android.util.Log;
@@ -76,6 +77,9 @@ import java.io.PrintWriter;
public class PipTouchHandler {
private static final String TAG = "PipTouchHandler";
+ /** Duration of the dismiss scrim fading in/out. */
+ private static final int DISMISS_TRANSITION_DURATION_MS = 200;
+
// Allow dragging the PIP to a location to close it
private final boolean mEnableDismissDragToEdge;
// Allow PIP to resize to a slightly bigger state upon touch
@@ -161,6 +165,7 @@ public class PipTouchHandler {
private float mSavedSnapFraction = -1f;
private boolean mSendingHoverAccessibilityEvents;
private boolean mMovementWithinDismiss;
+ private boolean mHideMenuAfterShown = false;
private PipAccessibilityInteractionConnection mConnection;
// Touch state
@@ -248,6 +253,8 @@ public class PipTouchHandler {
mTargetView = new DismissCircleView(context);
mTargetViewContainer = new FrameLayout(context);
+ mTargetViewContainer.setBackgroundDrawable(
+ context.getDrawable(R.drawable.floating_dismiss_gradient_transition));
mTargetViewContainer.setClipChildren(false);
mTargetViewContainer.addView(mTargetView);
@@ -552,6 +559,9 @@ public class PipTouchHandler {
mMagneticTargetAnimator
.spring(DynamicAnimation.TRANSLATION_Y, 0f, mTargetSpringConfig)
.start();
+
+ ((TransitionDrawable) mTargetViewContainer.getBackground()).startTransition(
+ DISMISS_TRANSITION_DURATION_MS);
}
}
@@ -564,6 +574,9 @@ public class PipTouchHandler {
mTargetSpringConfig)
.withEndActions(() -> mTargetViewContainer.setVisibility(View.GONE))
.start();
+
+ ((TransitionDrawable) mTargetViewContainer.getBackground()).reverseTransition(
+ DISMISS_TRANSITION_DURATION_MS);
}
/**
@@ -605,11 +618,9 @@ public class PipTouchHandler {
MotionEvent ev = (MotionEvent) inputEvent;
-
- if (mPipResizeGestureHandler.isWithinTouchRegion((int) ev.getX(), (int) ev.getY())) {
+ if (mPipResizeGestureHandler.isWithinTouchRegion((int) ev.getRawX(), (int) ev.getRawY())) {
return true;
}
-
if (mMagnetizedPip.maybeConsumeMotionEvent(ev)) {
// If the first touch event occurs within the magnetic field, pass the ACTION_DOWN event
// to the touch state. Touch state needs a DOWN event in order to later process MOVE
@@ -677,6 +688,7 @@ public class PipTouchHandler {
break;
}
case MotionEvent.ACTION_HOVER_EXIT: {
+ mHideMenuAfterShown = true;
// If Touch Exploration is enabled, some a11y services (e.g. Talkback) is probably
// on and changing MotionEvents into HoverEvents.
// Let's not enable menu show/hide for a11y services.
@@ -767,6 +779,9 @@ public class PipTouchHandler {
mSavedSnapFraction = mMotionHelper.animateToExpandedState(expandedBounds,
mMovementBounds, mExpandedMovementBounds, callback);
}
+ if (mHideMenuAfterShown) {
+ mMenuController.hideMenu();
+ }
} else if (menuState == MENU_STATE_NONE && mMenuState == MENU_STATE_FULL) {
// Try and restore the PiP to the closest edge, using the saved snap fraction
// if possible
@@ -804,6 +819,7 @@ public class PipTouchHandler {
}
}
mMenuState = menuState;
+ mHideMenuAfterShown = false;
updateMovementBounds();
// If pip menu has dismissed, we should register the A11y ActionReplacingConnection for pip
// as well, or it can't handle a11y focus and pip menu can't perform any action.
diff --git a/packages/SystemUI/src/com/android/systemui/power/EnhancedEstimatesImpl.java b/packages/SystemUI/src/com/android/systemui/power/EnhancedEstimatesImpl.java
index 78f53501d100..7d54c211242f 100644
--- a/packages/SystemUI/src/com/android/systemui/power/EnhancedEstimatesImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/power/EnhancedEstimatesImpl.java
@@ -1,6 +1,7 @@
package com.android.systemui.power;
import com.android.settingslib.fuelgauge.Estimate;
+import com.android.settingslib.fuelgauge.EstimateKt;
import javax.inject.Inject;
import javax.inject.Singleton;
@@ -19,7 +20,10 @@ public class EnhancedEstimatesImpl implements EnhancedEstimates {
@Override
public Estimate getEstimate() {
- return null;
+ // Returns an unknown estimate.
+ return new Estimate(EstimateKt.ESTIMATE_MILLIS_UNKNOWN,
+ false /* isBasedOnUsage */,
+ EstimateKt.AVERAGE_TIME_TO_DISCHARGE_UNKNOWN);
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/power/PowerUI.java b/packages/SystemUI/src/com/android/systemui/power/PowerUI.java
index 48750fa5e769..078c540939aa 100644
--- a/packages/SystemUI/src/com/android/systemui/power/PowerUI.java
+++ b/packages/SystemUI/src/com/android/systemui/power/PowerUI.java
@@ -374,8 +374,10 @@ public class PowerUI extends SystemUI implements CommandQueue.Callbacks {
BatteryStateSnapshot lastSnapshot) {
// if we are now over 45% battery & 6 hours remaining so we can trigger hybrid
// notification again
+ final long timeRemainingMillis = currentSnapshot.getTimeRemainingMillis();
if (currentSnapshot.getBatteryLevel() >= CHARGE_CYCLE_PERCENT_RESET
- && currentSnapshot.getTimeRemainingMillis() > SIX_HOURS_MILLIS) {
+ && (timeRemainingMillis > SIX_HOURS_MILLIS
+ || timeRemainingMillis == NO_ESTIMATE_AVAILABLE)) {
mLowWarningShownThisChargeCycle = false;
mSevereWarningShownThisChargeCycle = false;
if (DEBUG) {
@@ -390,8 +392,8 @@ public class PowerUI extends SystemUI implements CommandQueue.Callbacks {
mWarnings.showLowBatteryWarning(playSound);
// mark if we've already shown a warning this cycle. This will prevent the notification
// trigger from spamming users by only showing low/critical warnings once per cycle
- if (currentSnapshot.getTimeRemainingMillis()
- <= currentSnapshot.getSevereThresholdMillis()
+ if ((timeRemainingMillis != NO_ESTIMATE_AVAILABLE
+ && timeRemainingMillis <= currentSnapshot.getSevereThresholdMillis())
|| currentSnapshot.getBatteryLevel()
<= currentSnapshot.getSevereLevelThreshold()) {
mSevereWarningShownThisChargeCycle = true;
@@ -426,15 +428,18 @@ public class PowerUI extends SystemUI implements CommandQueue.Callbacks {
return false;
}
+ final long timeRemainingMillis = snapshot.getTimeRemainingMillis();
// Only show the low warning if enabled once per charge cycle & no battery saver
final boolean canShowWarning = snapshot.isLowWarningEnabled()
&& !mLowWarningShownThisChargeCycle && !snapshot.isPowerSaver()
- && (snapshot.getTimeRemainingMillis() < snapshot.getLowThresholdMillis()
+ && ((timeRemainingMillis != NO_ESTIMATE_AVAILABLE
+ && timeRemainingMillis < snapshot.getLowThresholdMillis())
|| snapshot.getBatteryLevel() <= snapshot.getLowLevelThreshold());
// Only show the severe warning once per charge cycle
final boolean canShowSevereWarning = !mSevereWarningShownThisChargeCycle
- && (snapshot.getTimeRemainingMillis() < snapshot.getSevereThresholdMillis()
+ && ((timeRemainingMillis != NO_ESTIMATE_AVAILABLE
+ && timeRemainingMillis < snapshot.getSevereThresholdMillis())
|| snapshot.getBatteryLevel() <= snapshot.getSevereLevelThreshold());
final boolean canShow = canShowWarning || canShowSevereWarning;
diff --git a/packages/SystemUI/src/com/android/systemui/qs/PageIndicator.java b/packages/SystemUI/src/com/android/systemui/qs/PageIndicator.java
index 0d614497190f..2c76d70fb3cc 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/PageIndicator.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/PageIndicator.java
@@ -45,9 +45,6 @@ public class PageIndicator extends ViewGroup {
}
public void setNumPages(int numPages) {
- if (numPages == getChildCount()) {
- return;
- }
TypedArray array = getContext().obtainStyledAttributes(
new int[]{android.R.attr.colorControlActivated});
int color = array.getColor(0, 0);
@@ -55,12 +52,12 @@ public class PageIndicator extends ViewGroup {
setNumPages(numPages, color);
}
- /** Oveload of setNumPages that allows the indicator color to be specified.*/
+ /** Overload of setNumPages that allows the indicator color to be specified.*/
public void setNumPages(int numPages, int color) {
+ setVisibility(numPages > 1 ? View.VISIBLE : View.GONE);
if (numPages == getChildCount()) {
return;
}
- setVisibility(numPages > 1 ? View.VISIBLE : View.GONE);
if (mAnimating) {
Log.w(TAG, "setNumPages during animation");
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSContainerImpl.java b/packages/SystemUI/src/com/android/systemui/qs/QSContainerImpl.java
index 6b0775f6c2d7..1c3b6850afc1 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSContainerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSContainerImpl.java
@@ -50,6 +50,8 @@ public class QSContainerImpl extends FrameLayout {
private int mSideMargins;
private boolean mQsDisabled;
+ private int mContentPaddingStart = -1;
+ private int mContentPaddingEnd = -1;
public QSContainerImpl(Context context, AttributeSet attrs) {
super(context, attrs);
@@ -66,10 +68,9 @@ public class QSContainerImpl extends FrameLayout {
mBackground = findViewById(R.id.quick_settings_background);
mStatusBarBackground = findViewById(R.id.quick_settings_status_bar_background);
mBackgroundGradient = findViewById(R.id.quick_settings_gradient_view);
- mSideMargins = getResources().getDimensionPixelSize(R.dimen.notification_side_paddings);
+ updateResources();
setImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY_NO);
- setMargins();
}
@Override
@@ -103,10 +104,15 @@ public class QSContainerImpl extends FrameLayout {
if (navBelow) {
maxQs -= getResources().getDimensionPixelSize(R.dimen.navigation_bar_height);
}
+
+ int padding = mPaddingLeft + mPaddingRight + layoutParams.leftMargin
+ + layoutParams.rightMargin;
+ final int qsPanelWidthSpec = getChildMeasureSpec(widthMeasureSpec, padding,
+ layoutParams.width);
// Measure with EXACTLY. That way, PagedTileLayout will only use excess height and will be
// measured last, after other views and padding is accounted for.
- mQSPanel.measure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(maxQs, MeasureSpec.EXACTLY));
- int width = mQSPanel.getMeasuredWidth();
+ mQSPanel.measure(qsPanelWidthSpec, MeasureSpec.makeMeasureSpec(maxQs, MeasureSpec.EXACTLY));
+ int width = mQSPanel.getMeasuredWidth() + padding;
int height = layoutParams.topMargin + layoutParams.bottomMargin
+ mQSPanel.getMeasuredHeight() + getPaddingBottom();
super.onMeasure(MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY),
@@ -148,8 +154,18 @@ public class QSContainerImpl extends FrameLayout {
LayoutParams layoutParams = (LayoutParams) mQSPanel.getLayoutParams();
layoutParams.topMargin = mContext.getResources().getDimensionPixelSize(
com.android.internal.R.dimen.quick_qs_offset_height);
-
mQSPanel.setLayoutParams(layoutParams);
+
+ mSideMargins = getResources().getDimensionPixelSize(R.dimen.notification_side_paddings);
+ mContentPaddingStart = getResources().getDimensionPixelSize(
+ com.android.internal.R.dimen.notification_content_margin_start);
+ int newPaddingEnd = getResources().getDimensionPixelSize(
+ com.android.internal.R.dimen.notification_content_margin_end);
+ boolean marginsChanged = newPaddingEnd != mContentPaddingEnd;
+ mContentPaddingEnd = newPaddingEnd;
+ if (marginsChanged) {
+ updatePaddingsAndMargins();
+ }
}
/**
@@ -196,17 +212,32 @@ public class QSContainerImpl extends FrameLayout {
updateExpansion();
}
- private void setMargins() {
- setMargins(mQSDetail);
- setMargins(mBackground);
- mQSPanel.setMargins(mSideMargins);
- mHeader.setMargins(mSideMargins);
- }
-
- private void setMargins(View view) {
- FrameLayout.LayoutParams lp = (LayoutParams) view.getLayoutParams();
- lp.rightMargin = mSideMargins;
- lp.leftMargin = mSideMargins;
+ private void updatePaddingsAndMargins() {
+ for (int i = 0; i < getChildCount(); i++) {
+ View view = getChildAt(i);
+ if (view == mStatusBarBackground || view == mBackgroundGradient
+ || view == mQSCustomizer) {
+ // Some views are always full width
+ continue;
+ }
+ LayoutParams lp = (LayoutParams) view.getLayoutParams();
+ lp.rightMargin = mSideMargins;
+ lp.leftMargin = mSideMargins;
+ if (view == mQSPanel) {
+ // QS panel lays out some of its content full width
+ mQSPanel.setContentMargins(mContentPaddingStart, mContentPaddingEnd);
+ } else if (view == mHeader) {
+ // The header contains the QQS panel which needs to have special padding, to
+ // visually align them.
+ mHeader.setContentMargins(mContentPaddingStart, mContentPaddingEnd);
+ } else {
+ view.setPaddingRelative(
+ mContentPaddingStart,
+ view.getPaddingTop(),
+ mContentPaddingEnd,
+ view.getPaddingBottom());
+ }
+ }
}
private int getDisplayHeight() {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
index 48ba1b99d714..78448785fe2f 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
@@ -88,6 +88,8 @@ public class QSPanel extends LinearLayout implements Tunable, Callback, Brightne
private final H mHandler = new H();
private final MetricsLogger mMetricsLogger = Dependency.get(MetricsLogger.class);
private final QSTileRevealController mQsTileRevealController;
+ /** Whether or not the QS media player feature is enabled. */
+ protected boolean mUsingMediaPlayer;
protected boolean mExpanded;
protected boolean mListening;
@@ -102,6 +104,9 @@ public class QSPanel extends LinearLayout implements Tunable, Callback, Brightne
protected QSSecurityFooter mFooter;
private PageIndicator mFooterPageIndicator;
private boolean mGridContentVisible = true;
+ private int mContentMarginStart;
+ private int mContentMarginEnd;
+ private int mVisualTilePadding;
protected QSTileLayout mTileLayout;
@@ -122,6 +127,7 @@ public class QSPanel extends LinearLayout implements Tunable, Callback, Brightne
UiEventLogger uiEventLogger
) {
super(context, attrs);
+ mUsingMediaPlayer = useQsMediaPlayer(context);
mMediaHost = mediaHost;
mContext = context;
mQSLogger = qsLogger;
@@ -170,8 +176,6 @@ public class QSPanel extends LinearLayout implements Tunable, Callback, Brightne
mMediaHost.init(MediaHierarchyManager.LOCATION_QS);
ViewGroup hostView = mMediaHost.getHostView();
addView(hostView);
- int sidePaddings = getResources().getDimensionPixelSize(
- R.dimen.quick_settings_side_margins);
int bottomPadding = getResources().getDimensionPixelSize(
R.dimen.quick_settings_expanded_bottom_margin);
MarginLayoutParams layoutParams = (MarginLayoutParams) hostView.getLayoutParams();
@@ -179,8 +183,7 @@ public class QSPanel extends LinearLayout implements Tunable, Callback, Brightne
layoutParams.width = ViewGroup.LayoutParams.MATCH_PARENT;
layoutParams.bottomMargin = bottomPadding;
hostView.setLayoutParams(layoutParams);
- hostView.setPadding(sidePaddings, hostView.getPaddingTop(), sidePaddings,
- hostView.getPaddingBottom());
+ updateMediaHostContentMargins();
}
protected void addDivider() {
@@ -359,8 +362,10 @@ public class QSPanel extends LinearLayout implements Tunable, Callback, Brightne
}
public void updateResources() {
- final Resources res = mContext.getResources();
- setPadding(0, res.getDimensionPixelSize(R.dimen.qs_panel_padding_top), 0, res.getDimensionPixelSize(R.dimen.qs_panel_padding_bottom));
+ int tileSize = getResources().getDimensionPixelSize(R.dimen.qs_quick_tile_size);
+ int tileBg = getResources().getDimensionPixelSize(R.dimen.qs_tile_background_size);
+ mVisualTilePadding = (int) ((tileSize - tileBg) / 2.0f);
+ updatePadding();
updatePageIndicator();
@@ -372,6 +377,14 @@ public class QSPanel extends LinearLayout implements Tunable, Callback, Brightne
}
}
+ protected void updatePadding() {
+ final Resources res = mContext.getResources();
+ setPaddingRelative(getPaddingStart(),
+ res.getDimensionPixelSize(R.dimen.qs_panel_padding_top),
+ getPaddingEnd(),
+ res.getDimensionPixelSize(R.dimen.qs_panel_padding_bottom));
+ }
+
@Override
protected void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
@@ -723,17 +736,51 @@ public class QSPanel extends LinearLayout implements Tunable, Callback, Brightne
mFooter.showDeviceMonitoringDialog();
}
- public void setMargins(int sideMargins) {
- for (int i = 0; i < getChildCount(); i++) {
- View view = getChildAt(i);
- if (view != mTileLayout) {
- LayoutParams lp = (LayoutParams) view.getLayoutParams();
- lp.leftMargin = sideMargins;
- lp.rightMargin = sideMargins;
- }
+ public void setContentMargins(int startMargin, int endMargin) {
+ // Only some views actually want this content padding, others want to go all the way
+ // to the edge like the brightness slider
+ mContentMarginStart = startMargin;
+ mContentMarginEnd = endMargin;
+ updateTileLayoutMargins(mContentMarginStart - mVisualTilePadding,
+ mContentMarginEnd - mVisualTilePadding);
+ updateMediaHostContentMargins();
+ }
+
+ /**
+ * Update the margins of all tile Layouts.
+ *
+ * @param visualMarginStart the visual start margin of the tile, adjusted for local insets
+ * to the tile. This can be set on a tileLayout
+ * @param visualMarginEnd the visual end margin of the tile, adjusted for local insets
+ * to the tile. This can be set on a tileLayout
+ */
+ protected void updateTileLayoutMargins(int visualMarginStart, int visualMarginEnd) {
+ updateMargins((View) mTileLayout, visualMarginStart, visualMarginEnd);
+ }
+
+ /**
+ * Update the margins of the media hosts
+ */
+ protected void updateMediaHostContentMargins() {
+ if (mUsingMediaPlayer && mMediaHost != null) {
+ updateMargins(mMediaHost.getHostView(), mContentMarginStart, mContentMarginEnd);
}
}
+ /**
+ * Update the margins of a view.
+ *
+ * @param view the view to adjust
+ * @param start the start margin to set
+ * @param end the end margin to set
+ */
+ protected void updateMargins(View view, int start, int end) {
+ LayoutParams lp = (LayoutParams) view.getLayoutParams();
+ lp.setMarginStart(start);
+ lp.setMarginEnd(end);
+ view.setLayoutParams(lp);
+ }
+
public MediaHost getMediaHost() {
return mMediaHost;
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSTileHost.java b/packages/SystemUI/src/com/android/systemui/qs/QSTileHost.java
index 4008918e267c..65d3572d04a3 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSTileHost.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSTileHost.java
@@ -355,10 +355,23 @@ public class QSTileHost implements QSHost, Tunable, PluginListener<QSFactory>, D
}
public void addTile(ComponentName tile) {
+ addTile(tile, /* end */ false);
+ }
+
+ /**
+ * Adds a custom tile to the set of current tiles.
+ * @param tile the component name of the {@link android.service.quicksettings.TileService}
+ * @param end if true, the tile will be added at the end. If false, at the beginning.
+ */
+ public void addTile(ComponentName tile, boolean end) {
String spec = CustomTile.toSpec(tile);
if (!mTileSpecs.contains(spec)) {
List<String> newSpecs = new ArrayList<>(mTileSpecs);
- newSpecs.add(0, spec);
+ if (end) {
+ newSpecs.add(spec);
+ } else {
+ newSpecs.add(0, spec);
+ }
changeTiles(mTileSpecs, newSpecs);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java b/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java
index 75507beba7ae..94b4cee92965 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java
@@ -41,7 +41,6 @@ import com.android.systemui.qs.customize.QSCustomizer;
import com.android.systemui.qs.logging.QSLogger;
import com.android.systemui.tuner.TunerService;
import com.android.systemui.tuner.TunerService.Tunable;
-import com.android.systemui.util.Utils;
import java.util.ArrayList;
import java.util.Collection;
@@ -62,8 +61,6 @@ public class QuickQSPanel extends QSPanel {
private boolean mDisabledByPolicy;
private int mMaxTiles;
protected QSPanel mFullPanel;
- /** Whether or not the QS media player feature is enabled. */
- private boolean mUsingMediaPlayer;
/** Whether or not the QuickQSPanel currently contains a media player. */
private boolean mShowHorizontalTileLayout;
private LinearLayout mHorizontalLinearLayout;
@@ -84,8 +81,7 @@ public class QuickQSPanel extends QSPanel {
MediaHost mediaHost,
UiEventLogger uiEventLogger
) {
- super(context, attrs, dumpManager, broadcastDispatcher, qsLogger, mediaHost,
- uiEventLogger);
+ super(context, attrs, dumpManager, broadcastDispatcher, qsLogger, mediaHost, uiEventLogger);
if (mFooter != null) {
removeView(mFooter.getView());
}
@@ -97,8 +93,6 @@ public class QuickQSPanel extends QSPanel {
}
mMediaBottomMargin = getResources().getDimensionPixelSize(
R.dimen.quick_settings_media_extra_bottom_margin);
-
- mUsingMediaPlayer = Utils.useQsMediaPlayer(context);
if (mUsingMediaPlayer) {
mHorizontalLinearLayout = new LinearLayout(mContext);
mHorizontalLinearLayout.setOrientation(LinearLayout.HORIZONTAL);
@@ -132,7 +126,6 @@ public class QuickQSPanel extends QSPanel {
mHorizontalLinearLayout.setVisibility(useHorizontal ? View.VISIBLE : View.GONE);
addView((View) mRegularTileLayout, 0);
super.setPadding(0, 0, 0, 0);
- applySideMargins(mHorizontalLinearLayout);
applyBottomMargin((View) mRegularTileLayout);
} else {
sDefaultMaxTiles = getResources().getInteger(R.integer.quick_qs_panel_max_columns);
@@ -151,14 +144,6 @@ public class QuickQSPanel extends QSPanel {
view.setLayoutParams(layoutParams);
}
- private void applySideMargins(View view) {
- int margin = getResources().getDimensionPixelSize(R.dimen.qs_header_tile_margin_horizontal);
- MarginLayoutParams layoutParams = (MarginLayoutParams) view.getLayoutParams();
- layoutParams.setMarginStart(margin);
- layoutParams.setMarginEnd(margin);
- view.setLayoutParams(layoutParams);
- }
-
private void reAttachMediaHost() {
if (mMediaHost == null) {
return;
@@ -177,10 +162,6 @@ public class QuickQSPanel extends QSPanel {
layoutParams.width = horizontal ? 0 : ViewGroup.LayoutParams.MATCH_PARENT;
layoutParams.weight = horizontal ? 1.5f : 0;
layoutParams.bottomMargin = mMediaBottomMargin;
- int marginStart = horizontal
- ? getResources().getDimensionPixelSize(R.dimen.qs_header_tile_margin_horizontal)
- : 0;
- layoutParams.setMarginStart(marginStart);
}
}
@@ -194,11 +175,22 @@ public class QuickQSPanel extends QSPanel {
mMediaHost.setShowsOnlyActiveMedia(true);
mMediaHost.init(MediaHierarchyManager.LOCATION_QQS);
reAttachMediaHost();
+ updateMediaHostContentMargins();
+ }
+
+ @Override
+ protected void updateTileLayoutMargins(int visualMarginStart, int visualMarginEnd) {
+ if (mUsingMediaPlayer) {
+ updateMargins((View) mRegularTileLayout, visualMarginStart, visualMarginEnd);
+ updateMargins((View) mHorizontalTileLayout, visualMarginStart, 0);
+ } else {
+ updateMargins((View) mTileLayout, visualMarginStart, visualMarginEnd);
+ }
}
@Override
- public void setPadding(int left, int top, int right, int bottom) {
- // Always have no padding.
+ protected void updatePadding() {
+ // QS Panel is setting a top padding by default, which we don't need.
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java b/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java
index 29b3436c0b72..20e47b2f2fa9 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java
@@ -42,6 +42,7 @@ import android.view.DisplayCutout;
import android.view.View;
import android.view.WindowInsets;
import android.widget.ImageView;
+import android.widget.LinearLayout;
import android.widget.RelativeLayout;
import android.widget.TextView;
@@ -143,6 +144,11 @@ public class QuickStatusBarHeader extends RelativeLayout implements
private boolean mHasTopCutout = false;
private int mRoundedCornerPadding = 0;
+ private int mContentMarginStart;
+ private int mContentMarginEnd;
+ private int mWaterfallTopInset;
+ private int mCutOutPaddingLeft;
+ private int mCutOutPaddingRight;
@Inject
public QuickStatusBarHeader(@Named(VIEW_CONTEXT) Context context, AttributeSet attrs,
@@ -422,33 +428,42 @@ public class QuickStatusBarHeader extends RelativeLayout implements
@Override
public WindowInsets onApplyWindowInsets(WindowInsets insets) {
- // Handle padding of QuickStatusBarHeader
- setPadding(mRoundedCornerPadding, getPaddingTop(), mRoundedCornerPadding,
- getPaddingBottom());
-
- // Handle padding of SystemIconsView
+ // Handle padding of the clock
DisplayCutout cutout = insets.getDisplayCutout();
Pair<Integer, Integer> cornerCutoutPadding = StatusBarWindowView.cornerCutoutMargins(
cutout, getDisplay());
Pair<Integer, Integer> padding =
StatusBarWindowView.paddingNeededForCutoutAndRoundedCorner(
- cutout, cornerCutoutPadding, mRoundedCornerPadding);
- final int waterfallTopInset = cutout == null ? 0 : cutout.getWaterfallInsets().top;
- int statusBarPaddingLeft = isLayoutRtl()
- ? getResources().getDimensionPixelSize(R.dimen.status_bar_padding_end)
- : getResources().getDimensionPixelSize(R.dimen.status_bar_padding_start);
- int statusBarPaddingRight = isLayoutRtl()
- ? getResources().getDimensionPixelSize(R.dimen.status_bar_padding_start)
- : getResources().getDimensionPixelSize(R.dimen.status_bar_padding_end);
- mSystemIconsView.setPadding(
- Math.max(padding.first + statusBarPaddingLeft - mRoundedCornerPadding, 0),
- waterfallTopInset,
- Math.max(padding.second + statusBarPaddingRight - mRoundedCornerPadding, 0),
- 0);
-
+ cutout, cornerCutoutPadding, -1);
+ mCutOutPaddingLeft = padding.first;
+ mCutOutPaddingRight = padding.second;
+ mWaterfallTopInset = cutout == null ? 0 : cutout.getWaterfallInsets().top;
+ updateClockPadding();
return super.onApplyWindowInsets(insets);
}
+ private void updateClockPadding() {
+ int clockPaddingLeft = 0;
+ int clockPaddingRight = 0;
+ // The clock might collide with cutouts, let's shift it out of the way.
+ // We only do that if the inset is bigger than our own padding, since it's nicer to
+ // align with
+ if (mCutOutPaddingLeft > 0) {
+ // if there's a cutout, let's use at least the rounded corner inset
+ int cutoutPadding = Math.max(mCutOutPaddingLeft, mRoundedCornerPadding);
+ int contentMarginLeft = isLayoutRtl() ? mContentMarginEnd : mContentMarginStart;
+ clockPaddingLeft = Math.max(cutoutPadding - contentMarginLeft, 0);
+ }
+ if (mCutOutPaddingRight > 0) {
+ // if there's a cutout, let's use at least the rounded corner inset
+ int cutoutPadding = Math.max(mCutOutPaddingRight, mRoundedCornerPadding);
+ int contentMarginRight = isLayoutRtl() ? mContentMarginStart : mContentMarginEnd;
+ clockPaddingRight = Math.max(cutoutPadding - contentMarginRight, 0);
+ }
+
+ mSystemIconsView.setPadding(clockPaddingLeft, mWaterfallTopInset, clockPaddingRight, 0);
+ }
+
@Override
@VisibleForTesting
public void onDetachedFromWindow() {
@@ -558,24 +573,27 @@ public class QuickStatusBarHeader extends RelativeLayout implements
return color == Color.WHITE ? 0 : 1;
}
- public void setMargins(int sideMargins) {
- for (int i = 0; i < getChildCount(); i++) {
- View v = getChildAt(i);
- // Prevents these views from getting set a margin.
- // The Icon views all have the same padding set in XML to be aligned.
- if (v == mSystemIconsView || v == mQuickQsStatusIcons || v == mHeaderQsPanel
- || v == mHeaderTextContainerView) {
- continue;
- }
- RelativeLayout.LayoutParams lp = (RelativeLayout.LayoutParams) v.getLayoutParams();
- lp.leftMargin = sideMargins;
- lp.rightMargin = sideMargins;
- }
- }
-
@NonNull
@Override
public Lifecycle getLifecycle() {
return mLifecycle;
}
+
+ public void setContentMargins(int marginStart, int marginEnd) {
+ mContentMarginStart = marginStart;
+ mContentMarginEnd = marginEnd;
+ for (int i = 0; i < getChildCount(); i++) {
+ View view = getChildAt(i);
+ if (view == mHeaderQsPanel) {
+ // QS panel doesn't lays out some of its content full width
+ mHeaderQsPanel.setContentMargins(marginStart, marginEnd);
+ } else {
+ MarginLayoutParams lp = (MarginLayoutParams) view.getLayoutParams();
+ lp.setMarginStart(marginStart);
+ lp.setMarginEnd(marginEnd);
+ view.setLayoutParams(lp);
+ }
+ }
+ updateClockPadding();
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/TileLayout.java b/packages/SystemUI/src/com/android/systemui/qs/TileLayout.java
index 098431658e6a..383c29d90a22 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/TileLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/TileLayout.java
@@ -96,7 +96,6 @@ public class TileLayout extends ViewGroup implements QSTileLayout {
mCellMarginHorizontal = res.getDimensionPixelSize(R.dimen.qs_tile_margin_horizontal);
mCellMarginVertical= res.getDimensionPixelSize(R.dimen.qs_tile_margin_vertical);
mCellMarginTop = res.getDimensionPixelSize(R.dimen.qs_tile_margin_top);
- mSidePadding = res.getDimensionPixelOffset(R.dimen.qs_tile_layout_margin_side);
mMaxAllowedRows = Math.max(1, getResources().getInteger(R.integer.quick_settings_max_rows));
if (mLessRows) mMaxAllowedRows = Math.max(1, mMaxAllowedRows - 1);
if (mColumns != columns) {
@@ -120,7 +119,7 @@ public class TileLayout extends ViewGroup implements QSTileLayout {
mRows = (numTiles + mColumns - 1) / mColumns;
}
mCellWidth =
- (availableWidth - mSidePadding * 2 - (mCellMarginHorizontal * mColumns)) / mColumns;
+ (availableWidth - (mCellMarginHorizontal * mColumns)) / mColumns;
// Measure each QS tile.
View previousView = this;
@@ -204,7 +203,7 @@ public class TileLayout extends ViewGroup implements QSTileLayout {
}
protected int getColumnStart(int column) {
- return getPaddingStart() + mSidePadding + mCellMarginHorizontal / 2 +
+ return getPaddingStart() + mCellMarginHorizontal / 2 +
column * (mCellWidth + mCellMarginHorizontal);
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/external/TileServices.java b/packages/SystemUI/src/com/android/systemui/qs/external/TileServices.java
index db7c6ad69d23..2863d08a75dc 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/external/TileServices.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/external/TileServices.java
@@ -69,10 +69,14 @@ public class TileServices extends IQSService.Stub {
mHost = host;
mContext = mHost.getContext();
mBroadcastDispatcher = broadcastDispatcher;
- mBroadcastDispatcher.registerReceiver(mRequestListeningReceiver,
- new IntentFilter(TileService.ACTION_REQUEST_LISTENING));
mHandler = new Handler(looper);
mMainHandler = new Handler(Looper.getMainLooper());
+ mBroadcastDispatcher.registerReceiver(
+ mRequestListeningReceiver,
+ new IntentFilter(TileService.ACTION_REQUEST_LISTENING),
+ null, // Use the default Executor
+ UserHandle.ALL
+ );
}
public Context getContext() {
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 d7dd6f24ceb3..32ef063a55be 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/ScreenRecordTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/ScreenRecordTile.java
@@ -22,6 +22,7 @@ import android.text.TextUtils;
import android.util.Log;
import android.widget.Switch;
+import com.android.internal.logging.UiEventLogger;
import com.android.systemui.R;
import com.android.systemui.plugins.ActivityStarter;
import com.android.systemui.plugins.qs.QSTile;
@@ -41,14 +42,16 @@ public class ScreenRecordTile extends QSTileImpl<QSTile.BooleanState>
private ActivityStarter mActivityStarter;
private long mMillisUntilFinished = 0;
private Callback mCallback = new Callback();
+ private UiEventLogger mUiEventLogger;
@Inject
public ScreenRecordTile(QSHost host, RecordingController controller,
- ActivityStarter activityStarter) {
+ ActivityStarter activityStarter, UiEventLogger uiEventLogger) {
super(host);
mController = controller;
mController.observe(this, mCallback);
mActivityStarter = activityStarter;
+ mUiEventLogger = uiEventLogger;
}
@Override
@@ -112,7 +115,6 @@ public class ScreenRecordTile extends QSTileImpl<QSTile.BooleanState>
}
private void startCountdown() {
- Log.d(TAG, "Starting countdown");
// Close QS, otherwise the permission dialog appears beneath it
getHost().collapsePanels();
Intent intent = mController.getPromptIntent();
@@ -125,7 +127,6 @@ public class ScreenRecordTile extends QSTileImpl<QSTile.BooleanState>
}
private void stopRecording() {
- Log.d(TAG, "Stopping recording from tile");
mController.stopRecording();
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/UserDetailItemView.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/UserDetailItemView.java
index aa63b4077b1b..6a8c61491709 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/UserDetailItemView.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/UserDetailItemView.java
@@ -95,14 +95,11 @@ public class UserDetailItemView extends LinearLayout {
mAvatar.setDrawableWithBadge(picture, userId);
}
- public void setAvatarEnabled(boolean enabled) {
- mAvatar.setEnabled(enabled);
- }
-
public void setDisabledByAdmin(boolean disabled) {
- mRestrictedPadlock.setVisibility(disabled ? View.VISIBLE : View.GONE);
- mName.setEnabled(!disabled);
- mAvatar.setEnabled(!disabled);
+ if (mRestrictedPadlock != null) {
+ mRestrictedPadlock.setVisibility(disabled ? View.VISIBLE : View.GONE);
+ }
+ setEnabled(!disabled);
}
public void setEnabled(boolean enabled) {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/UserDetailView.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/UserDetailView.java
index 89ce125ae985..fba7a22351e2 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/UserDetailView.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/UserDetailView.java
@@ -16,8 +16,12 @@
package com.android.systemui.qs.tiles;
+import static com.android.systemui.statusbar.policy.UserSwitcherController.USER_SWITCH_DISABLED_ALPHA;
+import static com.android.systemui.statusbar.policy.UserSwitcherController.USER_SWITCH_ENABLED_ALPHA;
+
import android.content.Context;
import android.content.Intent;
+import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.LayerDrawable;
import android.util.AttributeSet;
@@ -94,18 +98,21 @@ public class UserDetailView extends PseudoGridView {
}
String name = getName(mContext, item);
if (item.picture == null) {
- v.bind(name, getDrawable(mContext, item), item.resolveId());
+ v.bind(name, getDrawable(mContext, item).mutate(), item.resolveId());
} else {
- v.bind(name, item.picture, item.info.id);
+ Drawable drawable = new BitmapDrawable(v.getResources(), item.picture);
+ drawable.setColorFilter(
+ item.isSwitchToEnabled ? null : getDisabledUserAvatarColorFilter());
+ v.bind(name, drawable, item.info.id);
}
v.setActivated(item.isCurrent);
+ v.setDisabledByAdmin(item.isDisabledByAdmin);
+ v.setEnabled(item.isSwitchToEnabled);
+ v.setAlpha(v.isEnabled() ? USER_SWITCH_ENABLED_ALPHA : USER_SWITCH_DISABLED_ALPHA);
+
if (item.isCurrent) {
mCurrentUserView = v;
}
- v.setDisabledByAdmin(item.isDisabledByAdmin);
- if (!item.isSwitchToEnabled) {
- v.setEnabled(false);
- }
v.setTag(item);
return v;
}
@@ -113,8 +120,14 @@ public class UserDetailView extends PseudoGridView {
private static Drawable getDrawable(Context context,
UserSwitcherController.UserRecord item) {
Drawable icon = getIconDrawable(context, item);
- int iconColorRes = item.isCurrent ? R.color.qs_user_switcher_selected_avatar_icon_color
- : R.color.qs_user_switcher_avatar_icon_color;
+ int iconColorRes;
+ if (item.isCurrent) {
+ iconColorRes = R.color.qs_user_switcher_selected_avatar_icon_color;
+ } else if (!item.isSwitchToEnabled) {
+ iconColorRes = R.color.GM2_grey_600;
+ } else {
+ iconColorRes = R.color.qs_user_switcher_avatar_icon_color;
+ }
icon.setTint(context.getResources().getColor(iconColorRes, context.getTheme()));
int bgRes = item.isCurrent ? R.drawable.bg_avatar_selected : R.drawable.qs_bg_avatar;
diff --git a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java
index b272b60f3593..8a012b8b06f1 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java
@@ -64,13 +64,16 @@ import com.android.internal.accessibility.dialog.AccessibilityButtonChooserActiv
import com.android.internal.policy.ScreenDecorationsUtils;
import com.android.internal.util.ScreenshotHelper;
import com.android.systemui.Dumpable;
+import com.android.systemui.broadcast.BroadcastDispatcher;
import com.android.systemui.model.SysUiState;
import com.android.systemui.pip.PipAnimationController;
import com.android.systemui.pip.PipUI;
import com.android.systemui.recents.OverviewProxyService.OverviewProxyListener;
+import com.android.systemui.settings.CurrentUserTracker;
import com.android.systemui.shared.recents.IOverviewProxy;
import com.android.systemui.shared.recents.IPinnedStackAnimationListener;
import com.android.systemui.shared.recents.ISystemUiProxy;
+import com.android.systemui.shared.recents.model.Task;
import com.android.systemui.shared.system.ActivityManagerWrapper;
import com.android.systemui.shared.system.QuickStepContract;
import com.android.systemui.stackdivider.Divider;
@@ -83,8 +86,6 @@ import com.android.systemui.statusbar.phone.NotificationShadeWindowController;
import com.android.systemui.statusbar.phone.StatusBar;
import com.android.systemui.statusbar.phone.StatusBarWindowCallback;
import com.android.systemui.statusbar.policy.CallbackController;
-import com.android.systemui.statusbar.policy.DeviceProvisionedController;
-import com.android.systemui.statusbar.policy.DeviceProvisionedController.DeviceProvisionedListener;
import java.io.FileDescriptor;
import java.io.PrintWriter;
@@ -101,8 +102,9 @@ import dagger.Lazy;
* Class to send information from overview to launcher with a binder.
*/
@Singleton
-public class OverviewProxyService implements CallbackController<OverviewProxyListener>,
- NavigationModeController.ModeChangedListener, Dumpable {
+public class OverviewProxyService extends CurrentUserTracker implements
+ CallbackController<OverviewProxyListener>, NavigationModeController.ModeChangedListener,
+ Dumpable {
private static final String ACTION_QUICKSTEP = "android.intent.action.QUICKSTEP_SERVICE";
@@ -123,7 +125,6 @@ public class OverviewProxyService implements CallbackController<OverviewProxyLis
private final NotificationShadeWindowController mStatusBarWinController;
private final Runnable mConnectionRunnable = this::internalConnectToCurrentUser;
private final ComponentName mRecentsComponentName;
- private final DeviceProvisionedController mDeviceProvisionedController;
private final List<OverviewProxyListener> mConnectionCallbacks = new ArrayList<>();
private final Intent mQuickStepIntent;
private final ScreenshotHelper mScreenshotHelper;
@@ -383,8 +384,7 @@ public class OverviewProxyService implements CallbackController<OverviewProxyLis
@Override
public void handleImageAsScreenshot(Bitmap screenImage, Rect locationInScreen,
Insets visibleInsets, int taskId) {
- mScreenshotHelper.provideScreenshot(screenImage, locationInScreen, visibleInsets,
- taskId, SCREENSHOT_OVERVIEW, mHandler, null);
+ // Deprecated
}
@Override
@@ -434,6 +434,21 @@ public class OverviewProxyService implements CallbackController<OverviewProxyLis
}
}
+ @Override
+ public void handleImageBundleAsScreenshot(Bundle screenImageBundle, Rect locationInScreen,
+ Insets visibleInsets, Task.TaskKey task) {
+ mScreenshotHelper.provideScreenshot(
+ screenImageBundle,
+ locationInScreen,
+ visibleInsets,
+ task.id,
+ task.userId,
+ task.sourceComponent,
+ SCREENSHOT_OVERVIEW,
+ mHandler,
+ null);
+ }
+
private boolean verifyCaller(String reason) {
final int callerId = Binder.getCallingUserHandle().getIdentifier();
if (callerId != mCurrentBoundedUserId) {
@@ -480,7 +495,7 @@ public class OverviewProxyService implements CallbackController<OverviewProxyLis
return;
}
- mCurrentBoundedUserId = mDeviceProvisionedController.getCurrentUser();
+ mCurrentBoundedUserId = getCurrentUserId();
mOverviewProxy = IOverviewProxy.Stub.asInterface(service);
Bundle params = new Bundle();
@@ -523,22 +538,6 @@ public class OverviewProxyService implements CallbackController<OverviewProxyLis
}
};
- private final DeviceProvisionedListener mDeviceProvisionedCallback =
- new DeviceProvisionedListener() {
- @Override
- public void onUserSetupChanged() {
- if (mDeviceProvisionedController.isCurrentUserSetup()) {
- internalConnectToCurrentUser();
- }
- }
-
- @Override
- public void onUserSwitched() {
- mConnectionBackoffAttempts = 0;
- internalConnectToCurrentUser();
- }
- };
-
private final StatusBarWindowCallback mStatusBarWindowCallback = this::onStatusBarStateChanged;
// This is the death handler for the binder from the launcher service
@@ -548,18 +547,18 @@ public class OverviewProxyService implements CallbackController<OverviewProxyLis
@SuppressWarnings("OptionalUsedAsFieldOrParameterType")
@Inject
public OverviewProxyService(Context context, CommandQueue commandQueue,
- DeviceProvisionedController provisionController,
NavigationBarController navBarController, NavigationModeController navModeController,
NotificationShadeWindowController statusBarWinController, SysUiState sysUiState,
PipUI pipUI, Optional<Divider> dividerOptional,
- Optional<Lazy<StatusBar>> statusBarOptionalLazy) {
+ Optional<Lazy<StatusBar>> statusBarOptionalLazy,
+ BroadcastDispatcher broadcastDispatcher) {
+ super(broadcastDispatcher);
mContext = context;
mPipUI = pipUI;
mStatusBarOptionalLazy = statusBarOptionalLazy;
mHandler = new Handler();
mNavBarController = navBarController;
mStatusBarWinController = statusBarWinController;
- mDeviceProvisionedController = provisionController;
mConnectionBackoffAttempts = 0;
mDividerOptional = dividerOptional;
mRecentsComponentName = ComponentName.unflattenFromString(context.getString(
@@ -578,10 +577,6 @@ public class OverviewProxyService implements CallbackController<OverviewProxyLis
// Listen for nav bar mode changes
mNavBarMode = navModeController.addListener(this);
- // Listen for device provisioned/user setup
- updateEnabledState();
- mDeviceProvisionedController.addCallback(mDeviceProvisionedCallback);
-
// Listen for launcher package changes
IntentFilter filter = new IntentFilter(Intent.ACTION_PACKAGE_ADDED);
filter.addDataScheme("package");
@@ -602,6 +597,19 @@ public class OverviewProxyService implements CallbackController<OverviewProxyLis
.commitUpdate(mContext.getDisplayId());
}
});
+
+ // Listen for user setup
+ startTracking();
+
+ // Connect to the service
+ updateEnabledState();
+ startConnectionToCurrentUser();
+ }
+
+ @Override
+ public void onUserSwitched(int newUserId) {
+ mConnectionBackoffAttempts = 0;
+ internalConnectToCurrentUser();
}
public void notifyBackAction(boolean completed, int downX, int downY, boolean isButton,
@@ -709,10 +717,8 @@ public class OverviewProxyService implements CallbackController<OverviewProxyLis
disconnectFromLauncherService();
// If user has not setup yet or already connected, do not try to connect
- if (!mDeviceProvisionedController.isCurrentUserSetup() || !isEnabled()) {
- Log.v(TAG_OPS, "Cannot attempt connection, is setup "
- + mDeviceProvisionedController.isCurrentUserSetup() + ", is enabled "
- + isEnabled());
+ if (!isEnabled()) {
+ Log.v(TAG_OPS, "Cannot attempt connection, is enabled " + isEnabled());
return;
}
mHandler.removeCallbacks(mConnectionRunnable);
@@ -722,7 +728,7 @@ public class OverviewProxyService implements CallbackController<OverviewProxyLis
mBound = mContext.bindServiceAsUser(launcherServiceIntent,
mOverviewServiceConnection,
Context.BIND_AUTO_CREATE | Context.BIND_FOREGROUND_SERVICE_WHILE_AWAKE,
- UserHandle.of(mDeviceProvisionedController.getCurrentUser()));
+ UserHandle.of(getCurrentUserId()));
} catch (SecurityException e) {
Log.e(TAG_OPS, "Unable to bind because of security error", e);
}
@@ -881,8 +887,6 @@ public class OverviewProxyService implements CallbackController<OverviewProxyLis
pw.println(TAG_OPS + " state:");
pw.print(" recentsComponentName="); pw.println(mRecentsComponentName);
pw.print(" isConnected="); pw.println(mOverviewProxy != null);
- pw.print(" isCurrentUserSetup="); pw.println(mDeviceProvisionedController
- .isCurrentUserSetup());
pw.print(" connectionBackoffAttempts="); pw.println(mConnectionBackoffAttempts);
pw.print(" quickStepIntent="); pw.println(mQuickStepIntent);
diff --git a/packages/SystemUI/src/com/android/systemui/screenrecord/Events.java b/packages/SystemUI/src/com/android/systemui/screenrecord/Events.java
new file mode 100644
index 000000000000..9dede4848914
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/screenrecord/Events.java
@@ -0,0 +1,45 @@
+/*
+ * 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.screenrecord;
+
+import com.android.internal.logging.UiEvent;
+import com.android.internal.logging.UiEventLogger;
+
+/**
+ * Events related to the SystemUI screen recorder
+ */
+public class Events {
+
+ public enum ScreenRecordEvent implements UiEventLogger.UiEventEnum {
+ @UiEvent(doc = "Screen recording was started")
+ SCREEN_RECORD_START(299),
+ @UiEvent(doc = "Screen recording was stopped from the quick settings tile")
+ SCREEN_RECORD_END_QS_TILE(300),
+ @UiEvent(doc = "Screen recording was stopped from the notification")
+ SCREEN_RECORD_END_NOTIFICATION(301);
+
+ private final int mId;
+ ScreenRecordEvent(int id) {
+ mId = id;
+ }
+
+ @Override
+ public int getId() {
+ return mId;
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/screenrecord/RecordingService.java b/packages/SystemUI/src/com/android/systemui/screenrecord/RecordingService.java
index 960c50129a56..f2e8599536ca 100644
--- a/packages/SystemUI/src/com/android/systemui/screenrecord/RecordingService.java
+++ b/packages/SystemUI/src/com/android/systemui/screenrecord/RecordingService.java
@@ -33,11 +33,11 @@ import android.os.Bundle;
import android.os.IBinder;
import android.os.RemoteException;
import android.provider.Settings;
-import android.util.DisplayMetrics;
import android.util.Log;
-import android.util.Size;
import android.widget.Toast;
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.logging.UiEventLogger;
import com.android.systemui.R;
import com.android.systemui.dagger.qualifiers.LongRunning;
@@ -65,22 +65,28 @@ public class RecordingService extends Service implements MediaRecorder.OnInfoLis
private static final String ACTION_START = "com.android.systemui.screenrecord.START";
private static final String ACTION_STOP = "com.android.systemui.screenrecord.STOP";
+ private static final String ACTION_STOP_NOTIF =
+ "com.android.systemui.screenrecord.STOP_FROM_NOTIF";
private static final String ACTION_SHARE = "com.android.systemui.screenrecord.SHARE";
private static final String ACTION_DELETE = "com.android.systemui.screenrecord.DELETE";
private final RecordingController mController;
- private Notification.Builder mRecordingNotificationBuilder;
private ScreenRecordingAudioSource mAudioSource;
private boolean mShowTaps;
private boolean mOriginalShowTaps;
private ScreenMediaRecorder mRecorder;
private final Executor mLongExecutor;
+ private final UiEventLogger mUiEventLogger;
+ private final NotificationManager mNotificationManager;
@Inject
- public RecordingService(RecordingController controller, @LongRunning Executor executor) {
+ public RecordingService(RecordingController controller, @LongRunning Executor executor,
+ UiEventLogger uiEventLogger, NotificationManager notificationManager) {
mController = controller;
mLongExecutor = executor;
+ mUiEventLogger = uiEventLogger;
+ mNotificationManager = notificationManager;
}
/**
@@ -112,9 +118,6 @@ public class RecordingService extends Service implements MediaRecorder.OnInfoLis
String action = intent.getAction();
Log.d(TAG, "onStartCommand " + action);
- NotificationManager notificationManager =
- (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
-
switch (action) {
case ACTION_START:
mAudioSource = ScreenRecordingAudioSource
@@ -137,10 +140,16 @@ public class RecordingService extends Service implements MediaRecorder.OnInfoLis
startRecording();
break;
+ case ACTION_STOP_NOTIF:
case ACTION_STOP:
+ // only difference for actions is the log event
+ if (ACTION_STOP_NOTIF.equals(action)) {
+ mUiEventLogger.log(Events.ScreenRecordEvent.SCREEN_RECORD_END_NOTIFICATION);
+ } else {
+ mUiEventLogger.log(Events.ScreenRecordEvent.SCREEN_RECORD_END_QS_TILE);
+ }
stopRecording();
- notificationManager.cancel(NOTIFICATION_RECORDING_ID);
- saveRecording(notificationManager);
+ mNotificationManager.cancel(NOTIFICATION_RECORDING_ID);
stopSelf();
break;
@@ -156,7 +165,7 @@ public class RecordingService extends Service implements MediaRecorder.OnInfoLis
sendBroadcast(new Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS));
// Remove notification
- notificationManager.cancel(NOTIFICATION_VIEW_ID);
+ mNotificationManager.cancel(NOTIFICATION_VIEW_ID);
startActivity(Intent.createChooser(shareIntent, shareLabel)
.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK));
@@ -175,7 +184,7 @@ public class RecordingService extends Service implements MediaRecorder.OnInfoLis
Toast.LENGTH_LONG).show();
// Remove notification
- notificationManager.cancel(NOTIFICATION_VIEW_ID);
+ mNotificationManager.cancel(NOTIFICATION_VIEW_ID);
Log.d(TAG, "Deleted recording " + uri);
break;
}
@@ -192,14 +201,20 @@ public class RecordingService extends Service implements MediaRecorder.OnInfoLis
super.onCreate();
}
+ @VisibleForTesting
+ protected ScreenMediaRecorder getRecorder() {
+ return mRecorder;
+ }
+
/**
* Begin the recording session
*/
private void startRecording() {
try {
- mRecorder.start();
+ getRecorder().start();
mController.updateState(true);
createRecordingNotification();
+ mUiEventLogger.log(Events.ScreenRecordEvent.SCREEN_RECORD_START);
} catch (IOException | RemoteException e) {
Toast.makeText(this,
R.string.screenrecord_start_error, Toast.LENGTH_LONG)
@@ -208,7 +223,8 @@ public class RecordingService extends Service implements MediaRecorder.OnInfoLis
}
}
- private void createRecordingNotification() {
+ @VisibleForTesting
+ protected void createRecordingNotification() {
Resources res = getResources();
NotificationChannel channel = new NotificationChannel(
CHANNEL_ID,
@@ -216,19 +232,19 @@ public class RecordingService extends Service implements MediaRecorder.OnInfoLis
NotificationManager.IMPORTANCE_DEFAULT);
channel.setDescription(getString(R.string.screenrecord_channel_description));
channel.enableVibration(true);
- NotificationManager notificationManager =
- (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
- notificationManager.createNotificationChannel(channel);
+ mNotificationManager.createNotificationChannel(channel);
Bundle extras = new Bundle();
extras.putString(Notification.EXTRA_SUBSTITUTE_APP_NAME,
res.getString(R.string.screenrecord_name));
String notificationTitle = mAudioSource == ScreenRecordingAudioSource.NONE
- ? res.getString(R.string.screenrecord_ongoing_screen_and_audio)
- : res.getString(R.string.screenrecord_ongoing_screen_only);
+ ? res.getString(R.string.screenrecord_ongoing_screen_only)
+ : res.getString(R.string.screenrecord_ongoing_screen_and_audio);
+
- mRecordingNotificationBuilder = new Notification.Builder(this, CHANNEL_ID)
+ Intent stopIntent = getNotificationIntent(this);
+ Notification.Builder builder = new Notification.Builder(this, CHANNEL_ID)
.setSmallIcon(R.drawable.ic_screenrecord)
.setContentTitle(notificationTitle)
.setContentText(getResources().getString(R.string.screenrecord_stop_text))
@@ -237,17 +253,29 @@ public class RecordingService extends Service implements MediaRecorder.OnInfoLis
.setColor(getResources().getColor(R.color.GM2_red_700))
.setOngoing(true)
.setContentIntent(
- PendingIntent.getService(
- this, REQUEST_CODE, getStopIntent(this),
+ PendingIntent.getService(this, REQUEST_CODE, stopIntent,
PendingIntent.FLAG_UPDATE_CURRENT))
.addExtras(extras);
- notificationManager.notify(NOTIFICATION_RECORDING_ID,
- mRecordingNotificationBuilder.build());
- Notification notification = mRecordingNotificationBuilder.build();
- startForeground(NOTIFICATION_RECORDING_ID, notification);
+ startForeground(NOTIFICATION_RECORDING_ID, builder.build());
+ }
+
+ @VisibleForTesting
+ protected Notification createProcessingNotification() {
+ Resources res = getApplicationContext().getResources();
+ String notificationTitle = mAudioSource == ScreenRecordingAudioSource.NONE
+ ? res.getString(R.string.screenrecord_ongoing_screen_only)
+ : res.getString(R.string.screenrecord_ongoing_screen_and_audio);
+ Notification.Builder builder = new Notification.Builder(getApplicationContext(), CHANNEL_ID)
+ .setContentTitle(notificationTitle)
+ .setContentText(
+ getResources().getString(R.string.screenrecord_background_processing_label))
+ .setSmallIcon(R.drawable.ic_screenrecord);
+ return builder.build();
}
- private Notification createSaveNotification(Uri uri) {
+ @VisibleForTesting
+ protected Notification createSaveNotification(ScreenMediaRecorder.SavedRecording recording) {
+ Uri uri = recording.getUri();
Intent viewIntent = new Intent(Intent.ACTION_VIEW)
.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_GRANT_READ_URI_PERMISSION)
.setDataAndType(uri, "video/mp4");
@@ -290,16 +318,7 @@ public class RecordingService extends Service implements MediaRecorder.OnInfoLis
.addExtras(extras);
// Add thumbnail if available
- Bitmap thumbnailBitmap = null;
- try {
- ContentResolver resolver = getContentResolver();
- DisplayMetrics metrics = getResources().getDisplayMetrics();
- Size size = new Size(metrics.widthPixels, metrics.heightPixels / 2);
- thumbnailBitmap = resolver.loadThumbnail(uri, size, null);
- } catch (IOException e) {
- Log.e(TAG, "Error creating thumbnail: " + e.getMessage());
- e.printStackTrace();
- }
+ Bitmap thumbnailBitmap = recording.getThumbnail();
if (thumbnailBitmap != null) {
Notification.BigPictureStyle pictureStyle = new Notification.BigPictureStyle()
.bigPicture(thumbnailBitmap)
@@ -311,44 +330,39 @@ public class RecordingService extends Service implements MediaRecorder.OnInfoLis
private void stopRecording() {
setTapsVisible(mOriginalShowTaps);
- mRecorder.end();
+ if (getRecorder() != null) {
+ getRecorder().end();
+ saveRecording();
+ } else {
+ Log.e(TAG, "stopRecording called, but recorder was null");
+ }
mController.updateState(false);
}
- private void saveRecording(NotificationManager notificationManager) {
- Resources res = getApplicationContext().getResources();
- String notificationTitle = mAudioSource == ScreenRecordingAudioSource.NONE
- ? res.getString(R.string.screenrecord_ongoing_screen_only)
- : res.getString(R.string.screenrecord_ongoing_screen_and_audio);
- Notification.Builder builder = new Notification.Builder(getApplicationContext(), CHANNEL_ID)
- .setContentTitle(notificationTitle)
- .setContentText(
- getResources().getString(R.string.screenrecord_background_processing_label))
- .setSmallIcon(R.drawable.ic_screenrecord);
- notificationManager.notify(NOTIFICATION_PROCESSING_ID, builder.build());
+ private void saveRecording() {
+ mNotificationManager.notify(NOTIFICATION_PROCESSING_ID, createProcessingNotification());
mLongExecutor.execute(() -> {
try {
Log.d(TAG, "saving recording");
- Notification notification = createSaveNotification(mRecorder.save());
+ Notification notification = createSaveNotification(getRecorder().save());
if (!mController.isRecording()) {
Log.d(TAG, "showing saved notification");
- notificationManager.notify(NOTIFICATION_VIEW_ID, notification);
+ mNotificationManager.notify(NOTIFICATION_VIEW_ID, notification);
}
} catch (IOException e) {
Log.e(TAG, "Error saving screen recording: " + e.getMessage());
Toast.makeText(this, R.string.screenrecord_delete_error, Toast.LENGTH_LONG)
.show();
} finally {
- notificationManager.cancel(NOTIFICATION_PROCESSING_ID);
+ mNotificationManager.cancel(NOTIFICATION_PROCESSING_ID);
}
});
}
private void setTapsVisible(boolean turnOn) {
int value = turnOn ? 1 : 0;
- Settings.System.putInt(getApplicationContext().getContentResolver(),
- Settings.System.SHOW_TOUCHES, value);
+ Settings.System.putInt(getContentResolver(), Settings.System.SHOW_TOUCHES, value);
}
/**
@@ -360,6 +374,15 @@ public class RecordingService extends Service implements MediaRecorder.OnInfoLis
return new Intent(context, RecordingService.class).setAction(ACTION_STOP);
}
+ /**
+ * Get the recording notification content intent
+ * @param context
+ * @return
+ */
+ protected static Intent getNotificationIntent(Context context) {
+ return new Intent(context, RecordingService.class).setAction(ACTION_STOP_NOTIF);
+ }
+
private static Intent getShareIntent(Context context, String path) {
return new Intent(context, RecordingService.class).setAction(ACTION_SHARE)
.putExtra(EXTRA_PATH, path);
diff --git a/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenInternalAudioRecorder.java b/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenInternalAudioRecorder.java
index 752f4fddf24b..edbc3cfdece5 100644
--- a/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenInternalAudioRecorder.java
+++ b/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenInternalAudioRecorder.java
@@ -38,6 +38,7 @@ import java.nio.ByteBuffer;
public class ScreenInternalAudioRecorder {
private static String TAG = "ScreenAudioRecorder";
private static final int TIMEOUT = 500;
+ private static final float MIC_VOLUME_SCALE = 1.4f;
private final Context mContext;
private AudioRecord mAudioRecord;
private AudioRecord mAudioRecordMic;
@@ -148,6 +149,10 @@ public class ScreenInternalAudioRecorder {
readShortsInternal = mAudioRecord.read(bufferInternal, 0,
bufferInternal.length);
readShortsMic = mAudioRecordMic.read(bufferMic, 0, bufferMic.length);
+
+ // modify the volume
+ bufferMic = scaleValues(bufferMic,
+ readShortsMic, MIC_VOLUME_SCALE);
readBytes = Math.min(readShortsInternal, readShortsMic) * 2;
buffer = addAndConvertBuffers(bufferInternal, readShortsInternal, bufferMic,
readShortsMic);
@@ -168,6 +173,19 @@ public class ScreenInternalAudioRecorder {
});
}
+ private short[] scaleValues(short[] buff, int len, float scale) {
+ for (int i = 0; i < len; i++) {
+ int oldValue = buff[i];
+ int newValue = (int) (buff[i] * scale);
+ if (newValue > Short.MAX_VALUE) {
+ newValue = Short.MAX_VALUE;
+ } else if (newValue < Short.MIN_VALUE) {
+ newValue = Short.MIN_VALUE;
+ }
+ buff[i] = (short) (newValue);
+ }
+ return buff;
+ }
private byte[] addAndConvertBuffers(short[] a1, int a1Limit, short[] a2, int a2Limit) {
int size = Math.max(a1Limit, a2Limit);
if (size < 0) return new byte[0];
diff --git a/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenMediaRecorder.java b/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenMediaRecorder.java
index c967648c544e..1c7d987afff2 100644
--- a/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenMediaRecorder.java
+++ b/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenMediaRecorder.java
@@ -22,13 +22,17 @@ import static com.android.systemui.screenrecord.ScreenRecordingAudioSource.INTER
import static com.android.systemui.screenrecord.ScreenRecordingAudioSource.MIC;
import static com.android.systemui.screenrecord.ScreenRecordingAudioSource.MIC_AND_INTERNAL;
+import android.annotation.Nullable;
import android.content.ContentResolver;
import android.content.ContentValues;
import android.content.Context;
+import android.graphics.Bitmap;
import android.hardware.display.DisplayManager;
import android.hardware.display.VirtualDisplay;
+import android.media.MediaCodecInfo;
import android.media.MediaMuxer;
import android.media.MediaRecorder;
+import android.media.ThumbnailUtils;
import android.media.projection.IMediaProjection;
import android.media.projection.IMediaProjectionManager;
import android.media.projection.MediaProjection;
@@ -40,6 +44,7 @@ import android.os.ServiceManager;
import android.provider.MediaStore;
import android.util.DisplayMetrics;
import android.util.Log;
+import android.util.Size;
import android.view.Surface;
import android.view.WindowManager;
@@ -55,9 +60,9 @@ import java.util.Date;
*/
public class ScreenMediaRecorder {
private static final int TOTAL_NUM_TRACKS = 1;
- private static final int VIDEO_BIT_RATE = 10000000;
private static final int VIDEO_FRAME_RATE = 30;
- private static final int AUDIO_BIT_RATE = 16;
+ private static final int VIDEO_FRAME_RATE_TO_RESOLUTION_RATIO = 6;
+ private static final int AUDIO_BIT_RATE = 196000;
private static final int AUDIO_SAMPLE_RATE = 44100;
private static final int MAX_DURATION_MS = 60 * 60 * 1000;
private static final long MAX_FILESIZE_BYTES = 5000000000L;
@@ -108,7 +113,7 @@ public class ScreenMediaRecorder {
// Set up audio source
if (mAudioSource == MIC) {
- mMediaRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
+ mMediaRecorder.setAudioSource(MediaRecorder.AudioSource.DEFAULT);
}
mMediaRecorder.setVideoSource(MediaRecorder.VideoSource.SURFACE);
@@ -121,10 +126,16 @@ public class ScreenMediaRecorder {
wm.getDefaultDisplay().getRealMetrics(metrics);
int screenWidth = metrics.widthPixels;
int screenHeight = metrics.heightPixels;
+ int refereshRate = (int) wm.getDefaultDisplay().getRefreshRate();
+ int vidBitRate = screenHeight * screenWidth * refereshRate / VIDEO_FRAME_RATE
+ * VIDEO_FRAME_RATE_TO_RESOLUTION_RATIO;
mMediaRecorder.setVideoEncoder(MediaRecorder.VideoEncoder.H264);
+ mMediaRecorder.setVideoEncodingProfileLevel(
+ MediaCodecInfo.CodecProfileLevel.AVCProfileHigh,
+ MediaCodecInfo.CodecProfileLevel.AVCLevel42);
mMediaRecorder.setVideoSize(screenWidth, screenHeight);
- mMediaRecorder.setVideoFrameRate(VIDEO_FRAME_RATE);
- mMediaRecorder.setVideoEncodingBitRate(VIDEO_BIT_RATE);
+ mMediaRecorder.setVideoFrameRate(refereshRate);
+ mMediaRecorder.setVideoEncodingBitRate(vidBitRate);
mMediaRecorder.setMaxDuration(MAX_DURATION_MS);
mMediaRecorder.setMaxFileSize(MAX_FILESIZE_BYTES);
@@ -203,7 +214,7 @@ public class ScreenMediaRecorder {
/**
* Store recorded video
*/
- Uri save() throws IOException {
+ protected SavedRecording save() throws IOException {
String fileName = new SimpleDateFormat("'screen-'yyyyMMdd-HHmmss'.mp4'")
.format(new Date());
@@ -241,8 +252,38 @@ public class ScreenMediaRecorder {
OutputStream os = resolver.openOutputStream(itemUri, "w");
Files.copy(mTempVideoFile.toPath(), os);
os.close();
- mTempVideoFile.delete();
if (mTempAudioFile != null) mTempAudioFile.delete();
- return itemUri;
+ DisplayMetrics metrics = mContext.getResources().getDisplayMetrics();
+ Size size = new Size(metrics.widthPixels, metrics.heightPixels);
+ SavedRecording recording = new SavedRecording(itemUri, mTempVideoFile, size);
+ mTempVideoFile.delete();
+ return recording;
+ }
+
+ /**
+ * Object representing the recording
+ */
+ public class SavedRecording {
+
+ private Uri mUri;
+ private Bitmap mThumbnailBitmap;
+
+ protected SavedRecording(Uri uri, File file, Size thumbnailSize) {
+ mUri = uri;
+ try {
+ mThumbnailBitmap = ThumbnailUtils.createVideoThumbnail(
+ file, thumbnailSize, null);
+ } catch (IOException e) {
+ Log.e(TAG, "Error creating thumbnail", e);
+ }
+ }
+
+ public Uri getUri() {
+ return mUri;
+ }
+
+ public @Nullable Bitmap getThumbnail() {
+ return mThumbnailBitmap;
+ }
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenRecordDialog.java b/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenRecordDialog.java
index abd7e7159260..d057a8a43c43 100644
--- a/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenRecordDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenRecordDialog.java
@@ -24,12 +24,9 @@ import static com.android.systemui.screenrecord.ScreenRecordingAudioSource.NONE;
import android.app.Activity;
import android.app.PendingIntent;
import android.os.Bundle;
-import android.util.Log;
import android.view.Gravity;
-import android.view.View;
import android.view.ViewGroup;
import android.view.Window;
-import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.Spinner;
@@ -88,8 +85,8 @@ public class ScreenRecordDialog extends Activity {
});
mModes = new ArrayList<>();
- mModes.add(INTERNAL);
mModes.add(MIC);
+ mModes.add(INTERNAL);
mModes.add(MIC_AND_INTERNAL);
mAudioSwitch = findViewById(R.id.screenrecord_audio_switch);
diff --git a/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenRecordingAdapter.java b/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenRecordingAdapter.java
index 2e0e746594b4..3e78489e5707 100644
--- a/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenRecordingAdapter.java
+++ b/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenRecordingAdapter.java
@@ -88,12 +88,6 @@ public class ScreenRecordingAdapter extends ArrayAdapter<ScreenRecordingAudioSou
return layout;
}
- private void setDescription(LinearLayout layout, int description) {
- if (description != Resources.ID_NULL) {
- ((TextView) layout.getChildAt(1)).setText(description);
- }
- }
-
@Override
public View getDropDownView(int position, View convertView, ViewGroup parent) {
switch (getItem(position)) {
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java b/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java
index a9d3772a0fdb..57436bc9e675 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java
@@ -35,18 +35,25 @@ import android.app.ActivityOptions;
import android.app.Notification;
import android.app.PendingIntent;
import android.content.BroadcastReceiver;
+import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.graphics.Bitmap;
+import android.graphics.Color;
import android.graphics.Insets;
import android.graphics.Outline;
import android.graphics.PixelFormat;
import android.graphics.PointF;
import android.graphics.Rect;
import android.graphics.Region;
+import android.graphics.drawable.BitmapDrawable;
+import android.graphics.drawable.ColorDrawable;
+import android.graphics.drawable.Drawable;
import android.graphics.drawable.Icon;
+import android.graphics.drawable.InsetDrawable;
+import android.graphics.drawable.LayerDrawable;
import android.media.MediaActionSound;
import android.net.Uri;
import android.os.Handler;
@@ -207,6 +214,7 @@ public class GlobalScreenshot implements ViewTreeObserver.OnComputeInternalInset
private Animator mScreenshotAnimation;
private Runnable mOnCompleteRunnable;
private Animator mDismissAnimation;
+ private SavedImageData mImageData;
private boolean mInDarkMode = false;
private boolean mDirectionLTR = true;
private boolean mOrientationPortrait = true;
@@ -225,6 +233,9 @@ public class GlobalScreenshot implements ViewTreeObserver.OnComputeInternalInset
switch (msg.what) {
case MESSAGE_CORNER_TIMEOUT:
mUiEventLogger.log(ScreenshotEvent.SCREENSHOT_INTERACTION_TIMEOUT);
+ if (mImageData != null) {
+ mNotificationsController.showSilentScreenshotNotification(mImageData);
+ }
GlobalScreenshot.this.dismissScreenshot("timeout", false);
mOnCompleteRunnable.run();
break;
@@ -395,6 +406,9 @@ public class GlobalScreenshot implements ViewTreeObserver.OnComputeInternalInset
mDismissButton = mScreenshotLayout.findViewById(R.id.global_screenshot_dismiss_button);
mDismissButton.setOnClickListener(view -> {
mUiEventLogger.log(ScreenshotEvent.SCREENSHOT_EXPLICIT_DISMISSAL);
+ if (mImageData != null) {
+ mNotificationsController.showSilentScreenshotNotification(mImageData);
+ }
dismissScreenshot("dismiss_button", false);
mOnCompleteRunnable.run();
});
@@ -435,6 +449,10 @@ public class GlobalScreenshot implements ViewTreeObserver.OnComputeInternalInset
});
}
+ mImageData = null; // make sure we clear the current stored data
+ mNotificationsController.reset();
+ mNotificationsController.setImage(mScreenBitmap);
+
mSaveInBgTask = new SaveImageInBackgroundTask(mContext, data);
mSaveInBgTask.execute();
}
@@ -448,10 +466,12 @@ public class GlobalScreenshot implements ViewTreeObserver.OnComputeInternalInset
int rot = mDisplay.getRotation();
int width = crop.width();
int height = crop.height();
- takeScreenshot(SurfaceControl.screenshot(crop, width, height, rot), finisher, screenRect);
+ takeScreenshot(SurfaceControl.screenshot(crop, width, height, rot), finisher, screenRect,
+ Insets.NONE, true);
}
- private void takeScreenshot(Bitmap screenshot, Consumer<Uri> finisher, Rect screenRect) {
+ private void takeScreenshot(Bitmap screenshot, Consumer<Uri> finisher, Rect screenRect,
+ Insets screenInsets, boolean showFlash) {
dismissScreenshot("new screenshot requested", true);
mScreenBitmap = screenshot;
@@ -481,7 +501,7 @@ public class GlobalScreenshot implements ViewTreeObserver.OnComputeInternalInset
mDismissAnimation.cancel();
}
// Start the post-screenshot animation
- startAnimation(finisher, mScreenBitmap.getWidth(), mScreenBitmap.getHeight(), screenRect);
+ startAnimation(finisher, screenRect, screenInsets, showFlash);
}
void takeScreenshot(Consumer<Uri> finisher, Runnable onComplete) {
@@ -494,10 +514,18 @@ public class GlobalScreenshot implements ViewTreeObserver.OnComputeInternalInset
}
void handleImageAsScreenshot(Bitmap screenshot, Rect screenshotScreenBounds,
- Insets visibleInsets, int taskId, Consumer<Uri> finisher, Runnable onComplete) {
- // TODO use taskId and visibleInsets
+ Insets visibleInsets, int taskId, int userId, ComponentName topComponent,
+ Consumer<Uri> finisher, Runnable onComplete) {
+ // TODO: use task Id, userId, topComponent for smart handler
+
mOnCompleteRunnable = onComplete;
- takeScreenshot(screenshot, finisher, screenshotScreenBounds);
+ if (aspectRatiosMatch(screenshot, visibleInsets, screenshotScreenBounds)) {
+ takeScreenshot(screenshot, finisher, screenshotScreenBounds, visibleInsets, false);
+ } else {
+ takeScreenshot(screenshot, finisher,
+ new Rect(0, 0, screenshot.getWidth(), screenshot.getHeight()), Insets.NONE,
+ true);
+ }
}
/**
@@ -618,8 +646,9 @@ public class GlobalScreenshot implements ViewTreeObserver.OnComputeInternalInset
}
// Clear any references to the bitmap
- mScreenshotPreview.setImageBitmap(null);
- mScreenshotAnimatedView.setImageBitmap(null);
+ mScreenshotPreview.setImageDrawable(null);
+ mScreenshotAnimatedView.setImageDrawable(null);
+ mScreenshotAnimatedView.setVisibility(View.GONE);
mActionsContainerBackground.setVisibility(View.GONE);
mActionsContainer.setVisibility(View.GONE);
mBackgroundProtection.setAlpha(0f);
@@ -640,6 +669,19 @@ public class GlobalScreenshot implements ViewTreeObserver.OnComputeInternalInset
*/
private void showUiOnActionsReady(SavedImageData imageData) {
logSuccessOnActionsReady(imageData);
+ mImageData = imageData;
+
+ AccessibilityManager accessibilityManager = (AccessibilityManager)
+ mContext.getSystemService(Context.ACCESSIBILITY_SERVICE);
+ long timeoutMs = accessibilityManager.getRecommendedTimeoutMillis(
+ SCREENSHOT_CORNER_DEFAULT_TIMEOUT_MILLIS,
+ AccessibilityManager.FLAG_CONTENT_CONTROLS);
+
+ mScreenshotHandler.removeMessages(MESSAGE_CORNER_TIMEOUT);
+ mScreenshotHandler.sendMessageDelayed(
+ mScreenshotHandler.obtainMessage(MESSAGE_CORNER_TIMEOUT),
+ timeoutMs);
+
if (imageData.uri != null) {
mScreenshotHandler.post(() -> {
if (mScreenshotAnimation != null && mScreenshotAnimation.isRunning()) {
@@ -653,17 +695,6 @@ public class GlobalScreenshot implements ViewTreeObserver.OnComputeInternalInset
} else {
createScreenshotActionsShadeAnimation(imageData).start();
}
-
- AccessibilityManager accessibilityManager = (AccessibilityManager)
- mContext.getSystemService(Context.ACCESSIBILITY_SERVICE);
- long timeoutMs = accessibilityManager.getRecommendedTimeoutMillis(
- SCREENSHOT_CORNER_DEFAULT_TIMEOUT_MILLIS,
- AccessibilityManager.FLAG_CONTENT_CONTROLS);
-
- mScreenshotHandler.removeMessages(MESSAGE_CORNER_TIMEOUT);
- mScreenshotHandler.sendMessageDelayed(
- mScreenshotHandler.obtainMessage(MESSAGE_CORNER_TIMEOUT),
- timeoutMs);
});
}
}
@@ -684,8 +715,9 @@ public class GlobalScreenshot implements ViewTreeObserver.OnComputeInternalInset
/**
* Starts the animation after taking the screenshot
*/
- private void startAnimation(
- final Consumer<Uri> finisher, int bitmapWidth, int bitmapHeight, Rect screenRect) {
+ private void startAnimation(final Consumer<Uri> finisher, Rect screenRect, Insets screenInsets,
+ boolean showFlash) {
+
// If power save is on, show a toast so there is some visual indication that a
// screenshot has been taken.
PowerManager powerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
@@ -697,9 +729,13 @@ public class GlobalScreenshot implements ViewTreeObserver.OnComputeInternalInset
if (!mScreenshotLayout.isAttachedToWindow()) {
mWindowManager.addView(mScreenshotLayout, mWindowLayoutParams);
}
- mScreenshotAnimatedView.setImageBitmap(mScreenBitmap);
- mScreenshotPreview.setImageBitmap(mScreenBitmap);
+ mScreenshotAnimatedView.setImageDrawable(
+ createScreenDrawable(mScreenBitmap, screenInsets));
+ setAnimatedViewSize(screenRect.width(), screenRect.height());
+ // Show when the animation starts
+ mScreenshotAnimatedView.setVisibility(View.GONE);
+ mScreenshotPreview.setImageDrawable(createScreenDrawable(mScreenBitmap, screenInsets));
// make static preview invisible (from gone) so we can query its location on screen
mScreenshotPreview.setVisibility(View.INVISIBLE);
@@ -707,14 +743,14 @@ public class GlobalScreenshot implements ViewTreeObserver.OnComputeInternalInset
mScreenshotLayout.getViewTreeObserver().addOnComputeInternalInsetsListener(this);
mScreenshotAnimation =
- createScreenshotDropInAnimation(bitmapWidth, bitmapHeight, screenRect);
+ createScreenshotDropInAnimation(screenRect, showFlash);
saveScreenshotInWorkerThread(finisher, new ActionsReadyListener() {
- @Override
- void onActionsReady(SavedImageData imageData) {
- showUiOnActionsReady(imageData);
- }
- });
+ @Override
+ void onActionsReady(SavedImageData imageData) {
+ showUiOnActionsReady(imageData);
+ }
+ });
// Play the shutter sound to notify that we've taken a screenshot
mCameraSound.play(MediaActionSound.SHUTTER_CLICK);
@@ -726,20 +762,17 @@ public class GlobalScreenshot implements ViewTreeObserver.OnComputeInternalInset
});
}
- private AnimatorSet createScreenshotDropInAnimation(
- int bitmapWidth, int bitmapHeight, Rect bounds) {
+ private AnimatorSet createScreenshotDropInAnimation(Rect bounds, boolean showFlash) {
Rect previewBounds = new Rect();
mScreenshotPreview.getBoundsOnScreen(previewBounds);
- float cornerScale = mCornerSizeX / (mOrientationPortrait ? bitmapWidth : bitmapHeight);
- float currentScale = bounds.height() / (float) bitmapHeight;
+ float cornerScale =
+ mCornerSizeX / (mOrientationPortrait ? bounds.width() : bounds.height());
+ final float currentScale = 1f;
mScreenshotAnimatedView.setScaleX(currentScale);
mScreenshotAnimatedView.setScaleY(currentScale);
- mScreenshotAnimatedView.setPivotX(0);
- mScreenshotAnimatedView.setPivotY(0);
-
AnimatorSet dropInAnimation = new AnimatorSet();
ValueAnimator flashInAnimator = ValueAnimator.ofFloat(0, 1);
flashInAnimator.setDuration(SCREENSHOT_FLASH_IN_DURATION_MS);
@@ -781,13 +814,13 @@ public class GlobalScreenshot implements ViewTreeObserver.OnComputeInternalInset
if (t < xPositionPct) {
float xCenter = MathUtils.lerp(startPos.x, finalPos.x,
mFastOutSlowIn.getInterpolation(t / xPositionPct));
- mScreenshotAnimatedView.setX(xCenter - bitmapWidth * currentScaleX / 2f);
+ mScreenshotAnimatedView.setX(xCenter - bounds.width() * currentScaleX / 2f);
} else {
- mScreenshotAnimatedView.setX(finalPos.x - bitmapWidth * currentScaleX / 2f);
+ mScreenshotAnimatedView.setX(finalPos.x - bounds.width() * currentScaleX / 2f);
}
float yCenter = MathUtils.lerp(
startPos.y, finalPos.y, mFastOutSlowIn.getInterpolation(t));
- mScreenshotAnimatedView.setY(yCenter - bitmapHeight * currentScaleY / 2f);
+ mScreenshotAnimatedView.setY(yCenter - bounds.height() * currentScaleY / 2f);
});
toCorner.addListener(new AnimatorListenerAdapter() {
@@ -801,8 +834,12 @@ public class GlobalScreenshot implements ViewTreeObserver.OnComputeInternalInset
mScreenshotFlash.setAlpha(0f);
mScreenshotFlash.setVisibility(View.VISIBLE);
- dropInAnimation.play(flashOutAnimator).after(flashInAnimator);
- dropInAnimation.play(flashOutAnimator).with(toCorner);
+ if (showFlash) {
+ dropInAnimation.play(flashOutAnimator).after(flashInAnimator);
+ dropInAnimation.play(flashOutAnimator).with(toCorner);
+ } else {
+ dropInAnimation.play(toCorner);
+ }
dropInAnimation.addListener(new AnimatorListenerAdapter() {
@Override
@@ -968,6 +1005,71 @@ public class GlobalScreenshot implements ViewTreeObserver.OnComputeInternalInset
return animSet;
}
+ private void setAnimatedViewSize(int width, int height) {
+ ViewGroup.LayoutParams layoutParams = mScreenshotAnimatedView.getLayoutParams();
+ layoutParams.width = width;
+ layoutParams.height = height;
+ mScreenshotAnimatedView.setLayoutParams(layoutParams);
+ }
+
+ /** Does the aspect ratio of the bitmap with insets removed match the bounds. */
+ private boolean aspectRatiosMatch(Bitmap bitmap, Insets bitmapInsets, Rect screenBounds) {
+ int insettedWidth = bitmap.getWidth() - bitmapInsets.left - bitmapInsets.right;
+ int insettedHeight = bitmap.getHeight() - bitmapInsets.top - bitmapInsets.bottom;
+
+ if (insettedHeight == 0 || insettedWidth == 0 || bitmap.getWidth() == 0
+ || bitmap.getHeight() == 0) {
+ Log.e(TAG, String.format(
+ "Provided bitmap and insets create degenerate region: %dx%d %s",
+ bitmap.getWidth(), bitmap.getHeight(), bitmapInsets));
+ return false;
+ }
+
+ float insettedBitmapAspect = ((float) insettedWidth) / insettedHeight;
+ float boundsAspect = ((float) screenBounds.width()) / screenBounds.height();
+
+ boolean matchWithinTolerance = Math.abs(insettedBitmapAspect - boundsAspect) < 0.1f;
+ if (!matchWithinTolerance) {
+ Log.d(TAG, String.format("aspectRatiosMatch: don't match bitmap: %f, bounds: %f",
+ insettedBitmapAspect, boundsAspect));
+ }
+
+ return matchWithinTolerance;
+ }
+
+ /**
+ * Create a drawable using the size of the bitmap and insets as the fractional inset parameters.
+ */
+ private Drawable createScreenDrawable(Bitmap bitmap, Insets insets) {
+ int insettedWidth = bitmap.getWidth() - insets.left - insets.right;
+ int insettedHeight = bitmap.getHeight() - insets.top - insets.bottom;
+
+ BitmapDrawable bitmapDrawable = new BitmapDrawable(mContext.getResources(), bitmap);
+ if (insettedHeight == 0 || insettedWidth == 0 || bitmap.getWidth() == 0
+ || bitmap.getHeight() == 0) {
+ Log.e(TAG, String.format(
+ "Can't create insetted drawable, using 0 insets "
+ + "bitmap and insets create degenerate region: %dx%d %s",
+ bitmap.getWidth(), bitmap.getHeight(), insets));
+ return bitmapDrawable;
+ }
+
+ InsetDrawable insetDrawable = new InsetDrawable(bitmapDrawable,
+ -1f * insets.left / insettedWidth,
+ -1f * insets.top / insettedHeight,
+ -1f * insets.right / insettedWidth,
+ -1f * insets.bottom / insettedHeight);
+
+ if (insets.left < 0 || insets.top < 0 || insets.right < 0 || insets.bottom < 0) {
+ // Are any of the insets negative, meaning the bitmap is smaller than the bounds so need
+ // to fill in the background of the drawable.
+ return new LayerDrawable(new Drawable[] {
+ new ColorDrawable(Color.BLACK), insetDrawable});
+ } else {
+ return insetDrawable;
+ }
+ }
+
/**
* Receiver to proxy the share or edit intent, used to clean up the notification and send
* appropriate signals to the system (ie. to dismiss the keyguard if necessary).
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshotLegacy.java b/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshotLegacy.java
index 095c32f4a2ce..0017b1f79b74 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshotLegacy.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshotLegacy.java
@@ -24,6 +24,7 @@ import android.animation.AnimatorSet;
import android.animation.ValueAnimator;
import android.animation.ValueAnimator.AnimatorUpdateListener;
import android.annotation.Nullable;
+import android.content.ComponentName;
import android.content.Context;
import android.content.res.Configuration;
import android.content.res.Resources;
@@ -234,8 +235,10 @@ public class GlobalScreenshotLegacy {
}
void handleImageAsScreenshot(Bitmap screenshot, Rect screenshotScreenBounds,
- Insets visibleInsets, int taskId, Consumer<Uri> finisher) {
- // TODO use taskId and visibleInsets
+ Insets visibleInsets, int taskId, int userId, ComponentName topComponent,
+ Consumer<Uri> finisher) {
+ // TODO: use task Id, userId, topComponent for smart handler
+ // TODO: use visibleInsets for animation
takeScreenshot(screenshot, finisher, false, false, screenshotScreenBounds);
}
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/SaveImageInBackgroundTask.java b/packages/SystemUI/src/com/android/systemui/screenshot/SaveImageInBackgroundTask.java
index a5bab212e6b7..221174f70d66 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/SaveImageInBackgroundTask.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/SaveImageInBackgroundTask.java
@@ -123,6 +123,7 @@ class SaveImageInBackgroundTask extends AsyncTask<Void, Void, Void> {
if (isCancelled()) {
return null;
}
+ Thread.currentThread().setPriority(Thread.MAX_PRIORITY);
ContentResolver resolver = mContext.getContentResolver();
Bitmap image = mParams.image;
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotNotificationsController.java b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotNotificationsController.java
index fbcd6ba0ff47..46fe7f4630bd 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotNotificationsController.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotNotificationsController.java
@@ -226,6 +226,66 @@ public class ScreenshotNotificationsController {
}
/**
+ * Shows a silent notification with the saved screenshot and actions that can be taken with it.
+ *
+ * @param actionData SavedImageData struct with image URI and actions
+ */
+ public void showSilentScreenshotNotification(
+ GlobalScreenshot.SavedImageData actionData) {
+ mNotificationBuilder.addAction(actionData.shareAction);
+ mNotificationBuilder.addAction(actionData.editAction);
+ mNotificationBuilder.addAction(actionData.deleteAction);
+ for (Notification.Action smartAction : actionData.smartActions) {
+ mNotificationBuilder.addAction(smartAction);
+ }
+
+ // Create the intent to show the screenshot in gallery
+ Intent launchIntent = new Intent(Intent.ACTION_VIEW);
+ launchIntent.setDataAndType(actionData.uri, "image/png");
+ launchIntent.setFlags(
+ Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_GRANT_READ_URI_PERMISSION);
+
+ final long now = System.currentTimeMillis();
+
+ // Update the text and the icon for the existing notification
+ mPublicNotificationBuilder
+ .setContentTitle(mResources.getString(R.string.screenshot_saved_title))
+ .setContentText(mResources.getString(R.string.screenshot_saved_text))
+ .setContentIntent(PendingIntent.getActivity(mContext, 0, launchIntent, 0))
+ .setSmallIcon(R.drawable.stat_notify_image)
+ .setCategory(Notification.CATEGORY_PROGRESS)
+ .setWhen(now)
+ .setShowWhen(true)
+ .setAutoCancel(true)
+ .setColor(mContext.getColor(
+ com.android.internal.R.color.system_notification_accent_color))
+ .setGroup("silent")
+ .setGroupAlertBehavior(Notification.GROUP_ALERT_SUMMARY);
+ mNotificationBuilder
+ .setContentTitle(mResources.getString(R.string.screenshot_saved_title))
+ .setContentText(mResources.getString(R.string.screenshot_saved_text))
+ .setContentIntent(PendingIntent.getActivity(mContext, 0, launchIntent, 0))
+ .setSmallIcon(R.drawable.stat_notify_image)
+ .setCategory(Notification.CATEGORY_PROGRESS)
+ .setWhen(now)
+ .setShowWhen(true)
+ .setAutoCancel(true)
+ .setColor(mContext.getColor(
+ com.android.internal.R.color.system_notification_accent_color))
+ .setPublicVersion(mPublicNotificationBuilder.build())
+ .setStyle(mNotificationStyle)
+ .setFlag(Notification.FLAG_NO_CLEAR, false)
+ .setGroup("silent")
+ .setGroupAlertBehavior(Notification.GROUP_ALERT_SUMMARY);
+
+ SystemUI.overrideNotificationAppName(mContext, mPublicNotificationBuilder, true);
+ SystemUI.overrideNotificationAppName(mContext, mNotificationBuilder, true);
+
+ mNotificationManager.notify(SystemMessageProto.SystemMessage.NOTE_GLOBAL_SCREENSHOT,
+ mNotificationBuilder.build());
+ }
+
+ /**
* Sends a notification that the screenshot capture has failed.
*/
public void notifyScreenshotError(int msgResId) {
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/TakeScreenshotService.java b/packages/SystemUI/src/com/android/systemui/screenshot/TakeScreenshotService.java
index 98030d45b05e..8322fe08d3c2 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/TakeScreenshotService.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/TakeScreenshotService.java
@@ -20,6 +20,7 @@ import static com.android.internal.util.ScreenshotHelper.SCREENSHOT_MSG_PROCESS_
import static com.android.internal.util.ScreenshotHelper.SCREENSHOT_MSG_URI;
import android.app.Service;
+import android.content.ComponentName;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.Insets;
@@ -37,6 +38,7 @@ import android.view.WindowManager;
import com.android.internal.logging.UiEventLogger;
import com.android.internal.util.ScreenshotHelper;
+import com.android.systemui.shared.recents.utilities.BitmapUtil;
import java.util.function.Consumer;
@@ -107,16 +109,19 @@ public class TakeScreenshotService extends Service {
}
break;
case WindowManager.TAKE_SCREENSHOT_PROVIDED_IMAGE:
- Bitmap screenshot = screenshotRequest.getBitmap();
+ Bitmap screenshot = BitmapUtil.bundleToHardwareBitmap(
+ screenshotRequest.getBitmapBundle());
Rect screenBounds = screenshotRequest.getBoundsInScreen();
Insets insets = screenshotRequest.getInsets();
int taskId = screenshotRequest.getTaskId();
+ int userId = screenshotRequest.getUserId();
+ ComponentName topComponent = screenshotRequest.getTopComponent();
if (useCornerFlow) {
- mScreenshot.handleImageAsScreenshot(
- screenshot, screenBounds, insets, taskId, uriConsumer, onComplete);
+ mScreenshot.handleImageAsScreenshot(screenshot, screenBounds, insets,
+ taskId, userId, topComponent, uriConsumer, onComplete);
} else {
- mScreenshotLegacy.handleImageAsScreenshot(
- screenshot, screenBounds, insets, taskId, uriConsumer);
+ mScreenshotLegacy.handleImageAsScreenshot(screenshot, screenBounds, insets,
+ taskId, userId, topComponent, uriConsumer);
}
break;
default:
diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/Divider.java b/packages/SystemUI/src/com/android/systemui/stackdivider/Divider.java
index 95aceed1126b..21810c0e7cf5 100644
--- a/packages/SystemUI/src/com/android/systemui/stackdivider/Divider.java
+++ b/packages/SystemUI/src/com/android/systemui/stackdivider/Divider.java
@@ -99,16 +99,19 @@ public class Divider extends SystemUI implements DividerView.DividerCallbacks,
private Handler mHandler;
private KeyguardStateController mKeyguardStateController;
+ private WindowManagerProxy mWindowManagerProxy;
+
private final ArrayList<WeakReference<Consumer<Boolean>>> mDockedStackExistsListeners =
new ArrayList<>();
private SplitScreenTaskOrganizer mSplits = new SplitScreenTaskOrganizer(this);
private DisplayChangeController.OnDisplayChangingListener mRotationController =
- (display, fromRotation, toRotation, t) -> {
- if (!mSplits.isSplitScreenSupported()) {
+ (display, fromRotation, toRotation, wct) -> {
+ if (!mSplits.isSplitScreenSupported() || mWindowManagerProxy == null) {
return;
}
+ WindowContainerTransaction t = new WindowContainerTransaction();
DisplayLayout displayLayout =
new DisplayLayout(mDisplayController.getDisplayLayout(display));
SplitDisplayLayout sdl = new SplitDisplayLayout(mContext, displayLayout, mSplits);
@@ -127,6 +130,17 @@ public class Divider extends SystemUI implements DividerView.DividerCallbacks,
if (isSplitActive()) {
WindowManagerProxy.applyHomeTasksMinimized(sdl, mSplits.mSecondary.token, t);
}
+ if (mWindowManagerProxy.queueSyncTransactionIfWaiting(t)) {
+ // Because sync transactions are serialized, its possible for an "older"
+ // bounds-change to get applied after a screen rotation. In that case, we
+ // want to actually defer on that rather than apply immediately. Of course,
+ // this means that the bounds may not change until after the rotation so
+ // the user might see some artifacts. This should be rare.
+ Slog.w(TAG, "Screen rotated while other operations were pending, this may"
+ + " result in some graphical artifacts.");
+ } else {
+ wct.merge(t, true /* transfer */);
+ }
};
private final DividerImeController mImePositionProcessor;
@@ -159,6 +173,7 @@ public class Divider extends SystemUI implements DividerView.DividerCallbacks,
mRecentsOptionalLazy = recentsOptionalLazy;
mForcedResizableController = new ForcedResizableInfoActivityController(context, this);
mTransactionPool = transactionPool;
+ mWindowManagerProxy = new WindowManagerProxy(mTransactionPool, mHandler);
mImePositionProcessor = new DividerImeController(mSplits, mTransactionPool, mHandler);
}
@@ -278,9 +293,9 @@ public class Divider extends SystemUI implements DividerView.DividerCallbacks,
LayoutInflater.from(dctx).inflate(R.layout.docked_stack_divider, null);
DisplayLayout displayLayout = mDisplayController.getDisplayLayout(mContext.getDisplayId());
mView.injectDependencies(mWindowManager, mDividerState, this, mSplits, mSplitLayout,
- mImePositionProcessor);
+ mImePositionProcessor, mWindowManagerProxy);
mView.setVisibility(mVisible ? View.VISIBLE : View.INVISIBLE);
- mView.setMinimizedDockStack(mMinimized, mHomeStackResizable);
+ mView.setMinimizedDockStack(mMinimized, mHomeStackResizable, null /* transaction */);
final int size = dctx.getResources().getDimensionPixelSize(
com.android.internal.R.dimen.docked_stack_divider_thickness);
final boolean landscape = configuration.orientation == ORIENTATION_LANDSCAPE;
@@ -303,7 +318,7 @@ public class Divider extends SystemUI implements DividerView.DividerCallbacks,
addDivider(configuration);
if (mMinimized) {
- mView.setMinimizedDockStack(true, mHomeStackResizable);
+ mView.setMinimizedDockStack(true, mHomeStackResizable, null /* transaction */);
updateTouchable();
}
mView.setHidden(isDividerHidden);
@@ -327,11 +342,13 @@ public class Divider extends SystemUI implements DividerView.DividerCallbacks,
if (visible) {
mView.enterSplitMode(mHomeStackResizable);
// Update state because animations won't finish.
- mView.setMinimizedDockStack(mMinimized, mHomeStackResizable);
+ mWindowManagerProxy.runInSync(
+ t -> mView.setMinimizedDockStack(mMinimized, mHomeStackResizable, t));
+
} else {
mView.exitSplitMode();
- // un-minimize so that next entry triggers minimize anim.
- mView.setMinimizedDockStack(false /* minimized */, mHomeStackResizable);
+ mWindowManagerProxy.runInSync(
+ t -> mView.setMinimizedDockStack(false, mHomeStackResizable, t));
}
// Notify existence listeners
synchronized (mDockedStackExistsListeners) {
@@ -344,12 +361,6 @@ public class Divider extends SystemUI implements DividerView.DividerCallbacks,
}
}
- void onSplitDismissed() {
- updateVisibility(false /* visible */);
- mMinimized = false;
- removeDivider();
- }
-
/** Switch to minimized state if appropriate */
public void setMinimized(final boolean minimized) {
if (DEBUG) Slog.d(TAG, "posting ext setMinimized " + minimized + " vis:" + mVisible);
@@ -405,7 +416,7 @@ public class Divider extends SystemUI implements DividerView.DividerCallbacks,
}
}
updateTouchable();
- WindowOrganizer.applyTransaction(wct);
+ mWindowManagerProxy.applySyncTransaction(wct);
}
void setAdjustedForIme(boolean adjustedForIme) {
@@ -501,7 +512,14 @@ public class Divider extends SystemUI implements DividerView.DividerCallbacks,
update(mDisplayController.getDisplayContext(
mContext.getDisplayId()).getResources().getConfiguration());
// Set resizable directly here because applyEnterSplit already resizes home stack.
- mHomeStackResizable = WindowManagerProxy.applyEnterSplit(mSplits, mSplitLayout);
+ mHomeStackResizable = mWindowManagerProxy.applyEnterSplit(mSplits, mSplitLayout);
+ }
+
+ void startDismissSplit() {
+ mWindowManagerProxy.applyDismissSplit(mSplits, mSplitLayout, true /* dismissOrMaximize */);
+ updateVisibility(false /* visible */);
+ mMinimized = false;
+ removeDivider();
}
void ensureMinimizedSplit() {
@@ -530,6 +548,10 @@ public class Divider extends SystemUI implements DividerView.DividerCallbacks,
return mSplitLayout;
}
+ WindowManagerProxy getWmProxy() {
+ return mWindowManagerProxy;
+ }
+
/** @return the container token for the secondary split root task. */
public WindowContainerToken getSecondaryRoot() {
if (mSplits == null || mSplits.mSecondary == null) {
diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/DividerImeController.java b/packages/SystemUI/src/com/android/systemui/stackdivider/DividerImeController.java
index 1e0c07b1cd4c..aea87f2d1971 100644
--- a/packages/SystemUI/src/com/android/systemui/stackdivider/DividerImeController.java
+++ b/packages/SystemUI/src/com/android/systemui/stackdivider/DividerImeController.java
@@ -29,7 +29,6 @@ import android.view.SurfaceControl;
import android.window.TaskOrganizer;
import android.window.WindowContainerToken;
import android.window.WindowContainerTransaction;
-import android.window.WindowOrganizer;
import androidx.annotation.Nullable;
@@ -213,7 +212,7 @@ class DividerImeController implements DisplayImeController.ImePositionProcessor
SCREEN_WIDTH_DP_UNDEFINED, SCREEN_HEIGHT_DP_UNDEFINED);
}
- WindowOrganizer.applyTransaction(wct);
+ mSplits.mDivider.getWmProxy().applySyncTransaction(wct);
// Update all the adjusted-for-ime states
if (!mPaused) {
diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java b/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java
index e349b5af5b2d..2271f6de194f 100644
--- a/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java
+++ b/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java
@@ -46,6 +46,7 @@ import android.view.VelocityTracker;
import android.view.View;
import android.view.View.OnTouchListener;
import android.view.ViewConfiguration;
+import android.view.ViewRootImpl;
import android.view.ViewTreeObserver.InternalInsetsInfo;
import android.view.ViewTreeObserver.OnComputeInternalInsetsListener;
import android.view.WindowManager;
@@ -138,7 +139,7 @@ public class DividerView extends FrameLayout implements OnTouchListener,
private final Rect mOtherInsetRect = new Rect();
private final Rect mLastResizeRect = new Rect();
private final Rect mTmpRect = new Rect();
- private final WindowManagerProxy mWindowManagerProxy = WindowManagerProxy.getInstance();
+ private WindowManagerProxy mWindowManagerProxy;
private DividerWindowManager mWindowManager;
private VelocityTracker mVelocityTracker;
private FlingAnimationUtils mFlingAnimationUtils;
@@ -360,13 +361,14 @@ public class DividerView extends FrameLayout implements OnTouchListener,
public void injectDependencies(DividerWindowManager windowManager, DividerState dividerState,
DividerCallbacks callback, SplitScreenTaskOrganizer tiles, SplitDisplayLayout sdl,
- DividerImeController imeController) {
+ DividerImeController imeController, WindowManagerProxy wmProxy) {
mWindowManager = windowManager;
mState = dividerState;
mCallback = callback;
mTiles = tiles;
mSplitLayout = sdl;
mImeController = imeController;
+ mWindowManagerProxy = wmProxy;
if (mState.mRatioPositionBeforeMinimized == 0) {
// Set the middle target as the initial state
@@ -376,10 +378,6 @@ public class DividerView extends FrameLayout implements OnTouchListener,
}
}
- public WindowManagerProxy getWindowManagerProxy() {
- return mWindowManagerProxy;
- }
-
public Rect getNonMinimizedSplitScreenSecondaryBounds() {
mOtherTaskRect.set(mSplitLayout.mSecondary);
return mOtherTaskRect;
@@ -519,7 +517,8 @@ public class DividerView extends FrameLayout implements OnTouchListener,
if (mMoving && mDockSide != WindowManager.DOCKED_INVALID) {
SnapTarget snapTarget = getSnapAlgorithm().calculateSnapTarget(
mStartPosition, 0 /* velocity */, false /* hardDismiss */);
- resizeStackSurfaces(calculatePosition(x, y), mStartPosition, snapTarget);
+ resizeStackSurfaces(calculatePosition(x, y), mStartPosition, snapTarget,
+ null /* transaction */);
}
break;
case MotionEvent.ACTION_UP:
@@ -608,7 +607,7 @@ public class DividerView extends FrameLayout implements OnTouchListener,
taskPositionSameAtEnd && animation.getAnimatedFraction() == 1f
? TASK_POSITION_SAME
: snapTarget.taskPosition,
- snapTarget));
+ snapTarget, null /* transaction */));
Consumer<Boolean> endAction = cancelled -> {
if (DEBUG) Slog.d(TAG, "End Fling " + cancelled + " min:" + mIsInMinimizeInteraction);
final boolean wasMinimizeInteraction = mIsInMinimizeInteraction;
@@ -716,7 +715,7 @@ public class DividerView extends FrameLayout implements OnTouchListener,
dismissOrMaximize = mDockSide == WindowManager.DOCKED_RIGHT
|| mDockSide == WindowManager.DOCKED_BOTTOM;
}
- mWindowManagerProxy.dismissOrMaximizeDocked(mTiles, dismissOrMaximize);
+ mWindowManagerProxy.dismissOrMaximizeDocked(mTiles, mSplitLayout, dismissOrMaximize);
Transaction t = mTiles.getTransaction();
setResizeDimLayer(t, true /* primary */, 0f);
setResizeDimLayer(t, false /* primary */, 0f);
@@ -806,7 +805,8 @@ public class DividerView extends FrameLayout implements OnTouchListener,
mWindowManager.setTouchRegion(touchRegion);
}
- public void setMinimizedDockStack(boolean minimized, boolean isHomeStackResizable) {
+ void setMinimizedDockStack(boolean minimized, boolean isHomeStackResizable,
+ Transaction t) {
mHomeStackResizable = isHomeStackResizable;
updateDockSide();
if (!minimized) {
@@ -840,9 +840,10 @@ public class DividerView extends FrameLayout implements OnTouchListener,
// Relayout to recalculate the divider shadow when minimizing
requestLayout();
mIsInMinimizeInteraction = true;
- resizeStackSurfaces(mSplitLayout.getMinimizedSnapAlgorithm().getMiddleTarget());
+ resizeStackSurfaces(
+ mSplitLayout.getMinimizedSnapAlgorithm().getMiddleTarget(), t);
} else {
- resizeStackSurfaces(mSnapTargetBeforeMinimized);
+ resizeStackSurfaces(mSnapTargetBeforeMinimized, t);
mIsInMinimizeInteraction = false;
}
}
@@ -873,10 +874,11 @@ public class DividerView extends FrameLayout implements OnTouchListener,
* assigned to it.
*/
private SurfaceControl getWindowSurfaceControl() {
- if (getViewRootImpl() == null) {
+ final ViewRootImpl root = getViewRootImpl();
+ if (root == null) {
return null;
}
- SurfaceControl out = getViewRootImpl().getSurfaceControl();
+ SurfaceControl out = root.getSurfaceControl();
if (out != null && out.isValid()) {
return out;
}
@@ -885,15 +887,13 @@ public class DividerView extends FrameLayout implements OnTouchListener,
void exitSplitMode() {
// Reset tile bounds
- post(() -> {
- final SurfaceControl sc = getWindowSurfaceControl();
- if (sc == null) {
- return;
- }
- Transaction t = mTiles.getTransaction();
- t.hide(sc).apply();
- mTiles.releaseTransaction(t);
- });
+ final SurfaceControl sc = getWindowSurfaceControl();
+ if (sc == null) {
+ return;
+ }
+ Transaction t = mTiles.getTransaction();
+ t.hide(sc).apply();
+ mTiles.releaseTransaction(t);
int midPos = mSplitLayout.getSnapAlgorithm().getMiddleTarget().position;
WindowManagerProxy.applyResizeSplits(midPos, mSplitLayout);
}
@@ -1049,8 +1049,8 @@ public class DividerView extends FrameLayout implements OnTouchListener,
mDividerSize);
}
- private void resizeStackSurfaces(SnapTarget taskSnapTarget) {
- resizeStackSurfaces(taskSnapTarget.position, taskSnapTarget.position, taskSnapTarget);
+ private void resizeStackSurfaces(SnapTarget taskSnapTarget, Transaction t) {
+ resizeStackSurfaces(taskSnapTarget.position, taskSnapTarget.position, taskSnapTarget, t);
}
void resizeSplitSurfaces(Transaction t, Rect dockedRect, Rect otherRect) {
@@ -1105,7 +1105,8 @@ public class DividerView extends FrameLayout implements OnTouchListener,
}
}
- void resizeStackSurfaces(int position, int taskPosition, SnapTarget taskSnapTarget) {
+ void resizeStackSurfaces(int position, int taskPosition, SnapTarget taskSnapTarget,
+ Transaction transaction) {
if (mRemoved) {
// This divider view has been removed so shouldn't have any additional influence.
return;
@@ -1123,7 +1124,8 @@ public class DividerView extends FrameLayout implements OnTouchListener,
mBackground.invalidate();
}
- Transaction t = mTiles.getTransaction();
+ final boolean ownTransaction = transaction == null;
+ final Transaction t = ownTransaction ? mTiles.getTransaction() : transaction;
mLastResizeRect.set(mDockedRect);
if (mHomeStackResizable && mIsInMinimizeInteraction) {
calculateBoundsForPosition(mSnapTargetBeforeMinimized.position, mDockSide,
@@ -1138,8 +1140,10 @@ public class DividerView extends FrameLayout implements OnTouchListener,
}
resizeSplitSurfaces(t, mDockedRect, mDockedTaskRect, mOtherRect,
mOtherTaskRect);
- t.apply();
- mTiles.releaseTransaction(t);
+ if (ownTransaction) {
+ t.apply();
+ mTiles.releaseTransaction(t);
+ }
return;
}
@@ -1201,8 +1205,10 @@ public class DividerView extends FrameLayout implements OnTouchListener,
SnapTarget closestDismissTarget = getSnapAlgorithm().getClosestDismissTarget(position);
float dimFraction = getDimFraction(position, closestDismissTarget);
setResizeDimLayer(t, isDismissTargetPrimary(closestDismissTarget), dimFraction);
- t.apply();
- mTiles.releaseTransaction(t);
+ if (ownTransaction) {
+ t.apply();
+ mTiles.releaseTransaction(t);
+ }
}
private void applyExitAnimationParallax(Rect taskRect, int position) {
@@ -1383,7 +1389,8 @@ public class DividerView extends FrameLayout implements OnTouchListener,
resizeStackSurfaces(calculatePositionForInsetBounds(),
mSplitLayout.getSnapAlgorithm().getMiddleTarget().position,
- mSplitLayout.getSnapAlgorithm().getMiddleTarget());
+ mSplitLayout.getSnapAlgorithm().getMiddleTarget(),
+ null /* transaction */);
}
void onRecentsDrawn() {
diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/SplitScreenTaskOrganizer.java b/packages/SystemUI/src/com/android/systemui/stackdivider/SplitScreenTaskOrganizer.java
index c496d2280222..db324822994b 100644
--- a/packages/SystemUI/src/com/android/systemui/stackdivider/SplitScreenTaskOrganizer.java
+++ b/packages/SystemUI/src/com/android/systemui/stackdivider/SplitScreenTaskOrganizer.java
@@ -200,8 +200,7 @@ class SplitScreenTaskOrganizer extends TaskOrganizer {
Log.d(TAG, " was in split, so this means leave it "
+ mPrimary.topActivityType + " " + mSecondary.topActivityType);
}
- WindowManagerProxy.applyDismissSplit(this, true /* dismissOrMaximize */);
- mDivider.onSplitDismissed();
+ mDivider.startDismissSplit();
} else if (!primaryIsEmpty && primaryWasEmpty && secondaryWasEmpty) {
// Wasn't in split-mode (both were empty), but now that the primary split is
// populated, we should fully enter split by moving everything else into secondary.
diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/SyncTransactionQueue.java b/packages/SystemUI/src/com/android/systemui/stackdivider/SyncTransactionQueue.java
new file mode 100644
index 000000000000..1ff404677ea6
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/stackdivider/SyncTransactionQueue.java
@@ -0,0 +1,177 @@
+/*
+ * 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.stackdivider;
+
+import android.os.Handler;
+import android.util.Slog;
+import android.view.SurfaceControl;
+import android.window.WindowContainerTransaction;
+import android.window.WindowContainerTransactionCallback;
+import android.window.WindowOrganizer;
+
+import androidx.annotation.NonNull;
+
+import com.android.systemui.TransactionPool;
+
+import java.util.ArrayList;
+
+/**
+ * Helper for serializing sync-transactions and corresponding callbacks.
+ */
+class SyncTransactionQueue {
+ private static final boolean DEBUG = Divider.DEBUG;
+ private static final String TAG = "SyncTransactionQueue";
+
+ // Just a little longer than the sync-engine timeout of 5s
+ private static final int REPLY_TIMEOUT = 5300;
+
+ private final TransactionPool mTransactionPool;
+ private final Handler mHandler;
+
+ // Sync Transactions currently don't support nesting or interleaving properly, so
+ // queue up transactions to run them serially.
+ private final ArrayList<SyncCallback> mQueue = new ArrayList<>();
+
+ private SyncCallback mInFlight = null;
+ private final ArrayList<TransactionRunnable> mRunnables = new ArrayList<>();
+
+ private final Runnable mOnReplyTimeout = () -> {
+ synchronized (mQueue) {
+ if (mInFlight != null && mQueue.contains(mInFlight)) {
+ Slog.w(TAG, "Sync Transaction timed-out: " + mInFlight.mWCT);
+ mInFlight.onTransactionReady(mInFlight.mId, new SurfaceControl.Transaction());
+ }
+ }
+ };
+
+ SyncTransactionQueue(TransactionPool pool, Handler handler) {
+ mTransactionPool = pool;
+ mHandler = handler;
+ }
+
+ /**
+ * Queues a sync transaction to be sent serially to WM.
+ */
+ void queue(WindowContainerTransaction wct) {
+ SyncCallback cb = new SyncCallback(wct);
+ synchronized (mQueue) {
+ if (DEBUG) Slog.d(TAG, "Queueing up " + wct);
+ mQueue.add(cb);
+ if (mQueue.size() == 1) {
+ cb.send();
+ }
+ }
+ }
+
+ /**
+ * Queues a sync transaction only if there are already sync transaction(s) queued or in flight.
+ * Otherwise just returns without queueing.
+ * @return {@code true} if queued, {@code false} if not.
+ */
+ boolean queueIfWaiting(WindowContainerTransaction wct) {
+ synchronized (mQueue) {
+ if (mQueue.isEmpty()) {
+ if (DEBUG) Slog.d(TAG, "Nothing in queue, so skip queueing up " + wct);
+ return false;
+ }
+ if (DEBUG) Slog.d(TAG, "Queue is non-empty, so queueing up " + wct);
+ SyncCallback cb = new SyncCallback(wct);
+ mQueue.add(cb);
+ if (mQueue.size() == 1) {
+ cb.send();
+ }
+ }
+ return true;
+ }
+
+ /**
+ * Runs a runnable in sync with sync transactions (ie. when the current in-flight transaction
+ * returns. If there are no transactions in-flight, runnable executes immediately.
+ */
+ void runInSync(TransactionRunnable runnable) {
+ synchronized (mQueue) {
+ if (DEBUG) Slog.d(TAG, "Run in sync. mInFlight=" + mInFlight);
+ if (mInFlight != null) {
+ mRunnables.add(runnable);
+ return;
+ }
+ }
+ SurfaceControl.Transaction t = mTransactionPool.acquire();
+ runnable.runWithTransaction(t);
+ t.apply();
+ mTransactionPool.release(t);
+ }
+
+ // Synchronized on mQueue
+ private void onTransactionReceived(@NonNull SurfaceControl.Transaction t) {
+ if (DEBUG) Slog.d(TAG, " Running " + mRunnables.size() + " sync runnables");
+ for (int i = 0, n = mRunnables.size(); i < n; ++i) {
+ mRunnables.get(i).runWithTransaction(t);
+ }
+ mRunnables.clear();
+ t.apply();
+ t.close();
+ }
+
+ interface TransactionRunnable {
+ void runWithTransaction(SurfaceControl.Transaction t);
+ }
+
+ private class SyncCallback extends WindowContainerTransactionCallback {
+ int mId = -1;
+ final WindowContainerTransaction mWCT;
+
+ SyncCallback(WindowContainerTransaction wct) {
+ mWCT = wct;
+ }
+
+ // Must be sychronized on mQueue
+ void send() {
+ if (mInFlight != null) {
+ throw new IllegalStateException("Sync Transactions must be serialized. In Flight: "
+ + mInFlight.mId + " - " + mInFlight.mWCT);
+ }
+ mInFlight = this;
+ if (DEBUG) Slog.d(TAG, "Sending sync transaction: " + mWCT);
+ mId = new WindowOrganizer().applySyncTransaction(mWCT, this);
+ if (DEBUG) Slog.d(TAG, " Sent sync transaction. Got id=" + mId);
+ mHandler.postDelayed(mOnReplyTimeout, REPLY_TIMEOUT);
+ }
+
+ @Override
+ public void onTransactionReady(int id,
+ @androidx.annotation.NonNull SurfaceControl.Transaction t) {
+ mHandler.post(() -> {
+ synchronized (mQueue) {
+ if (mId != id) {
+ Slog.e(TAG, "Got an unexpected onTransactionReady. Expected "
+ + mId + " but got " + id);
+ return;
+ }
+ mInFlight = null;
+ mHandler.removeCallbacks(mOnReplyTimeout);
+ if (DEBUG) Slog.d(TAG, "onTransactionReady id=" + mId);
+ mQueue.remove(this);
+ onTransactionReceived(t);
+ if (!mQueue.isEmpty()) {
+ mQueue.get(0).send();
+ }
+ }
+ });
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/WindowManagerProxy.java b/packages/SystemUI/src/com/android/systemui/stackdivider/WindowManagerProxy.java
index 3027bd225216..c8361c63e960 100644
--- a/packages/SystemUI/src/com/android/systemui/stackdivider/WindowManagerProxy.java
+++ b/packages/SystemUI/src/com/android/systemui/stackdivider/WindowManagerProxy.java
@@ -25,9 +25,11 @@ import android.annotation.NonNull;
import android.app.ActivityManager;
import android.app.ActivityTaskManager;
import android.graphics.Rect;
+import android.os.Handler;
import android.os.RemoteException;
import android.util.Log;
import android.view.Display;
+import android.view.SurfaceControl;
import android.view.WindowManagerGlobal;
import android.window.TaskOrganizer;
import android.window.WindowContainerToken;
@@ -35,6 +37,7 @@ import android.window.WindowContainerTransaction;
import android.window.WindowOrganizer;
import com.android.internal.annotations.GuardedBy;
+import com.android.systemui.TransactionPool;
import java.util.ArrayList;
import java.util.List;
@@ -49,8 +52,6 @@ public class WindowManagerProxy {
private static final String TAG = "WindowManagerProxy";
private static final int[] HOME_AND_RECENTS = {ACTIVITY_TYPE_HOME, ACTIVITY_TYPE_RECENTS};
- private static final WindowManagerProxy sInstance = new WindowManagerProxy();
-
@GuardedBy("mDockedRect")
private final Rect mDockedRect = new Rect();
@@ -61,6 +62,8 @@ public class WindowManagerProxy {
private final ExecutorService mExecutor = Executors.newSingleThreadExecutor();
+ private final SyncTransactionQueue mSyncTransactionQueue;
+
private final Runnable mSetTouchableRegionRunnable = new Runnable() {
@Override
public void run() {
@@ -76,16 +79,13 @@ public class WindowManagerProxy {
}
};
- private WindowManagerProxy() {
+ WindowManagerProxy(TransactionPool transactionPool, Handler handler) {
+ mSyncTransactionQueue = new SyncTransactionQueue(transactionPool, handler);
}
- public static WindowManagerProxy getInstance() {
- return sInstance;
- }
-
- void dismissOrMaximizeDocked(
- final SplitScreenTaskOrganizer tiles, final boolean dismissOrMaximize) {
- mExecutor.execute(() -> applyDismissSplit(tiles, dismissOrMaximize));
+ void dismissOrMaximizeDocked(final SplitScreenTaskOrganizer tiles, SplitDisplayLayout layout,
+ final boolean dismissOrMaximize) {
+ mExecutor.execute(() -> applyDismissSplit(tiles, layout, dismissOrMaximize));
}
public void setResizing(final boolean resizing) {
@@ -163,7 +163,7 @@ public class WindowManagerProxy {
*
* @return whether the home stack is resizable
*/
- static boolean applyEnterSplit(SplitScreenTaskOrganizer tiles, SplitDisplayLayout layout) {
+ boolean applyEnterSplit(SplitScreenTaskOrganizer tiles, SplitDisplayLayout layout) {
// Set launchtile first so that any stack created after
// getAllStackInfos and before reparent (even if unlikely) are placed
// correctly.
@@ -174,6 +174,8 @@ public class WindowManagerProxy {
if (rootTasks.isEmpty()) {
return false;
}
+ ActivityManager.RunningTaskInfo topHomeTask = null;
+ boolean homeIsTop = false;
for (int i = rootTasks.size() - 1; i >= 0; --i) {
final ActivityManager.RunningTaskInfo rootTask = rootTasks.get(i);
// Only move resizeable task to split secondary. WM will just ignore this anyways...
@@ -183,16 +185,25 @@ public class WindowManagerProxy {
!= WINDOWING_MODE_FULLSCREEN) {
continue;
}
+ // Since this iterates from bottom to top, update topHomeTask for every fullscreen task
+ // so it will be left with the status of the top one.
+ topHomeTask = isHomeOrRecentTask(rootTask) ? rootTask : null;
wct.reparent(rootTask.token, tiles.mSecondary.token, true /* onTop */);
}
// Move the secondary split-forward.
wct.reorder(tiles.mSecondary.token, true /* onTop */);
boolean isHomeResizable = applyHomeTasksMinimized(layout, null /* parent */, wct);
- WindowOrganizer.applyTransaction(wct);
+ if (isHomeResizable && topHomeTask != null) {
+ // Translate/update-crop of secondary out-of-band with sync transaction -- Until BALST
+ // is enabled, this temporarily syncs the home surface position with offset until
+ // sync transaction finishes.
+ wct.setBoundsChangeTransaction(topHomeTask.token, tiles.mHomeBounds);
+ }
+ applySyncTransaction(wct);
return isHomeResizable;
}
- private static boolean isHomeOrRecentTask(ActivityManager.RunningTaskInfo ti) {
+ static boolean isHomeOrRecentTask(ActivityManager.RunningTaskInfo ti) {
final int atype = ti.configuration.windowConfiguration.getActivityType();
return atype == ACTIVITY_TYPE_HOME || atype == ACTIVITY_TYPE_RECENTS;
}
@@ -203,7 +214,8 @@ public class WindowManagerProxy {
* split (thus resulting in the top of the secondary split becoming
* fullscreen. {@code false} resolves the other way.
*/
- static void applyDismissSplit(SplitScreenTaskOrganizer tiles, boolean dismissOrMaximize) {
+ void applyDismissSplit(SplitScreenTaskOrganizer tiles, SplitDisplayLayout layout,
+ boolean dismissOrMaximize) {
// Set launch root first so that any task created after getChildContainers and
// before reparent (pretty unlikely) are put into fullscreen.
TaskOrganizer.setLaunchRoot(Display.DEFAULT_DISPLAY, null);
@@ -229,6 +241,7 @@ public class WindowManagerProxy {
wct.reparent(primaryChildren.get(i).token, null /* parent */,
true /* onTop */);
}
+ boolean homeOnTop = false;
// Don't need to worry about home tasks because they are already in the "proper"
// order within the secondary split.
for (int i = secondaryChildren.size() - 1; i >= 0; --i) {
@@ -236,8 +249,31 @@ public class WindowManagerProxy {
wct.reparent(ti.token, null /* parent */, true /* onTop */);
if (isHomeOrRecentTask(ti)) {
wct.setBounds(ti.token, null);
+ if (i == 0) {
+ homeOnTop = true;
+ }
}
}
+ if (homeOnTop) {
+ // Translate/update-crop of secondary out-of-band with sync transaction -- instead
+ // play this in sync with new home-app frame because until BALST is enabled this
+ // shows up on screen before the syncTransaction returns.
+ // We only have access to the secondary root surface, though, so in order to
+ // position things properly, we have to take into account the existing negative
+ // offset/crop of the minimized-home task.
+ final boolean landscape = layout.mDisplayLayout.isLandscape();
+ final int posX = landscape ? layout.mSecondary.left - tiles.mHomeBounds.left
+ : layout.mSecondary.left;
+ final int posY = landscape ? layout.mSecondary.top
+ : layout.mSecondary.top - tiles.mHomeBounds.top;
+ final SurfaceControl.Transaction sft = new SurfaceControl.Transaction();
+ sft.setPosition(tiles.mSecondarySurface, posX, posY);
+ final Rect crop = new Rect(0, 0, layout.mDisplayLayout.width(),
+ layout.mDisplayLayout.height());
+ crop.offset(-posX, -posY);
+ sft.setWindowCrop(tiles.mSecondarySurface, crop);
+ wct.setBoundsChangeTransaction(tiles.mSecondary.token, sft);
+ }
} else {
// Maximize, so move non-home secondary split first
for (int i = secondaryChildren.size() - 1; i >= 0; --i) {
@@ -267,6 +303,29 @@ public class WindowManagerProxy {
}
// Reset focusable to true
wct.setFocusable(tiles.mPrimary.token, true /* focusable */);
- WindowOrganizer.applyTransaction(wct);
+ applySyncTransaction(wct);
+ }
+
+ /**
+ * Utility to apply a sync transaction serially with other sync transactions.
+ *
+ * @see SyncTransactionQueue#queue
+ */
+ void applySyncTransaction(WindowContainerTransaction wct) {
+ mSyncTransactionQueue.queue(wct);
+ }
+
+ /**
+ * @see SyncTransactionQueue#queueIfWaiting
+ */
+ boolean queueSyncTransactionIfWaiting(WindowContainerTransaction wct) {
+ return mSyncTransactionQueue.queueIfWaiting(wct);
+ }
+
+ /**
+ * @see SyncTransactionQueue#runInSync
+ */
+ void runInSync(SyncTransactionQueue.TransactionRunnable runnable) {
+ mSyncTransactionQueue.runInSync(runnable);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java
index 217148df60e2..5628a24f40ef 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java
@@ -52,7 +52,6 @@ import com.android.systemui.Interpolators;
import com.android.systemui.colorextraction.SysuiColorExtractor;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.media.MediaDataManager;
-import com.android.systemui.media.MediaDeviceManager;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.statusbar.dagger.StatusBarModule;
import com.android.systemui.statusbar.notification.NotificationEntryListener;
@@ -102,6 +101,12 @@ public class NotificationMediaManager implements Dumpable {
PAUSED_MEDIA_STATES.add(PlaybackState.STATE_PAUSED);
PAUSED_MEDIA_STATES.add(PlaybackState.STATE_ERROR);
}
+ private static final HashSet<Integer> INACTIVE_MEDIA_STATES = new HashSet<>();
+ static {
+ INACTIVE_MEDIA_STATES.add(PlaybackState.STATE_NONE);
+ INACTIVE_MEDIA_STATES.add(PlaybackState.STATE_STOPPED);
+ INACTIVE_MEDIA_STATES.add(PlaybackState.STATE_ERROR);
+ }
private final NotificationEntryManager mEntryManager;
private final MediaDataManager mMediaDataManager;
@@ -190,8 +195,7 @@ public class NotificationMediaManager implements Dumpable {
KeyguardBypassController keyguardBypassController,
@Main DelayableExecutor mainExecutor,
DeviceConfigProxy deviceConfig,
- MediaDataManager mediaDataManager,
- MediaDeviceManager mediaDeviceManager) {
+ MediaDataManager mediaDataManager) {
mContext = context;
mMediaArtworkProcessor = mediaArtworkProcessor;
mKeyguardBypassController = keyguardBypassController;
@@ -212,13 +216,11 @@ public class NotificationMediaManager implements Dumpable {
@Override
public void onPendingEntryAdded(NotificationEntry entry) {
mediaDataManager.onNotificationAdded(entry.getKey(), entry.getSbn());
- mediaDeviceManager.onNotificationAdded(entry.getKey(), entry.getSbn());
}
@Override
public void onPreEntryUpdated(NotificationEntry entry) {
mediaDataManager.onNotificationAdded(entry.getKey(), entry.getSbn());
- mediaDeviceManager.onNotificationAdded(entry.getKey(), entry.getSbn());
}
@Override
@@ -239,7 +241,6 @@ public class NotificationMediaManager implements Dumpable {
int reason) {
onNotificationRemoved(entry.getKey());
mediaDataManager.onNotificationRemoved(entry.getKey());
- mediaDeviceManager.onNotificationRemoved(entry.getKey());
}
});
@@ -252,10 +253,24 @@ public class NotificationMediaManager implements Dumpable {
mPropertiesChangedListener);
}
+ /**
+ * Check if a state should be considered actively playing
+ * @param state a PlaybackState
+ * @return true if playing
+ */
public static boolean isPlayingState(int state) {
return !PAUSED_MEDIA_STATES.contains(state);
}
+ /**
+ * Check if a state should be considered active (playing or paused)
+ * @param state a PlaybackState
+ * @return true if active
+ */
+ public static boolean isActiveState(int state) {
+ return !INACTIVE_MEDIA_STATES.contains(state);
+ }
+
public void setUpWithPresenter(NotificationPresenter presenter) {
mPresenter = presenter;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationViewHierarchyManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationViewHierarchyManager.java
index 3dda15b5ce39..5bee9a762f6f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationViewHierarchyManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationViewHierarchyManager.java
@@ -42,7 +42,6 @@ import com.android.systemui.statusbar.notification.stack.NotificationListContain
import com.android.systemui.statusbar.phone.KeyguardBypassController;
import com.android.systemui.statusbar.phone.NotificationGroupManager;
import com.android.systemui.util.Assert;
-import com.android.systemui.util.Utils;
import java.util.ArrayList;
import java.util.HashMap;
@@ -61,7 +60,11 @@ public class NotificationViewHierarchyManager implements DynamicPrivacyControlle
private final Handler mHandler;
- /** Re-usable map of top-level notifications to their sorted children if any.*/
+ /**
+ * Re-usable map of top-level notifications to their sorted children if any.
+ * If the top-level notification doesn't have children, its key will still exist in this map
+ * with its value explicitly set to null.
+ */
private final HashMap<NotificationEntry, List<NotificationEntry>> mTmpChildOrderMap =
new HashMap<>();
@@ -150,9 +153,7 @@ public class NotificationViewHierarchyManager implements DynamicPrivacyControlle
final int N = activeNotifications.size();
for (int i = 0; i < N; i++) {
NotificationEntry ent = activeNotifications.get(i);
- boolean hideMedia = Utils.useQsMediaPlayer(mContext);
if (ent.isRowDismissed() || ent.isRowRemoved()
- || (ent.isMediaNotification() && hideMedia)
|| mBubbleController.isBubbleNotificationSuppressedFromShade(ent)
|| mFgsSectionController.hasEntry(ent)) {
// we don't want to update removed notifications because they could
@@ -215,10 +216,19 @@ public class NotificationViewHierarchyManager implements DynamicPrivacyControlle
}
orderedChildren.add(ent);
} else {
- // Top-level notif
- mTmpChildOrderMap.put(ent, null);
+ // Top-level notif (either a summary or single notification)
+
+ // A child may have already added its summary to mTmpChildOrderMap with a
+ // list of children. This can happen since there's no guarantee summaries are
+ // sorted before its children.
+ if (!mTmpChildOrderMap.containsKey(ent)) {
+ // mTmpChildOrderMap's keyset is used to iterate through all entries, so it's
+ // necessary to add each top-level notif as a key
+ mTmpChildOrderMap.put(ent, null);
+ }
toShow.add(ent.getRow());
}
+
}
ArrayList<ExpandableNotificationRow> viewsToRemove = new ArrayList<>();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/dagger/StatusBarDependenciesModule.java b/packages/SystemUI/src/com/android/systemui/statusbar/dagger/StatusBarDependenciesModule.java
index c988e1251d3f..84c8db3218e7 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/dagger/StatusBarDependenciesModule.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/dagger/StatusBarDependenciesModule.java
@@ -24,7 +24,6 @@ import com.android.internal.statusbar.IStatusBarService;
import com.android.systemui.bubbles.BubbleController;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.media.MediaDataManager;
-import com.android.systemui.media.MediaDeviceManager;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.statusbar.ActionClickLogger;
import com.android.systemui.statusbar.CommandQueue;
@@ -51,8 +50,6 @@ import com.android.systemui.tracing.ProtoTracer;
import com.android.systemui.util.DeviceConfigProxy;
import com.android.systemui.util.concurrency.DelayableExecutor;
-import java.util.concurrent.Executor;
-
import javax.inject.Singleton;
import dagger.Lazy;
@@ -105,8 +102,7 @@ public interface StatusBarDependenciesModule {
KeyguardBypassController keyguardBypassController,
@Main DelayableExecutor mainExecutor,
DeviceConfigProxy deviceConfigProxy,
- MediaDataManager mediaDataManager,
- MediaDeviceManager mediaDeviceManager) {
+ MediaDataManager mediaDataManager) {
return new NotificationMediaManager(
context,
statusBarLazy,
@@ -116,8 +112,7 @@ public interface StatusBarDependenciesModule {
keyguardBypassController,
mainExecutor,
deviceConfigProxy,
- mediaDataManager,
- mediaDeviceManager);
+ mediaDataManager);
}
/** */
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/ConversationNotifications.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/ConversationNotifications.kt
index fc6c2be1ce9a..1972b869ba25 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/ConversationNotifications.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/ConversationNotifications.kt
@@ -19,13 +19,16 @@ package com.android.systemui.statusbar.notification
import android.app.Notification
import android.content.Context
import android.content.pm.LauncherApps
+import android.os.Handler
import android.service.notification.NotificationListenerService.Ranking
import android.service.notification.NotificationListenerService.RankingMap
import com.android.internal.statusbar.NotificationVisibility
import com.android.internal.widget.ConversationLayout
+import com.android.systemui.dagger.qualifiers.Main
import com.android.systemui.statusbar.notification.collection.NotificationEntry
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow
import com.android.systemui.statusbar.notification.row.NotificationContentView
+import com.android.systemui.statusbar.notification.stack.StackStateAnimator
import com.android.systemui.statusbar.phone.NotificationGroupManager
import java.util.concurrent.ConcurrentHashMap
import javax.inject.Inject
@@ -62,7 +65,8 @@ class ConversationNotificationProcessor @Inject constructor(
class ConversationNotificationManager @Inject constructor(
private val notificationEntryManager: NotificationEntryManager,
private val notificationGroupManager: NotificationGroupManager,
- private val context: Context
+ private val context: Context,
+ @Main private val mainHandler: Handler
) {
// Need this state to be thread safe, since it's accessed from the ui thread
// (NotificationEntryListener) and a bg thread (NotificationContentInflater)
@@ -72,32 +76,41 @@ class ConversationNotificationManager @Inject constructor(
init {
notificationEntryManager.addNotificationEntryListener(object : NotificationEntryListener {
-
override fun onNotificationRankingUpdated(rankingMap: RankingMap) {
fun getLayouts(view: NotificationContentView) =
sequenceOf(view.contractedChild, view.expandedChild, view.headsUpChild)
val ranking = Ranking()
- states.keys.asSequence()
+ val activeConversationEntries = states.keys.asSequence()
.mapNotNull { notificationEntryManager.getActiveNotificationUnfiltered(it) }
- .forEach { entry ->
- if (rankingMap.getRanking(entry.sbn.key, ranking) &&
- ranking.isConversation) {
- val important = ranking.channel.isImportantConversation
- var changed = false
- entry.row?.layouts?.asSequence()
- ?.flatMap(::getLayouts)
- ?.mapNotNull { it as? ConversationLayout }
- ?.forEach {
- if (important != it.isImportantConversation) {
- it.setIsImportantConversation(important)
- changed = true
- }
- }
- if (changed) {
- notificationGroupManager.updateIsolation(entry)
- }
+ for (entry in activeConversationEntries) {
+ if (rankingMap.getRanking(entry.sbn.key, ranking) && ranking.isConversation) {
+ val important = ranking.channel.isImportantConversation
+ val layouts = entry.row?.layouts?.asSequence()
+ ?.flatMap(::getLayouts)
+ ?.mapNotNull { it as? ConversationLayout }
+ ?: emptySequence()
+ var changed = false
+ for (layout in layouts) {
+ if (important == layout.isImportantConversation) {
+ continue
+ }
+ changed = true
+ if (important && entry.isMarkedForUserTriggeredMovement) {
+ // delay this so that it doesn't animate in until after
+ // the notif has been moved in the shade
+ mainHandler.postDelayed({
+ layout.setIsImportantConversation(
+ important, true /* animate */)
+ }, IMPORTANCE_ANIMATION_DELAY.toLong())
+ } else {
+ layout.setIsImportantConversation(important)
}
}
+ if (changed) {
+ notificationGroupManager.updateIsolation(entry)
+ }
+ }
+ }
}
override fun onEntryInflated(entry: NotificationEntry) {
@@ -177,9 +190,16 @@ class ConversationNotificationManager @Inject constructor(
private fun resetBadgeUi(row: ExpandableNotificationRow): Unit =
(row.layouts?.asSequence() ?: emptySequence())
- .flatMap { layout -> layout.allViews.asSequence()}
+ .flatMap { layout -> layout.allViews.asSequence() }
.mapNotNull { view -> view as? ConversationLayout }
.forEach { convoLayout -> convoLayout.setUnreadCount(0) }
private data class ConversationState(val unreadCount: Int, val notification: Notification)
+
+ companion object {
+ private const val IMPORTANCE_ANIMATION_DELAY =
+ StackStateAnimator.ANIMATION_DURATION_STANDARD +
+ StackStateAnimator.ANIMATION_DURATION_PRIORITY_CHANGE +
+ 100
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationFilter.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationFilter.java
index 3afd6235b287..6335a09cde2b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationFilter.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationFilter.java
@@ -16,6 +16,8 @@
package com.android.systemui.statusbar.notification;
+import static com.android.systemui.media.MediaDataManagerKt.isMediaNotification;
+
import android.Manifest;
import android.app.AppGlobals;
import android.app.Notification;
@@ -27,6 +29,7 @@ import android.service.notification.StatusBarNotification;
import com.android.internal.annotations.VisibleForTesting;
import com.android.systemui.Dependency;
import com.android.systemui.ForegroundServiceController;
+import com.android.systemui.media.MediaFeatureFlag;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.statusbar.NotificationLockscreenUserManager;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
@@ -46,6 +49,7 @@ public class NotificationFilter {
private final NotificationGroupManager mGroupManager = Dependency.get(
NotificationGroupManager.class);
private final StatusBarStateController mStatusBarStateController;
+ private final Boolean mIsMediaFlagEnabled;
private NotificationEntryManager.KeyguardEnvironment mEnvironment;
private ShadeController mShadeController;
@@ -53,8 +57,11 @@ public class NotificationFilter {
private NotificationLockscreenUserManager mUserManager;
@Inject
- public NotificationFilter(StatusBarStateController statusBarStateController) {
+ public NotificationFilter(
+ StatusBarStateController statusBarStateController,
+ MediaFeatureFlag mediaFeatureFlag) {
mStatusBarStateController = statusBarStateController;
+ mIsMediaFlagEnabled = mediaFeatureFlag.getEnabled();
}
private NotificationEntryManager.KeyguardEnvironment getEnvironment() {
@@ -133,6 +140,10 @@ public class NotificationFilter {
}
}
}
+
+ if (mIsMediaFlagEnabled && isMediaNotification(sbn)) {
+ return true;
+ }
return false;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/MediaCoordinator.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/MediaCoordinator.java
new file mode 100644
index 000000000000..026a3ffb73cd
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/MediaCoordinator.java
@@ -0,0 +1,52 @@
+/*
+ * 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.statusbar.notification.collection.coordinator;
+
+import static com.android.systemui.media.MediaDataManagerKt.isMediaNotification;
+
+import com.android.systemui.media.MediaFeatureFlag;
+import com.android.systemui.statusbar.notification.collection.NotifPipeline;
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
+import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifFilter;
+
+import javax.inject.Inject;
+
+/**
+ * Coordinates hiding (filtering) of media notifications.
+ */
+public class MediaCoordinator implements Coordinator {
+ private static final String TAG = "MediaCoordinator";
+
+ private final Boolean mIsMediaFeatureEnabled;
+
+ private final NotifFilter mMediaFilter = new NotifFilter(TAG) {
+ @Override
+ public boolean shouldFilterOut(NotificationEntry entry, long now) {
+ return mIsMediaFeatureEnabled && isMediaNotification(entry.getSbn());
+ }
+ };
+
+ @Inject
+ public MediaCoordinator(MediaFeatureFlag featureFlag) {
+ mIsMediaFeatureEnabled = featureFlag.getEnabled();
+ }
+
+ @Override
+ public void attach(NotifPipeline pipeline) {
+ pipeline.addFinalizeFilter(mMediaFilter);
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/NotifCoordinators.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/NotifCoordinators.java
index 2b279bbd553a..ac4296439507 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/NotifCoordinators.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/NotifCoordinators.java
@@ -57,7 +57,8 @@ public class NotifCoordinators implements Dumpable {
BubbleCoordinator bubbleCoordinator,
HeadsUpCoordinator headsUpCoordinator,
ConversationCoordinator conversationCoordinator,
- PreparationCoordinator preparationCoordinator) {
+ PreparationCoordinator preparationCoordinator,
+ MediaCoordinator mediaCoordinator) {
dumpManager.registerDumpable(TAG, this);
mCoordinators.add(new HideLocallyDismissedNotifsCoordinator());
mCoordinators.add(hideNotifsForOtherUsersCoordinator);
@@ -72,6 +73,7 @@ public class NotifCoordinators implements Dumpable {
mCoordinators.add(preparationCoordinator);
}
// TODO: add new Coordinators here! (b/112656837)
+ mCoordinators.add(mediaCoordinator);
// TODO: add the sections in a particular ORDER (HeadsUp < People < Alerting)
for (Coordinator c : mCoordinators) {
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 df3609bbc6b6..1c076c49249b 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
@@ -23,6 +23,9 @@ 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.people.PeopleNotificationIdentifier;
+import com.android.systemui.statusbar.phone.NotificationGroupManager;
+
+import java.util.List;
import javax.inject.Inject;
import javax.inject.Singleton;
@@ -36,10 +39,14 @@ import javax.inject.Singleton;
@Singleton
public class HighPriorityProvider {
private final PeopleNotificationIdentifier mPeopleNotificationIdentifier;
+ private final NotificationGroupManager mGroupManager;
@Inject
- public HighPriorityProvider(PeopleNotificationIdentifier peopleNotificationIdentifier) {
+ public HighPriorityProvider(
+ PeopleNotificationIdentifier peopleNotificationIdentifier,
+ NotificationGroupManager groupManager) {
mPeopleNotificationIdentifier = peopleNotificationIdentifier;
+ mGroupManager = groupManager;
}
/**
@@ -74,13 +81,25 @@ public class HighPriorityProvider {
private boolean hasHighPriorityChild(ListEntry entry) {
+ List<NotificationEntry> children = null;
+
if (entry instanceof GroupEntry) {
- for (NotificationEntry child : ((GroupEntry) entry).getChildren()) {
+ // New notification pipeline
+ children = ((GroupEntry) entry).getChildren();
+ } else if (entry.getRepresentativeEntry() != null
+ && mGroupManager.isGroupSummary(entry.getRepresentativeEntry().getSbn())) {
+ // Old notification pipeline
+ children = mGroupManager.getChildren(entry.getRepresentativeEntry().getSbn());
+ }
+
+ if (children != null) {
+ for (NotificationEntry child : children) {
if (isHighPriority(child)) {
return true;
}
}
}
+
return false;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/AppOpsInfo.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/AppOpsInfo.java
index 9dcc187cb0ef..e445c9d73bbb 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/AppOpsInfo.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/AppOpsInfo.java
@@ -52,7 +52,7 @@ public class AppOpsInfo extends LinearLayout implements NotificationGuts.GutsCon
private NotificationGuts mGutsContainer;
private OnClickListener mOnOk = v -> {
- closeControls(v);
+ mGutsContainer.closeControls(v, false);
};
public AppOpsInfo(Context context, AttributeSet attrs) {
@@ -117,6 +117,7 @@ public class AppOpsInfo extends LinearLayout implements NotificationGuts.GutsCon
});
TextView ok = findViewById(R.id.ok);
ok.setOnClickListener(mOnOk);
+ ok.setAccessibilityDelegate(mGutsContainer.getAccessibilityDelegate());
}
private String getPrompt() {
@@ -160,19 +161,6 @@ public class AppOpsInfo extends LinearLayout implements NotificationGuts.GutsCon
}
}
- private void closeControls(View v) {
- mMetricsLogger.visibility(MetricsEvent.APP_OPS_GUTS, false);
- int[] parentLoc = new int[2];
- int[] targetLoc = new int[2];
- mGutsContainer.getLocationOnScreen(parentLoc);
- v.getLocationOnScreen(targetLoc);
- final int centerX = v.getWidth() / 2;
- final int centerY = v.getHeight() / 2;
- final int x = targetLoc[0] - parentLoc[0] + centerX;
- final int y = targetLoc[1] - parentLoc[1] + centerY;
- mGutsContainer.closeControls(x, y, false, false);
- }
-
@Override
public void setGutsParent(NotificationGuts guts) {
mGutsContainer = guts;
@@ -200,6 +188,9 @@ public class AppOpsInfo extends LinearLayout implements NotificationGuts.GutsCon
@Override
public boolean handleCloseControls(boolean save, boolean force) {
+ if (mMetricsLogger != null) {
+ mMetricsLogger.visibility(MetricsEvent.APP_OPS_GUTS, false);
+ }
return false;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ChannelEditorDialogController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ChannelEditorDialogController.kt
index b163818f68a8..93db9cdf85ef 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ChannelEditorDialogController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ChannelEditorDialogController.kt
@@ -341,7 +341,6 @@ class ChannelEditorDialogController @Inject constructor(
}
private val wmFlags = (WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS
- or WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
or WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH
or WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED)
}
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 f7ad50edb2f6..94e12e82f850 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
@@ -1122,9 +1122,8 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
}
public void setGutsView(MenuItem item) {
- if (mGuts != null && item.getGutsView() instanceof NotificationGuts.GutsContent) {
- ((NotificationGuts.GutsContent) item.getGutsView()).setGutsParent(mGuts);
- mGuts.setGutsContent((NotificationGuts.GutsContent) item.getGutsView());
+ if (getGuts() != null && item.getGutsView() instanceof NotificationGuts.GutsContent) {
+ getGuts().setGutsContent((NotificationGuts.GutsContent) item.getGutsView());
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java
index 9925909c3e16..b0861bfbd643 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java
@@ -557,9 +557,9 @@ public class NotificationContentView extends FrameLayout {
private void focusExpandButtonIfNecessary() {
if (mFocusOnVisibilityChange) {
- NotificationHeaderView header = getVisibleNotificationHeader();
- if (header != null) {
- ImageView expandButton = header.getExpandButton();
+ NotificationViewWrapper wrapper = getVisibleWrapper(mVisibleType);
+ if (wrapper != null) {
+ View expandButton = wrapper.getExpandButton();
if (expandButton != null) {
expandButton.requestAccessibilityFocus();
}
@@ -1348,7 +1348,9 @@ public class NotificationContentView extends FrameLayout {
}
ImageView bubbleButton = layout.findViewById(com.android.internal.R.id.bubble_button);
View actionContainer = layout.findViewById(com.android.internal.R.id.actions_container);
- if (bubbleButton == null || actionContainer == null) {
+ LinearLayout actionContainerLayout =
+ layout.findViewById(com.android.internal.R.id.actions_container_layout);
+ if (bubbleButton == null || actionContainer == null || actionContainerLayout == null) {
return;
}
boolean isPersonWithShortcut =
@@ -1374,8 +1376,16 @@ public class NotificationContentView extends FrameLayout {
bubbleButton.setOnClickListener(mContainingNotification.getBubbleClickListener());
bubbleButton.setVisibility(VISIBLE);
actionContainer.setVisibility(VISIBLE);
+
+ int paddingEnd = getResources().getDimensionPixelSize(
+ com.android.internal.R.dimen.bubble_visible_padding_end);
+ actionContainerLayout.setPaddingRelative(0, 0, paddingEnd, 0);
} else {
bubbleButton.setVisibility(GONE);
+
+ int paddingEnd = getResources().getDimensionPixelSize(
+ com.android.internal.R.dimen.bubble_gone_padding_end);
+ actionContainerLayout.setPaddingRelative(0, 0, paddingEnd, 0);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationConversationInfo.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationConversationInfo.java
index 9befa313edd8..bee2f7002823 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationConversationInfo.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationConversationInfo.java
@@ -44,6 +44,7 @@ import android.content.pm.ShortcutInfo;
import android.content.pm.ShortcutManager;
import android.os.Handler;
import android.os.RemoteException;
+import android.os.UserHandle;
import android.provider.Settings;
import android.service.notification.StatusBarNotification;
import android.text.TextUtils;
@@ -115,6 +116,7 @@ public class NotificationConversationInfo extends LinearLayout implements
private OnSnoozeClickListener mOnSnoozeClickListener;
private OnSettingsClickListener mOnSettingsClickListener;
private NotificationGuts mGutsContainer;
+ private OnConversationSettingsClickListener mOnConversationSettingsClickListener;
@VisibleForTesting
boolean mSkipPost = false;
@@ -137,13 +139,13 @@ public class NotificationConversationInfo extends LinearLayout implements
mSelectedAction = ACTION_HOME;
mShortcutManager.requestPinShortcut(mShortcutInfo, null);
mShadeController.animateCollapsePanels();
- closeControls(v, true);
+ mGutsContainer.closeControls(v, true);
};
private OnClickListener mOnSnoozeClick = v -> {
mSelectedAction = ACTION_SNOOZE;
mOnSnoozeClickListener.onClick(v, 1);
- closeControls(v, true);
+ mGutsContainer.closeControls(v, true);
};
*/
@@ -164,7 +166,11 @@ public class NotificationConversationInfo extends LinearLayout implements
private OnClickListener mOnDone = v -> {
mPressedApply = true;
- closeControls(v, true);
+ // If the user selected Priority, maybe show the priority onboarding
+ if (mSelectedAction == ACTION_FAVORITE && shouldShowPriorityOnboarding()) {
+ showPriorityOnboarding();
+ }
+ mGutsContainer.closeControls(v, true);
};
public NotificationConversationInfo(Context context, AttributeSet attrs) {
@@ -175,6 +181,10 @@ public class NotificationConversationInfo extends LinearLayout implements
void onClick(View v, NotificationChannel channel, int appUid);
}
+ public interface OnConversationSettingsClickListener {
+ void onClick();
+ }
+
public interface OnAppSettingsClickListener {
void onClick(View v, Intent intent);
}
@@ -190,14 +200,6 @@ public class NotificationConversationInfo extends LinearLayout implements
}
mSelectedAction = selectedAction;
- onSelectedActionChanged();
- }
-
- private void onSelectedActionChanged() {
- // If the user selected Priority, maybe show the priority onboarding
- if (mSelectedAction == ACTION_FAVORITE && shouldShowPriorityOnboarding()) {
- showPriorityOnboarding();
- }
}
public void bindNotification(
@@ -216,7 +218,8 @@ public class NotificationConversationInfo extends LinearLayout implements
Provider<PriorityOnboardingDialogController.Builder> builderProvider,
boolean isDeviceProvisioned,
@Main Handler mainHandler,
- @Background Handler bgHandler) {
+ @Background Handler bgHandler,
+ OnConversationSettingsClickListener onConversationSettingsClickListener) {
mSelectedAction = -1;
mINotificationManager = iNotificationManager;
mVisualStabilityManager = visualStabilityManager;
@@ -231,6 +234,7 @@ public class NotificationConversationInfo extends LinearLayout implements
mDelegatePkg = mSbn.getOpPkg();
mIsDeviceProvisioned = isDeviceProvisioned;
mOnSnoozeClickListener = onSnoozeClickListener;
+ mOnConversationSettingsClickListener = onConversationSettingsClickListener;
mIconFactory = conversationIconFactory;
mUserContext = userContext;
mBubbleMetadata = bubbleMetadata;
@@ -258,6 +262,7 @@ public class NotificationConversationInfo extends LinearLayout implements
View done = findViewById(R.id.done);
done.setOnClickListener(mOnDone);
+ done.setAccessibilityDelegate(mGutsContainer.getAccessibilityDelegate());
}
private void bindActions() {
@@ -322,7 +327,6 @@ public class NotificationConversationInfo extends LinearLayout implements
ImageView image = findViewById(R.id.conversation_icon);
image.setImageDrawable(mIconFactory.getConversationDrawable(
mShortcutInfo, mPackageName, mAppUid, important));
-
}
private void bindPackage() {
@@ -368,14 +372,11 @@ public class NotificationConversationInfo extends LinearLayout implements
}
}
TextView groupNameView = findViewById(R.id.group_name);
- View groupDivider = findViewById(R.id.group_divider);
if (groupName != null) {
groupNameView.setText(groupName);
groupNameView.setVisibility(VISIBLE);
- groupDivider.setVisibility(VISIBLE);
} else {
groupNameView.setVisibility(GONE);
- groupDivider.setVisibility(GONE);
}
}
@@ -507,10 +508,10 @@ public class NotificationConversationInfo extends LinearLayout implements
mBgHandler.post(
new UpdateChannelRunnable(mINotificationManager, mPackageName,
mAppUid, mSelectedAction, mNotificationChannel));
- mMainHandler.postDelayed(() -> {
- mEntry.markForUserTriggeredMovement(true);
- mVisualStabilityManager.temporarilyAllowReordering();
- }, StackStateAnimator.ANIMATION_DURATION_STANDARD);
+ mEntry.markForUserTriggeredMovement(true);
+ mMainHandler.postDelayed(
+ mVisualStabilityManager::temporarilyAllowReordering,
+ StackStateAnimator.ANIMATION_DURATION_STANDARD);
}
private boolean shouldShowPriorityOnboarding() {
@@ -523,9 +524,9 @@ public class NotificationConversationInfo extends LinearLayout implements
boolean ignoreDnd = false;
try {
- ignoreDnd = (mINotificationManager
- .getConsolidatedNotificationPolicy().priorityConversationSenders
- & NotificationManager.Policy.CONVERSATION_SENDERS_IMPORTANT) != 0;
+ ignoreDnd = mINotificationManager
+ .getConsolidatedNotificationPolicy().priorityConversationSenders ==
+ NotificationManager.Policy.CONVERSATION_SENDERS_IMPORTANT;
} catch (RemoteException e) {
Log.e(TAG, "Could not check conversation senders", e);
}
@@ -540,31 +541,16 @@ public class NotificationConversationInfo extends LinearLayout implements
.setView(onboardingView)
.setIgnoresDnd(ignoreDnd)
.setShowsAsBubble(showAsBubble)
+ .setIcon(mIconFactory.getBaseIconDrawable(mShortcutInfo))
+ .setBadge(mIconFactory.getAppBadge(
+ mPackageName, UserHandle.getUserId(mSbn.getUid())))
+ .setOnSettingsClick(mOnConversationSettingsClickListener)
.build();
controller.init();
controller.show();
}
- /**
- * Closes the controls and commits the updated importance values (indirectly).
- *
- * <p><b>Note,</b> this will only get called once the view is dismissing. This means that the
- * user does not have the ability to undo the action anymore.
- */
- @VisibleForTesting
- void closeControls(View v, boolean save) {
- int[] parentLoc = new int[2];
- int[] targetLoc = new int[2];
- mGutsContainer.getLocationOnScreen(parentLoc);
- v.getLocationOnScreen(targetLoc);
- final int centerX = v.getWidth() / 2;
- final int centerY = v.getHeight() / 2;
- final int x = targetLoc[0] - parentLoc[0] + centerX;
- final int y = targetLoc[1] - parentLoc[1] + centerY;
- mGutsContainer.closeControls(x, y, save, false /* force */);
- }
-
@Override
public void setGutsParent(NotificationGuts guts) {
mGutsContainer = guts;
@@ -634,8 +620,7 @@ public class NotificationConversationInfo extends LinearLayout implements
try {
switch (mAction) {
case ACTION_FAVORITE:
- mChannelToUpdate.setImportantConversation(
- !mChannelToUpdate.isImportantConversation());
+ mChannelToUpdate.setImportantConversation(true);
if (mChannelToUpdate.isImportantConversation()) {
mChannelToUpdate.setAllowBubbles(true);
if (mAppBubble == BUBBLE_PREFERENCE_NONE) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGuts.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGuts.java
index c762b73a1648..eeac46a60ac8 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGuts.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGuts.java
@@ -22,12 +22,14 @@ import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.drawable.Drawable;
+import android.os.Bundle;
import android.os.Handler;
import android.util.AttributeSet;
import android.util.Log;
import android.view.View;
import android.view.ViewAnimationUtils;
import android.view.accessibility.AccessibilityEvent;
+import android.view.accessibility.AccessibilityNodeInfo;
import android.widget.FrameLayout;
import androidx.annotation.Nullable;
@@ -59,6 +61,31 @@ public class NotificationGuts extends FrameLayout {
private GutsContent mGutsContent;
+ private View.AccessibilityDelegate mGutsContentAccessibilityDelegate =
+ new View.AccessibilityDelegate() {
+ @Override
+ public void onInitializeAccessibilityNodeInfo(
+ View host, AccessibilityNodeInfo info) {
+ super.onInitializeAccessibilityNodeInfo(host, info);
+ info.addAction(AccessibilityNodeInfo.AccessibilityAction.ACTION_LONG_CLICK);
+ }
+
+ @Override
+ public boolean performAccessibilityAction(View host, int action, Bundle args) {
+ if (super.performAccessibilityAction(host, action, args)) {
+ return true;
+ }
+
+ switch (action) {
+ case AccessibilityNodeInfo.ACTION_LONG_CLICK:
+ closeControls(host, false);
+ return true;
+ }
+
+ return false;
+ }
+ };
+
public interface GutsContent {
public void setGutsParent(NotificationGuts listener);
@@ -110,6 +137,11 @@ public class NotificationGuts extends FrameLayout {
* view on the lockscreen
*/
boolean needsFalsingProtection();
+
+ /**
+ * Equivalent to {@link View#setAccessibilityDelegate(AccessibilityDelegate)}
+ */
+ void setAccessibilityDelegate(AccessibilityDelegate gutsContentAccessibilityDelegate);
}
public interface OnGutsClosedListener {
@@ -146,6 +178,8 @@ public class NotificationGuts extends FrameLayout {
}
public void setGutsContent(GutsContent content) {
+ content.setGutsParent(this);
+ content.setAccessibilityDelegate(mGutsContentAccessibilityDelegate);
mGutsContent = content;
removeAllViews();
addView(mGutsContent.getContentView());
@@ -237,13 +271,29 @@ public class NotificationGuts extends FrameLayout {
/**
* Closes any exposed guts/views.
+ */
+ public void closeControls(View eventSource, boolean save) {
+ int[] parentLoc = new int[2];
+ int[] targetLoc = new int[2];
+ getLocationOnScreen(parentLoc);
+ eventSource.getLocationOnScreen(targetLoc);
+ final int centerX = eventSource.getWidth() / 2;
+ final int centerY = eventSource.getHeight() / 2;
+ final int x = targetLoc[0] - parentLoc[0] + centerX;
+ final int y = targetLoc[1] - parentLoc[1] + centerY;
+
+ closeControls(x, y, save, false);
+ }
+
+ /**
+ * Closes any exposed guts/views.
*
* @param x x coordinate to animate the close circular reveal with
* @param y y coordinate to animate the close circular reveal with
* @param save whether the state should be saved
* @param force whether the guts should be force-closed regardless of state.
*/
- public void closeControls(int x, int y, boolean save, boolean force) {
+ private void closeControls(int x, int y, boolean save, boolean force) {
// First try to dismiss any blocking helper.
boolean wasBlockingHelperDismissed =
Dependency.get(NotificationBlockingHelperManager.class)
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 a64dcdffff1e..1074adc3383d 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
@@ -216,6 +216,11 @@ public class NotificationGutsManager implements Dumpable, NotificationLifetimeEx
}
}
+ private void startConversationSettingsActivity(int uid, ExpandableNotificationRow row) {
+ final Intent intent = new Intent(Settings.ACTION_CONVERSATION_SETTINGS);
+ mNotificationActivityStarter.startNotificationGutsIntent(intent, uid, row);
+ }
+
private boolean bindGuts(final ExpandableNotificationRow row) {
row.ensureGutsInflated();
return bindGuts(row, mGutsMenuItem);
@@ -438,6 +443,12 @@ public class NotificationGutsManager implements Dumpable, NotificationLifetimeEx
mListContainer.getSwipeActionHelper().snooze(sbn, hours);
};
+ final NotificationConversationInfo.OnConversationSettingsClickListener
+ onConversationSettingsListener =
+ () -> {
+ startConversationSettingsActivity(sbn.getUid(), row);
+ };
+
if (!userHandle.equals(UserHandle.ALL)
|| mLockscreenUserManager.getCurrentUserId() == UserHandle.USER_SYSTEM) {
onSettingsClick = (View v, NotificationChannel channel, int appUid) -> {
@@ -468,7 +479,8 @@ public class NotificationGutsManager implements Dumpable, NotificationLifetimeEx
mBuilderProvider,
mDeviceProvisionedController.isDeviceProvisioned(),
mMainHandler,
- mBgHandler);
+ mBgHandler,
+ onConversationSettingsListener);
}
/**
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 334599930b63..a131ebef77db 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
@@ -141,7 +141,7 @@ public class NotificationInfo extends LinearLayout implements NotificationGuts.G
// used by standard ui
private OnClickListener mOnDismissSettings = v -> {
mPressedApply = true;
- closeControls(v, true);
+ mGutsContainer.closeControls(v, true);
};
public NotificationInfo(Context context, AttributeSet attrs) {
@@ -250,7 +250,7 @@ public class NotificationInfo extends LinearLayout implements NotificationGuts.G
View done = findViewById(R.id.done);
done.setOnClickListener(mOnDismissSettings);
-
+ done.setAccessibilityDelegate(mGutsContainer.getAccessibilityDelegate());
View silent = findViewById(R.id.silence);
View alert = findViewById(R.id.alert);
@@ -330,7 +330,7 @@ public class NotificationInfo extends LinearLayout implements NotificationGuts.G
mUniqueChannelsInRow, mPkgIcon, mOnSettingsClickListener);
mChannelEditorDialogController.setOnFinishListener(() -> {
mPresentingChannelEditorDialog = false;
- closeControls(this, false);
+ mGutsContainer.closeControls(this, false);
});
mChannelEditorDialogController.show();
}
@@ -375,14 +375,11 @@ public class NotificationInfo extends LinearLayout implements NotificationGuts.G
}
}
TextView groupNameView = findViewById(R.id.group_name);
- View divider = findViewById(R.id.group_divider);
if (groupName != null) {
groupNameView.setText(groupName);
groupNameView.setVisibility(VISIBLE);
- divider.setVisibility(VISIBLE);
} else {
groupNameView.setVisibility(GONE);
- divider.setVisibility(GONE);
}
}
@@ -531,25 +528,6 @@ public class NotificationInfo extends LinearLayout implements NotificationGuts.G
return intent;
}
- /**
- * Closes the controls and commits the updated importance values (indirectly).
- *
- * <p><b>Note,</b> this will only get called once the view is dismissing. This means that the
- * user does not have the ability to undo the action anymore.
- */
- @VisibleForTesting
- void closeControls(View v, boolean save) {
- int[] parentLoc = new int[2];
- int[] targetLoc = new int[2];
- mGutsContainer.getLocationOnScreen(parentLoc);
- v.getLocationOnScreen(targetLoc);
- final int centerX = v.getWidth() / 2;
- final int centerY = v.getHeight() / 2;
- final int x = targetLoc[0] - parentLoc[0] + centerX;
- final int y = targetLoc[1] - parentLoc[1] + centerY;
- mGutsContainer.closeControls(x, y, save, false /* force */);
- }
-
@Override
public void setGutsParent(NotificationGuts guts) {
mGutsContainer = guts;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationSnooze.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationSnooze.java
index cde3dfd66aaf..1ffb244b51c9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationSnooze.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationSnooze.java
@@ -380,16 +380,8 @@ public class NotificationSnooze extends LinearLayout
private void undoSnooze(View v) {
mSelectedOption = null;
- int[] parentLoc = new int[2];
- int[] targetLoc = new int[2];
- mGutsContainer.getLocationOnScreen(parentLoc);
- v.getLocationOnScreen(targetLoc);
- final int centerX = v.getWidth() / 2;
- final int centerY = v.getHeight() / 2;
- final int x = targetLoc[0] - parentLoc[0] + centerX;
- final int y = targetLoc[1] - parentLoc[1] + centerY;
showSnoozeOptions(false);
- mGutsContainer.closeControls(x, y, false /* save */, false /* force */);
+ mGutsContainer.closeControls(v, false);
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/PartialConversationInfo.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/PartialConversationInfo.java
index ea059cbcf3e1..186ffa67f046 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/PartialConversationInfo.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/PartialConversationInfo.java
@@ -89,7 +89,7 @@ public class PartialConversationInfo extends LinearLayout implements
private OnClickListener mOnDone = v -> {
mPressedApply = true;
- closeControls(v, true);
+ mGutsContainer.closeControls(v, true);
};
public PartialConversationInfo(Context context, AttributeSet attrs) {
@@ -132,6 +132,7 @@ public class PartialConversationInfo extends LinearLayout implements
View done = findViewById(R.id.done);
done.setOnClickListener(mOnDone);
+ done.setAccessibilityDelegate(mGutsContainer.getAccessibilityDelegate());
}
private void bindActions() {
@@ -147,8 +148,7 @@ public class PartialConversationInfo extends LinearLayout implements
}
private void bindHeader() {
- bindConversationDetails();
-
+ bindPackage();
// Delegate
bindDelegate();
}
@@ -172,58 +172,13 @@ public class PartialConversationInfo extends LinearLayout implements
mUniqueChannelsInRow, mPkgIcon, mOnSettingsClickListener);
mChannelEditorDialogController.setOnFinishListener(() -> {
mPresentingChannelEditorDialog = false;
- closeControls(this, false);
+ mGutsContainer.closeControls(this, false);
});
mChannelEditorDialogController.show();
}
});
}
- private void bindConversationDetails() {
- final TextView channelName = findViewById(R.id.parent_channel_name);
- channelName.setText(mNotificationChannel.getName());
-
- bindGroup();
- bindName();
- bindPackage();
- bindIcon();
- }
-
- private void bindName() {
- TextView name = findViewById(R.id.name);
- Bundle extras = mSbn.getNotification().extras;
- CharSequence nameString = extras.getCharSequence(Notification.EXTRA_CONVERSATION_TITLE, "");
- if (TextUtils.isEmpty(nameString)) {
- nameString = extras.getCharSequence(Notification.EXTRA_TITLE, "");
- }
- name.setText(nameString);
- }
-
- private void bindIcon() {
- ImageView image = findViewById(R.id.conversation_icon);
- if (mSbn.getNotification().extras.getBoolean(EXTRA_IS_GROUP_CONVERSATION, false)) {
- // TODO: maybe use a generic group icon, or a composite of recent senders
- image.setImageDrawable(mPkgIcon);
- } else {
- final List<Notification.MessagingStyle.Message> messages =
- Notification.MessagingStyle.Message.getMessagesFromBundleArray(
- (Parcelable[]) mSbn.getNotification().extras.get(
- Notification.EXTRA_MESSAGES));
-
- final Notification.MessagingStyle.Message latestMessage =
- Notification.MessagingStyle.findLatestIncomingMessage(messages);
- Icon personIcon = null;
- if (latestMessage != null && latestMessage.getSenderPerson() != null) {
- personIcon = latestMessage.getSenderPerson().getIcon();
- }
- if (personIcon != null) {
- image.setImageIcon(latestMessage.getSenderPerson().getIcon());
- } else {
- image.setImageDrawable(mPkgIcon);
- }
- }
- }
-
private void bindPackage() {
ApplicationInfo info;
try {
@@ -240,7 +195,10 @@ public class PartialConversationInfo extends LinearLayout implements
} catch (PackageManager.NameNotFoundException e) {
mPkgIcon = mPm.getDefaultActivityIcon();
}
- ((TextView) findViewById(R.id.pkg_name)).setText(mAppName);
+ TextView name = findViewById(R.id.name);
+ name.setText(mAppName);
+ ImageView image = findViewById(R.id.icon);
+ image.setImageDrawable(mPkgIcon);
}
private void bindDelegate() {
@@ -269,14 +227,11 @@ public class PartialConversationInfo extends LinearLayout implements
}
}
TextView groupNameView = findViewById(R.id.group_name);
- View groupDivider = findViewById(R.id.group_divider);
if (groupName != null) {
groupNameView.setText(groupName);
groupNameView.setVisibility(VISIBLE);
- groupDivider.setVisibility(VISIBLE);
} else {
groupNameView.setVisibility(GONE);
- groupDivider.setVisibility(GONE);
}
}
@@ -320,25 +275,6 @@ public class PartialConversationInfo extends LinearLayout implements
}
}
- /**
- * Closes the controls and commits the updated importance values (indirectly).
- *
- * <p><b>Note,</b> this will only get called once the view is dismissing. This means that the
- * user does not have the ability to undo the action anymore.
- */
- @VisibleForTesting
- void closeControls(View v, boolean save) {
- int[] parentLoc = new int[2];
- int[] targetLoc = new int[2];
- mGutsContainer.getLocationOnScreen(parentLoc);
- v.getLocationOnScreen(targetLoc);
- final int centerX = v.getWidth() / 2;
- final int centerY = v.getHeight() / 2;
- final int x = targetLoc[0] - parentLoc[0] + centerX;
- final int y = targetLoc[1] - parentLoc[1] + centerY;
- mGutsContainer.closeControls(x, y, save, false /* force */);
- }
-
@Override
public void setGutsParent(NotificationGuts guts) {
mGutsContainer = guts;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/PriorityOnboardingDialogController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/PriorityOnboardingDialogController.kt
index d1b405256f39..fab367df8fde 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/PriorityOnboardingDialogController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/PriorityOnboardingDialogController.kt
@@ -16,37 +16,57 @@
package com.android.systemui.statusbar.notification.row
+import android.animation.Animator
+import android.animation.AnimatorListenerAdapter
+import android.animation.AnimatorSet
+import android.animation.ValueAnimator
import android.app.Dialog
import android.content.Context
import android.graphics.Color
import android.graphics.PixelFormat
import android.graphics.drawable.ColorDrawable
+import android.graphics.drawable.Drawable
+import android.graphics.drawable.GradientDrawable
+import android.text.SpannableStringBuilder
+import android.text.style.BulletSpan
import android.view.Gravity
import android.view.View
-import android.view.View.GONE
+import android.view.ViewGroup
import android.view.ViewGroup.LayoutParams.MATCH_PARENT
import android.view.ViewGroup.LayoutParams.WRAP_CONTENT
import android.view.Window
import android.view.WindowInsets.Type.statusBars
import android.view.WindowManager
-import android.widget.LinearLayout
+import android.view.animation.Interpolator
+import android.view.animation.PathInterpolator
+import android.widget.ImageView
import android.widget.TextView
+import com.android.systemui.Interpolators.LINEAR_OUT_SLOW_IN
import com.android.systemui.Prefs
import com.android.systemui.R
-import java.lang.IllegalStateException
+import com.android.systemui.statusbar.notification.row.NotificationConversationInfo.OnConversationSettingsClickListener
import javax.inject.Inject
+
/**
* Controller to handle presenting the priority conversations onboarding dialog
*/
class PriorityOnboardingDialogController @Inject constructor(
- val view: View,
- val context: Context,
- val ignoresDnd: Boolean,
- val showsAsBubble: Boolean
+ val view: View,
+ val context: Context,
+ private val ignoresDnd: Boolean,
+ private val showsAsBubble: Boolean,
+ val icon : Drawable,
+ private val onConversationSettingsClickListener : OnConversationSettingsClickListener,
+ val badge : Drawable
) {
private lateinit var dialog: Dialog
+ private val OVERSHOOT: Interpolator = PathInterpolator(0.4f, 0f, 0.2f, 1.4f)
+ private val IMPORTANCE_ANIM_DELAY = 150L
+ private val IMPORTANCE_ANIM_GROW_DURATION = 250L
+ private val IMPORTANCE_ANIM_SHRINK_DURATION = 200L
+ private val IMPORTANCE_ANIM_SHRINK_DELAY = 25L
fun init() {
initDialog()
@@ -62,11 +82,22 @@ class PriorityOnboardingDialogController @Inject constructor(
dialog.dismiss()
}
+ private fun settings() {
+ // Log that the user has seen the onboarding
+ Prefs.putBoolean(context, Prefs.Key.HAS_SEEN_PRIORITY_ONBOARDING, true)
+ dialog.dismiss()
+ onConversationSettingsClickListener?.onClick()
+ }
+
class Builder @Inject constructor() {
private lateinit var view: View
private lateinit var context: Context
private var ignoresDnd = false
private var showAsBubble = false
+ private lateinit var icon: Drawable
+ private lateinit var onConversationSettingsClickListener
+ : OnConversationSettingsClickListener
+ private lateinit var badge : Drawable
fun setView(v: View): Builder {
view = v
@@ -88,9 +119,24 @@ class PriorityOnboardingDialogController @Inject constructor(
return this
}
+ fun setIcon(draw : Drawable) : Builder {
+ icon = draw
+ return this
+ }
+ fun setBadge(badge : Drawable) : Builder {
+ this.badge = badge
+ return this
+ }
+
+ fun setOnSettingsClick(onClick : OnConversationSettingsClickListener) : Builder {
+ onConversationSettingsClickListener = onClick
+ return this
+ }
+
fun build(): PriorityOnboardingDialogController {
val controller = PriorityOnboardingDialogController(
- view, context, ignoresDnd, showAsBubble)
+ view, context, ignoresDnd, showAsBubble, icon,
+ onConversationSettingsClickListener, badge)
return controller
}
}
@@ -113,13 +159,91 @@ class PriorityOnboardingDialogController @Inject constructor(
done()
}
- if (!ignoresDnd) {
- findViewById<LinearLayout>(R.id.ignore_dnd_tip).visibility = GONE
+ findViewById<TextView>(R.id.settings_button)?.setOnClickListener {
+ settings()
}
- if (!showsAsBubble) {
- findViewById<LinearLayout>(R.id.floating_bubble_tip).visibility = GONE
+ findViewById<ImageView>(R.id.conversation_icon)?.setImageDrawable(icon)
+ findViewById<ImageView>(R.id.icon)?.setImageDrawable(badge)
+ val mImportanceRingView = findViewById<ImageView>(R.id.conversation_icon_badge_ring)
+ val conversationIconBadgeBg = findViewById<ImageView>(R.id.conversation_icon_badge_bg)
+
+ val ring: GradientDrawable = mImportanceRingView.drawable as GradientDrawable
+ ring.mutate()
+ val bg = conversationIconBadgeBg.drawable as GradientDrawable
+ bg.mutate()
+ val ringColor = context.getResources()
+ .getColor(com.android.internal.R.color.conversation_important_highlight)
+ val standardThickness = context.resources.getDimensionPixelSize(
+ com.android.internal.R.dimen.importance_ring_stroke_width)
+ val largeThickness = context.resources.getDimensionPixelSize(
+ com.android.internal.R.dimen.importance_ring_anim_max_stroke_width)
+ val standardSize = context.resources.getDimensionPixelSize(
+ com.android.internal.R.dimen.importance_ring_size)
+ val baseSize = standardSize - standardThickness * 2
+ val largeSize = baseSize + largeThickness * 2
+ val bgSize = context.resources.getDimensionPixelSize(
+ com.android.internal.R.dimen.conversation_icon_size_badged)
+
+ val animatorUpdateListener: ValueAnimator.AnimatorUpdateListener
+ = ValueAnimator.AnimatorUpdateListener { animation ->
+ val strokeWidth = animation.animatedValue as Int
+ ring.setStroke(strokeWidth, ringColor)
+ val newSize = baseSize + strokeWidth * 2
+ ring.setSize(newSize, newSize)
+ mImportanceRingView.invalidate()
+ }
+
+ val growAnimation: ValueAnimator = ValueAnimator.ofInt(0, largeThickness)
+ growAnimation.interpolator = LINEAR_OUT_SLOW_IN
+ growAnimation.duration = IMPORTANCE_ANIM_GROW_DURATION
+ growAnimation.addUpdateListener(animatorUpdateListener)
+
+ val shrinkAnimation: ValueAnimator
+ = ValueAnimator.ofInt(largeThickness, standardThickness)
+ shrinkAnimation.duration = IMPORTANCE_ANIM_SHRINK_DURATION
+ shrinkAnimation.startDelay = IMPORTANCE_ANIM_SHRINK_DELAY
+ shrinkAnimation.interpolator = OVERSHOOT
+ shrinkAnimation.addUpdateListener(animatorUpdateListener)
+ shrinkAnimation.addListener(object : AnimatorListenerAdapter() {
+ override fun onAnimationStart(animation: Animator?) {
+ // Shrink the badge bg so that it doesn't peek behind the animation
+ bg.setSize(baseSize, baseSize);
+ conversationIconBadgeBg.invalidate();
+ }
+
+ override fun onAnimationEnd(animation: Animator?) {
+ // Reset bg back to normal size
+ bg.setSize(bgSize, bgSize);
+ conversationIconBadgeBg.invalidate();
+
+ }
+ })
+
+ val anims = AnimatorSet()
+ anims.startDelay = IMPORTANCE_ANIM_DELAY
+ anims.playSequentially(growAnimation, shrinkAnimation)
+
+ val gapWidth = dialog.context.getResources().getDimensionPixelSize(
+ R.dimen.conversation_onboarding_bullet_gap_width)
+ val description = SpannableStringBuilder()
+ description.append(context.getText(R.string.priority_onboarding_show_at_top_text),
+ BulletSpan(gapWidth), /* flags */0)
+ description.append(System.lineSeparator())
+ description.append(context.getText(R.string.priority_onboarding_show_avatar_text),
+ BulletSpan(gapWidth), /* flags */0)
+ if (showsAsBubble) {
+ description.append(System.lineSeparator())
+ description.append(context.getText(
+ R.string.priority_onboarding_appear_as_bubble_text),
+ BulletSpan(gapWidth), /* flags */0)
+ }
+ if (ignoresDnd) {
+ description.append(System.lineSeparator())
+ description.append(context.getText(R.string.priority_onboarding_ignores_dnd_text),
+ BulletSpan(gapWidth), /* flags */0)
}
+ findViewById<TextView>(R.id.behaviors).setText(description)
window?.apply {
setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT))
@@ -129,18 +253,18 @@ class PriorityOnboardingDialogController @Inject constructor(
attributes = attributes.apply {
format = PixelFormat.TRANSLUCENT
- title = ChannelEditorDialogController::class.java.simpleName
+ title = PriorityOnboardingDialogController::class.java.simpleName
gravity = Gravity.BOTTOM or Gravity.CENTER_HORIZONTAL
fitInsetsTypes = attributes.fitInsetsTypes and statusBars().inv()
width = MATCH_PARENT
height = WRAP_CONTENT
}
}
+ anims.start()
}
}
private val wmFlags = (WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS
- or WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
or WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH
or WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED)
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationConversationTemplateViewWrapper.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationConversationTemplateViewWrapper.kt
index 15499b87d56d..fe70c818216e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationConversationTemplateViewWrapper.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationConversationTemplateViewWrapper.kt
@@ -50,6 +50,7 @@ class NotificationConversationTemplateViewWrapper constructor(
private lateinit var conversationBadgeBg: View
private lateinit var expandButton: View
private lateinit var expandButtonContainer: View
+ private lateinit var expandButtonInnerContainer: View
private lateinit var imageMessageContainer: ViewGroup
private lateinit var messagingLinearLayout: MessagingLinearLayout
private lateinit var conversationTitleView: View
@@ -69,6 +70,8 @@ class NotificationConversationTemplateViewWrapper constructor(
expandButton = requireViewById(com.android.internal.R.id.expand_button)
expandButtonContainer =
requireViewById(com.android.internal.R.id.expand_button_container)
+ expandButtonInnerContainer =
+ requireViewById(com.android.internal.R.id.expand_button_inner_container)
importanceRing = requireViewById(com.android.internal.R.id.conversation_icon_badge_ring)
appName = requireViewById(com.android.internal.R.id.app_name_text)
conversationTitleView = requireViewById(com.android.internal.R.id.conversation_text)
@@ -134,6 +137,8 @@ class NotificationConversationTemplateViewWrapper constructor(
)
}
+ override fun getExpandButton() = expandButtonInnerContainer
+
override fun setShelfIconVisible(visible: Boolean) {
if (conversationLayout.isImportantConversation) {
if (conversationIconView.visibility != GONE) {
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 f8b783113ccb..c747a7c300b7 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
@@ -262,7 +262,10 @@ public class NotificationHeaderViewWrapper extends NotificationViewWrapper {
stack.push(mView);
while (!stack.isEmpty()) {
View child = stack.pop();
- if (child instanceof ImageView) {
+ if (child instanceof ImageView
+ // Skip the importance ring for conversations, disabled cropping is needed for
+ // its animation
+ && child.getId() != com.android.internal.R.id.conversation_icon_badge_ring) {
((ImageView) child).setCropToPadding(true);
} else if (child instanceof ViewGroup){
ViewGroup group = (ViewGroup) child;
@@ -317,6 +320,11 @@ public class NotificationHeaderViewWrapper extends NotificationViewWrapper {
}
@Override
+ public View getExpandButton() {
+ return mExpandButton;
+ }
+
+ @Override
public int getOriginalIconColor() {
return mIcon.getOriginalIconColor();
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationViewWrapper.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationViewWrapper.java
index 02e537d2879f..30080e3d8cc2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationViewWrapper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationViewWrapper.java
@@ -240,6 +240,13 @@ public abstract class NotificationViewWrapper implements TransformableView {
return null;
}
+ /**
+ * @return the expand button if it exists
+ */
+ public @Nullable View getExpandButton() {
+ return null;
+ }
+
public int getOriginalIconColor() {
return Notification.COLOR_INVALID;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManager.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManager.kt
index ba7675f27cf4..0bdac39f35e9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManager.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManager.kt
@@ -287,21 +287,17 @@ class NotificationSectionsManager @Inject internal constructor(
// Is there a section discontinuity? This usually occurs due to HUNs
if (prev?.entry?.bucket?.let { it > child.entry.bucket } == true) {
// Remove existing headers, and move the Incoming header if necessary
- if (alertingHeaderTarget != -1) {
- if (showHeaders && incomingHeaderTarget != -1) {
- incomingHeaderTarget = alertingHeaderTarget
- }
- alertingHeaderTarget = -1
- }
- if (peopleHeaderTarget != -1) {
- if (showHeaders && incomingHeaderTarget != -1) {
- incomingHeaderTarget = peopleHeaderTarget
- }
- peopleHeaderTarget = -1
- }
- if (showHeaders && incomingHeaderTarget == -1) {
- incomingHeaderTarget = 0
+ incomingHeaderTarget = when {
+ !showHeaders -> -1
+ incomingHeaderTarget != -1 -> incomingHeaderTarget
+ peopleHeaderTarget != -1 -> peopleHeaderTarget
+ alertingHeaderTarget != -1 -> alertingHeaderTarget
+ gentleHeaderTarget != -1 -> gentleHeaderTarget
+ else -> 0
}
+ peopleHeaderTarget = -1
+ alertingHeaderTarget = -1
+ gentleHeaderTarget = -1
// Walk backwards changing all previous notifications to the Incoming
// section
for (j in i - 1 downTo lastIncomingIndex + 1) {
@@ -323,6 +319,9 @@ class NotificationSectionsManager @Inject internal constructor(
peopleHeaderTarget = i
// Offset the target if there are other headers before this that
// will be moved.
+ if (currentIncomingHeaderIdx != -1 && incomingHeaderTarget == -1) {
+ peopleHeaderTarget--
+ }
if (currentPeopleHeaderIdx != -1) {
peopleHeaderTarget--
}
@@ -340,6 +339,13 @@ class NotificationSectionsManager @Inject internal constructor(
alertingHeaderTarget = i
// Offset the target if there are other headers before this that
// will be moved.
+ if (currentIncomingHeaderIdx != -1 && incomingHeaderTarget == -1) {
+ alertingHeaderTarget--
+ }
+ if (currentPeopleHeaderIdx != -1 && peopleHeaderTarget == -1) {
+ // People header will be removed
+ alertingHeaderTarget--
+ }
if (currentAlertingHeaderIdx != -1) {
alertingHeaderTarget--
}
@@ -354,6 +360,17 @@ class NotificationSectionsManager @Inject internal constructor(
gentleHeaderTarget = i
// Offset the target if there are other headers before this that
// will be moved.
+ if (currentIncomingHeaderIdx != -1 && incomingHeaderTarget == -1) {
+ gentleHeaderTarget--
+ }
+ if (currentPeopleHeaderIdx != -1 && peopleHeaderTarget == -1) {
+ // People header will be removed
+ gentleHeaderTarget--
+ }
+ if (currentAlertingHeaderIdx != -1 && alertingHeaderTarget == -1) {
+ // Alerting header will be removed
+ gentleHeaderTarget--
+ }
if (currentGentleHeaderIdx != -1) {
gentleHeaderTarget--
}
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 325c8c0e506a..684bf1958154 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
@@ -146,6 +146,7 @@ import com.android.systemui.statusbar.phone.HeadsUpManagerPhone;
import com.android.systemui.statusbar.phone.HeadsUpTouchHelper;
import com.android.systemui.statusbar.phone.KeyguardBypassController;
import com.android.systemui.statusbar.phone.LockscreenGestureLogger;
+import com.android.systemui.statusbar.phone.LockscreenGestureLogger.LockscreenUiEvent;
import com.android.systemui.statusbar.phone.NotificationGroupManager;
import com.android.systemui.statusbar.phone.NotificationGroupManager.OnGroupChangeListener;
import com.android.systemui.statusbar.phone.NotificationIconAreaController;
@@ -6538,7 +6539,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd
return row.canViewBeDismissed();
}
if (v instanceof PeopleHubView) {
- return true;
+ return ((PeopleHubView) v).getCanSwipe();
}
return false;
}
@@ -6633,6 +6634,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd
MetricsEvent.ACTION_LS_SHADE,
(int) (dragLengthY / mDisplayMetrics.density),
0 /* velocityDp - N/A */);
+ mLockscreenGestureLogger.log(LockscreenUiEvent.LOCKSCREEN_PULL_SHADE_OPEN);
if (!mAmbientState.isDozing() || startingChild != null) {
// We have notifications, go to locked shade.
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/PeopleHubView.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/PeopleHubView.kt
index a1d898fb84b0..8f77a1d776e4 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/PeopleHubView.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/PeopleHubView.kt
@@ -72,7 +72,7 @@ class PeopleHubView(context: Context, attrs: AttributeSet) :
}
}
- var canSwipe: Boolean = true
+ var canSwipe: Boolean = false
set(value) {
if (field != value) {
if (field) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/AutoTileManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/AutoTileManager.java
index 79515415f1c3..fc8c8dbba7fd 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/AutoTileManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/AutoTileManager.java
@@ -274,7 +274,7 @@ public class AutoTileManager {
}
if (value != 0) {
if (mSpec.startsWith(CustomTile.PREFIX)) {
- mHost.addTile(CustomTile.getComponentFromSpec(mSpec));
+ mHost.addTile(CustomTile.getComponentFromSpec(mSpec), /* end */ true);
} else {
mHost.addTile(mSpec);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockscreenGestureLogger.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockscreenGestureLogger.java
index 8c3420a522ec..83d398d3e7ae 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockscreenGestureLogger.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockscreenGestureLogger.java
@@ -20,6 +20,9 @@ import android.metrics.LogMaker;
import android.util.ArrayMap;
import com.android.internal.logging.MetricsLogger;
+import com.android.internal.logging.UiEvent;
+import com.android.internal.logging.UiEventLogger;
+import com.android.internal.logging.UiEventLoggerImpl;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.systemui.Dependency;
import com.android.systemui.EventLogConstants;
@@ -34,6 +37,56 @@ import javax.inject.Singleton;
*/
@Singleton
public class LockscreenGestureLogger {
+
+ /**
+ * Contains Lockscreen related Westworld UiEvent enums.
+ */
+ public enum LockscreenUiEvent implements UiEventLogger.UiEventEnum {
+ @UiEvent(doc = "Lockscreen > Pull shade open")
+ LOCKSCREEN_PULL_SHADE_OPEN(539),
+
+ @UiEvent(doc = "Lockscreen > Tap on lock, locks phone")
+ LOCKSCREEN_LOCK_TAP(540),
+
+ @UiEvent(doc = "Lockscreen > Swipe down to open quick settings")
+ LOCKSCREEN_QUICK_SETTINGS_OPEN(541),
+
+ @UiEvent(doc = "Swipe down to open quick settings when unlocked")
+ LOCKSCREEN_UNLOCKED_QUICK_SETTINGS_OPEN(542),
+
+ @UiEvent(doc = "Lockscreen > Tap on lock, shows hint")
+ LOCKSCREEN_LOCK_SHOW_HINT(543),
+
+ @UiEvent(doc = "Notification shade > Tap to open quick settings")
+ LOCKSCREEN_NOTIFICATION_SHADE_QUICK_SETTINGS_OPEN(544),
+
+ @UiEvent(doc = "Lockscreen > Dialer")
+ LOCKSCREEN_DIALER(545),
+
+ @UiEvent(doc = "Lockscreen > Camera")
+ LOCKSCREEN_CAMERA(546),
+
+ @UiEvent(doc = "Lockscreen > Unlock gesture")
+ LOCKSCREEN_UNLOCK(547),
+
+ @UiEvent(doc = "Lockscreen > Tap on notification, false touch rejection")
+ LOCKSCREEN_NOTIFICATION_FALSE_TOUCH(548),
+
+ @UiEvent(doc = "Expand the notification panel while unlocked")
+ LOCKSCREEN_UNLOCKED_NOTIFICATION_PANEL_EXPAND(549);
+
+ private final int mId;
+
+ LockscreenUiEvent(int id) {
+ mId = id;
+ }
+
+ @Override
+ public int getId() {
+ return mId;
+ }
+ }
+
private ArrayMap<Integer, Integer> mLegacyMap;
private final MetricsLogger mMetricsLogger = Dependency.get(MetricsLogger.class);
@@ -55,6 +108,13 @@ public class LockscreenGestureLogger {
}
/**
+ * Logs {@link LockscreenUiEvent}.
+ */
+ public void log(LockscreenUiEvent lockscreenUiEvent) {
+ new UiEventLoggerImpl().log(lockscreenUiEvent);
+ }
+
+ /**
* Record the location of a swipe gesture, expressed as percentages of the whole screen
* @param category the action
* @param xPercent x-location / width * 100
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockscreenLockIconController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockscreenLockIconController.java
index 8a5c8b0898bc..5d3910b4c415 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockscreenLockIconController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockscreenLockIconController.java
@@ -45,6 +45,7 @@ import com.android.systemui.statusbar.KeyguardIndicationController;
import com.android.systemui.statusbar.StatusBarState;
import com.android.systemui.statusbar.notification.NotificationWakeUpCoordinator;
import com.android.systemui.statusbar.notification.NotificationWakeUpCoordinator.WakeUpListener;
+import com.android.systemui.statusbar.phone.LockscreenGestureLogger.LockscreenUiEvent;
import com.android.systemui.statusbar.policy.AccessibilityController;
import com.android.systemui.statusbar.policy.ConfigurationController;
import com.android.systemui.statusbar.policy.ConfigurationController.ConfigurationListener;
@@ -436,6 +437,7 @@ public class LockscreenLockIconController {
private boolean handleLongClick(View view) {
mLockscreenGestureLogger.write(MetricsProto.MetricsEvent.ACTION_LS_LOCK,
0 /* lengthDp - N/A */, 0 /* velocityDp - N/A */);
+ mLockscreenGestureLogger.log(LockscreenUiEvent.LOCKSCREEN_LOCK_TAP);
mKeyguardIndicationController.showTransientIndication(
R.string.keyguard_indication_trust_disabled);
mKeyguardUpdateMonitor.onLockIconPressed();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java
index 26e80adafd3d..8954d98d0201 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java
@@ -59,6 +59,7 @@ import android.content.res.Configuration;
import android.database.ContentObserver;
import android.graphics.PixelFormat;
import android.graphics.Rect;
+import android.graphics.RectF;
import android.hardware.display.DisplayManager;
import android.inputmethodservice.InputMethodService;
import android.net.Uri;
@@ -83,6 +84,7 @@ import android.view.MotionEvent;
import android.view.Surface;
import android.view.View;
import android.view.ViewGroup;
+import android.view.ViewTreeObserver;
import android.view.WindowInsetsController.Appearance;
import android.view.WindowManager;
import android.view.WindowManager.LayoutParams;
@@ -94,6 +96,8 @@ import androidx.annotation.VisibleForTesting;
import com.android.internal.accessibility.dialog.AccessibilityButtonChooserActivity;
import com.android.internal.logging.MetricsLogger;
+import com.android.internal.logging.UiEvent;
+import com.android.internal.logging.UiEventLogger;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.internal.util.LatencyTracker;
import com.android.internal.view.AppearanceRegion;
@@ -217,11 +221,31 @@ public class NavigationBarFragment extends LifecycleFragment implements Callback
* original handle hidden and we'll flip the visibilities once the
* {@link #mTasksFrozenListener} fires
*/
- private NavigationHandle mOrientationHandle;
+ private VerticalNavigationHandle mOrientationHandle;
private WindowManager.LayoutParams mOrientationParams;
private int mStartingQuickSwitchRotation;
private int mCurrentRotation;
private boolean mFixedRotationEnabled;
+ private ViewTreeObserver.OnGlobalLayoutListener mOrientationHandleGlobalLayoutListener;
+ private UiEventLogger mUiEventLogger;
+
+ @com.android.internal.annotations.VisibleForTesting
+ public enum NavBarActionEvent implements UiEventLogger.UiEventEnum {
+
+ @UiEvent(doc = "Assistant invoked via home button long press.")
+ NAVBAR_ASSIST_LONGPRESS(550);
+
+ private final int mId;
+
+ NavBarActionEvent(int id) {
+ mId = id;
+ }
+
+ @Override
+ public int getId() {
+ return mId;
+ }
+ }
/** Only for default display */
@Nullable
@@ -364,7 +388,8 @@ public class NavigationBarFragment extends LifecycleFragment implements Callback
ShadeController shadeController,
NotificationRemoteInputManager notificationRemoteInputManager,
SystemActions systemActions,
- @Main Handler mainHandler) {
+ @Main Handler mainHandler,
+ UiEventLogger uiEventLogger) {
mAccessibilityManagerWrapper = accessibilityManagerWrapper;
mDeviceProvisionedController = deviceProvisionedController;
mStatusBarStateController = statusBarStateController;
@@ -384,6 +409,7 @@ public class NavigationBarFragment extends LifecycleFragment implements Callback
mRecentsOptional = recentsOptional;
mSystemActions = systemActions;
mHandler = mainHandler;
+ mUiEventLogger = uiEventLogger;
}
// ----- Fragment Lifecycle Callbacks -----
@@ -519,6 +545,8 @@ public class NavigationBarFragment extends LifecycleFragment implements Callback
getContext().getSystemService(DisplayManager.class).unregisterDisplayListener(this);
getBarTransitions().removeDarkIntensityListener(mOrientationHandleIntensityListener);
mWindowManager.removeView(mOrientationHandle);
+ mOrientationHandle.getViewTreeObserver().removeOnGlobalLayoutListener(
+ mOrientationHandleGlobalLayoutListener);
}
}
@@ -573,6 +601,20 @@ public class NavigationBarFragment extends LifecycleFragment implements Callback
PixelFormat.TRANSLUCENT);
mWindowManager.addView(mOrientationHandle, mOrientationParams);
mOrientationHandle.setVisibility(View.GONE);
+ mOrientationHandleGlobalLayoutListener =
+ () -> {
+ if (mStartingQuickSwitchRotation == -1) {
+ return;
+ }
+
+ RectF boundsOnScreen = mOrientationHandle.computeHomeHandleBounds();
+ mOrientationHandle.mapRectFromViewToScreenCoords(boundsOnScreen, true);
+ Rect boundsRounded = new Rect();
+ boundsOnScreen.roundOut(boundsRounded);
+ mNavigationBarView.setOrientedHandleSamplingRegion(boundsRounded);
+ };
+ mOrientationHandle.getViewTreeObserver().addOnGlobalLayoutListener(
+ mOrientationHandleGlobalLayoutListener);
}
private void orientSecondaryHomeHandle() {
@@ -621,6 +663,7 @@ public class NavigationBarFragment extends LifecycleFragment implements Callback
}
if (mNavigationBarView != null) {
mNavigationBarView.setVisibility(View.VISIBLE);
+ mNavigationBarView.setOrientedHandleSamplingRegion(null);
}
}
@@ -988,6 +1031,7 @@ public class NavigationBarFragment extends LifecycleFragment implements Callback
return false;
}
mMetricsLogger.action(MetricsEvent.ACTION_ASSIST_LONG_PRESS);
+ mUiEventLogger.log(NavBarActionEvent.NAVBAR_ASSIST_LONGPRESS);
Bundle args = new Bundle();
args.putInt(
AssistManager.INVOCATION_TYPE_KEY, AssistManager.INVOCATION_HOME_BUTTON_LONG_PRESS);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarInflaterView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarInflaterView.java
index 46c873db8a08..4337e20c0a39 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarInflaterView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarInflaterView.java
@@ -40,6 +40,7 @@ import com.android.systemui.shared.system.QuickStepContract;
import com.android.systemui.statusbar.phone.ReverseLinearLayout.ReverseRelativeLayout;
import com.android.systemui.statusbar.policy.KeyButtonView;
+import java.io.PrintWriter;
import java.util.Objects;
public class NavigationBarInflaterView extends FrameLayout
@@ -469,4 +470,10 @@ public class NavigationBarInflaterView extends FrameLayout
private static float convertDpToPx(Context context, float dp) {
return dp * context.getResources().getDisplayMetrics().density;
}
+
+ public void dump(PrintWriter pw) {
+ pw.println("NavigationBarInflaterView {");
+ pw.println(" mCurrentLayout: " + mCurrentLayout);
+ pw.println(" }");
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
index 2978772cac5e..4821d8c46ed4 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
@@ -35,6 +35,7 @@ import android.animation.PropertyValuesHolder;
import android.animation.TimeInterpolator;
import android.animation.ValueAnimator;
import android.annotation.DrawableRes;
+import android.annotation.Nullable;
import android.app.StatusBarManager;
import android.content.Context;
import android.content.res.Configuration;
@@ -158,6 +159,14 @@ public class NavigationBarView extends FrameLayout implements
*/
private ScreenPinningNotify mScreenPinningNotify;
private Rect mSamplingBounds = new Rect();
+ /**
+ * When quickswitching between apps of different orientations, we draw a secondary home handle
+ * in the position of the first app's orientation. This rect represents the region of that
+ * home handle so we can apply the correct light/dark luma on that.
+ * @see {@link NavigationBarFragment#mOrientationHandle}
+ */
+ @Nullable
+ private Rect mOrientedHandleSamplingRegion;
private class NavTransitionListener implements TransitionListener {
private boolean mBackTransitioning;
@@ -327,6 +336,10 @@ public class NavigationBarView extends FrameLayout implements
@Override
public Rect getSampledRegion(View sampledView) {
+ if (mOrientedHandleSamplingRegion != null) {
+ return mOrientedHandleSamplingRegion;
+ }
+
updateSamplingRect();
return mSamplingBounds;
}
@@ -897,6 +910,11 @@ public class NavigationBarView extends FrameLayout implements
}
}
+ void setOrientedHandleSamplingRegion(Rect orientedHandleSamplingRegion) {
+ mOrientedHandleSamplingRegion = orientedHandleSamplingRegion;
+ mRegionSamplingHelper.updateSamplingRect();
+ }
+
@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
super.onLayout(changed, left, top, right, bottom);
@@ -1190,6 +1208,8 @@ public class NavigationBarView extends FrameLayout implements
mIsVertical ? "true" : "false",
getLightTransitionsController().getCurrentDarkIntensity()));
+ pw.println(" mOrientedHandleSamplingRegion: " + mOrientedHandleSamplingRegion);
+
dumpButton(pw, "back", getBackButton());
dumpButton(pw, "home", getHomeButton());
dumpButton(pw, "rcnt", getRecentsButton());
@@ -1198,6 +1218,9 @@ public class NavigationBarView extends FrameLayout implements
pw.println(" }");
+ if (mNavigationInflaterView != null) {
+ mNavigationInflaterView.dump(pw);
+ }
mContextualButtonGroup.dump(pw);
mRecentsOnboarding.dump(pw);
mRegionSamplingHelper.dump(pw);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java
index f58cce58af74..9d3e915cad69 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java
@@ -19,6 +19,7 @@ import com.android.internal.util.ContrastColorUtil;
import com.android.settingslib.Utils;
import com.android.systemui.Interpolators;
import com.android.systemui.R;
+import com.android.systemui.bubbles.BubbleController;
import com.android.systemui.plugins.DarkIconDispatcher;
import com.android.systemui.plugins.DarkIconDispatcher.DarkReceiver;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
@@ -55,6 +56,7 @@ public class NotificationIconAreaController implements DarkReceiver,
private final NotificationWakeUpCoordinator mWakeUpCoordinator;
private final KeyguardBypassController mBypassController;
private final DozeParameters mDozeParameters;
+ private final BubbleController mBubbleController;
private int mIconSize;
private int mIconHPadding;
@@ -101,7 +103,8 @@ public class NotificationIconAreaController implements DarkReceiver,
KeyguardBypassController keyguardBypassController,
NotificationMediaManager notificationMediaManager,
NotificationListener notificationListener,
- DozeParameters dozeParameters) {
+ DozeParameters dozeParameters,
+ BubbleController bubbleController) {
mStatusBar = statusBar;
mContrastColorUtil = ContrastColorUtil.getInstance(context);
mContext = context;
@@ -112,6 +115,7 @@ public class NotificationIconAreaController implements DarkReceiver,
mWakeUpCoordinator = wakeUpCoordinator;
wakeUpCoordinator.addListener(this);
mBypassController = keyguardBypassController;
+ mBubbleController = bubbleController;
notificationListener.addNotificationSettingsListener(mSettingsListener);
initializeNotificationAreaViews(context);
@@ -291,6 +295,9 @@ public class NotificationIconAreaController implements DarkReceiver,
|| !entry.isPulseSuppressed())) {
return false;
}
+ if (mBubbleController.isBubbleExpanded(entry)) {
+ return false;
+ }
return true;
}
@@ -572,6 +579,9 @@ public class NotificationIconAreaController implements DarkReceiver,
.setInterpolator(Interpolators.LINEAR)
.setDuration(AOD_ICONS_APPEAR_DURATION)
.start();
+ } else {
+ mAodIcons.setAlpha(1.0f);
+ mAodIcons.setTranslationY(0);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java
index 8889510cde28..d884bdd47930 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java
@@ -104,9 +104,9 @@ 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.stack.AnimationProperties;
-import com.android.systemui.statusbar.notification.stack.MediaHeaderView;
import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout;
import com.android.systemui.statusbar.notification.stack.StackStateAnimator;
+import com.android.systemui.statusbar.phone.LockscreenGestureLogger.LockscreenUiEvent;
import com.android.systemui.statusbar.phone.dagger.StatusBarComponent;
import com.android.systemui.statusbar.policy.ConfigurationController;
import com.android.systemui.statusbar.policy.KeyguardStateController;
@@ -2474,6 +2474,8 @@ public class NotificationPanelViewController extends PanelViewController {
} else {
mLockscreenGestureLogger.write(MetricsEvent.ACTION_LS_HINT,
0 /* lengthDp - N/A */, 0 /* velocityDp - N/A */);
+ mLockscreenGestureLogger
+ .log(LockscreenUiEvent.LOCKSCREEN_LOCK_SHOW_HINT);
startUnlockHintAnimation();
}
}
@@ -3257,7 +3259,7 @@ public class NotificationPanelViewController extends PanelViewController {
int velocityDp = Math.abs((int) (vel / displayDensity));
if (start) {
mLockscreenGestureLogger.write(MetricsEvent.ACTION_LS_DIALER, lengthDp, velocityDp);
-
+ mLockscreenGestureLogger.log(LockscreenUiEvent.LOCKSCREEN_DIALER);
mFalsingManager.onLeftAffordanceOn();
if (mFalsingManager.shouldEnforceBouncer()) {
mStatusBar.executeRunnableDismissingKeyguard(
@@ -3272,6 +3274,7 @@ public class NotificationPanelViewController extends PanelViewController {
mLastCameraLaunchSource)) {
mLockscreenGestureLogger.write(
MetricsEvent.ACTION_LS_CAMERA, lengthDp, velocityDp);
+ mLockscreenGestureLogger.log(LockscreenUiEvent.LOCKSCREEN_CAMERA);
}
mFalsingManager.onCameraOn();
if (mFalsingManager.shouldEnforceBouncer()) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelViewController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelViewController.java
index 57d36fcafa15..a902e1b0c960 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelViewController.java
@@ -47,6 +47,7 @@ import com.android.systemui.statusbar.FlingAnimationUtils;
import com.android.systemui.statusbar.StatusBarState;
import com.android.systemui.statusbar.SysuiStatusBarStateController;
import com.android.systemui.statusbar.VibratorHelper;
+import com.android.systemui.statusbar.phone.LockscreenGestureLogger.LockscreenUiEvent;
import com.android.systemui.statusbar.policy.KeyguardStateController;
import java.io.FileDescriptor;
@@ -319,6 +320,8 @@ public abstract class PanelViewController {
mLockscreenGestureLogger.writeAtFractionalPosition(MetricsEvent.ACTION_PANEL_VIEW_EXPAND,
(int) (event.getX() / width * 100), (int) (event.getY() / height * 100), rot);
+ mLockscreenGestureLogger
+ .log(LockscreenUiEvent.LOCKSCREEN_UNLOCKED_NOTIFICATION_PANEL_EXPAND);
}
protected void maybeVibrateOnOpening() {
@@ -378,6 +381,7 @@ public abstract class PanelViewController {
int heightDp = (int) Math.abs((y - mInitialTouchY) / displayDensity);
int velocityDp = (int) Math.abs(vel / displayDensity);
mLockscreenGestureLogger.write(MetricsEvent.ACTION_LS_UNLOCK, heightDp, velocityDp);
+ mLockscreenGestureLogger.log(LockscreenUiEvent.LOCKSCREEN_UNLOCK);
}
fling(vel, expand, isFalseTouch(x, y));
onTrackingStopped(expand);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
index e0e52001e740..1bc42d1a169d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
@@ -2253,6 +2253,8 @@ public class StatusBar extends SystemUI implements DemoMode,
updateHideIconsForBouncer(false /* animate */);
}
}
+
+ updateBubblesVisibility();
}
@Override
@@ -2268,6 +2270,8 @@ public class StatusBar extends SystemUI implements DemoMode,
}
mLightBarController.onStatusBarAppearanceChanged(appearanceRegions, barModeChanged,
mStatusBarMode, navbarColorManagedByIme);
+
+ updateBubblesVisibility();
}
@Override
@@ -2311,6 +2315,7 @@ public class StatusBar extends SystemUI implements DemoMode,
final int barMode = barMode(mTransientShown, mAppearance);
if (updateBarMode(barMode)) {
mLightBarController.onStatusBarModeChanged(barMode);
+ updateBubblesVisibility();
}
}
@@ -2395,6 +2400,14 @@ public class StatusBar extends SystemUI implements DemoMode,
mNotificationPanelViewController.setQsScrimEnabled(scrimEnabled);
}
+ /** Temporarily hides Bubbles if the status bar is hidden. */
+ private void updateBubblesVisibility() {
+ mBubbleController.onStatusBarVisibilityChanged(
+ mStatusBarMode != MODE_LIGHTS_OUT
+ && mStatusBarMode != MODE_LIGHTS_OUT_TRANSPARENT
+ && !mStatusBarWindowHidden);
+ }
+
void checkBarMode(@TransitionMode int mode, @WindowVisibleState int windowState,
BarTransitions transitions) {
final boolean anim = !mNoAnimationOnNextBarModeChange && mDeviceInteractive
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java
index 84da35b63d0a..45f0c49a4fd4 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java
@@ -72,6 +72,7 @@ import com.android.systemui.statusbar.notification.row.NotificationGutsManager;
import com.android.systemui.statusbar.notification.row.NotificationGutsManager.OnSettingsClickListener;
import com.android.systemui.statusbar.notification.row.NotificationInfo.CheckSaveListener;
import com.android.systemui.statusbar.notification.stack.NotificationListContainer;
+import com.android.systemui.statusbar.phone.LockscreenGestureLogger.LockscreenUiEvent;
import com.android.systemui.statusbar.policy.ConfigurationController;
import com.android.systemui.statusbar.policy.KeyguardStateController;
@@ -374,6 +375,7 @@ public class StatusBarNotificationPresenter implements NotificationPresenter,
mLockscreenGestureLogger.write(
MetricsEvent.ACTION_LS_NOTE,
0 /* lengthDp - N/A */, 0 /* velocityDp - N/A */);
+ mLockscreenGestureLogger.log(LockscreenUiEvent.LOCKSCREEN_NOTIFICATION_FALSE_TOUCH);
mNotificationPanel.showTransientIndication(R.string.notification_tap_again);
ActivatableNotificationView previousView = mNotificationPanel.getActivatedChild();
if (previousView != null) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/VerticalNavigationHandle.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/VerticalNavigationHandle.java
index a15ca9532a88..0cdf1d32d6a0 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/VerticalNavigationHandle.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/VerticalNavigationHandle.java
@@ -18,12 +18,14 @@ package com.android.systemui.statusbar.phone;
import android.content.Context;
import android.graphics.Canvas;
+import android.graphics.RectF;
import com.android.systemui.R;
/** Temporarily shown view when using QuickSwitch to switch between apps of different rotations */
public class VerticalNavigationHandle extends NavigationHandle {
private final int mWidth;
+ private final RectF mTmpBoundsRectF = new RectF();
public VerticalNavigationHandle(Context context) {
super(context);
@@ -32,16 +34,21 @@ public class VerticalNavigationHandle extends NavigationHandle {
@Override
protected void onDraw(Canvas canvas) {
+ canvas.drawRoundRect(computeHomeHandleBounds(), mRadius, mRadius, mPaint);
+ }
+
+ RectF computeHomeHandleBounds() {
int left;
int top;
int bottom;
int right;
-
+ int topStart = getLocationOnScreen()[1];
int radiusOffset = mRadius * 2;
right = getWidth() - mBottom;
- top = getHeight() / 2 - (mWidth / 2); /* (height of screen / 2) - (height of bar / 2) */
+ top = getHeight() / 2 - (mWidth / 2) - (topStart / 2);
left = getWidth() - mBottom - radiusOffset;
- bottom = getHeight() / 2 + (mWidth / 2);
- canvas.drawRoundRect(left, top, right, bottom, mRadius, mRadius, mPaint);
+ bottom = top + mWidth;
+ mTmpBoundsRectF.set(left, top, right, bottom);
+ return mTmpBoundsRectF;
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonView.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonView.java
index c2f246f3922f..0ca8ef009173 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonView.java
@@ -52,6 +52,9 @@ import android.widget.ImageView;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.logging.MetricsLogger;
+import com.android.internal.logging.UiEvent;
+import com.android.internal.logging.UiEventLogger;
+import com.android.internal.logging.UiEventLoggerImpl;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.systemui.Dependency;
import com.android.systemui.R;
@@ -64,6 +67,7 @@ public class KeyButtonView extends ImageView implements ButtonInterface {
private static final String TAG = KeyButtonView.class.getSimpleName();
private final boolean mPlaySounds;
+ private final UiEventLogger mUiEventLogger;
private int mContentDescriptionRes;
private long mDownTime;
private int mCode;
@@ -72,7 +76,7 @@ public class KeyButtonView extends ImageView implements ButtonInterface {
private boolean mIsVertical;
private AudioManager mAudioManager;
private boolean mGestureAborted;
- private boolean mLongClicked;
+ @VisibleForTesting boolean mLongClicked;
private OnClickListener mOnClickListener;
private final KeyButtonRipple mRipple;
private final OverviewProxyService mOverviewProxyService;
@@ -82,6 +86,40 @@ public class KeyButtonView extends ImageView implements ButtonInterface {
private float mDarkIntensity;
private boolean mHasOvalBg = false;
+ @VisibleForTesting
+ public enum NavBarButtonEvent implements UiEventLogger.UiEventEnum {
+
+ @UiEvent(doc = "The home button was pressed in the navigation bar.")
+ NAVBAR_HOME_BUTTON_TAP(533),
+
+ @UiEvent(doc = "The back button was pressed in the navigation bar.")
+ NAVBAR_BACK_BUTTON_TAP(534),
+
+ @UiEvent(doc = "The overview button was pressed in the navigation bar.")
+ NAVBAR_OVERVIEW_BUTTON_TAP(535),
+
+ @UiEvent(doc = "The home button was long-pressed in the navigation bar.")
+ NAVBAR_HOME_BUTTON_LONGPRESS(536),
+
+ @UiEvent(doc = "The back button was long-pressed in the navigation bar.")
+ NAVBAR_BACK_BUTTON_LONGPRESS(537),
+
+ @UiEvent(doc = "The overview button was long-pressed in the navigation bar.")
+ NAVBAR_OVERVIEW_BUTTON_LONGPRESS(538),
+
+ NONE(0); // an event we should not log
+
+ private final int mId;
+
+ NavBarButtonEvent(int id) {
+ mId = id;
+ }
+
+ @Override
+ public int getId() {
+ return mId;
+ }
+ }
private final Runnable mCheckLongPress = new Runnable() {
public void run() {
if (isPressed()) {
@@ -104,12 +142,14 @@ public class KeyButtonView extends ImageView implements ButtonInterface {
}
public KeyButtonView(Context context, AttributeSet attrs, int defStyle) {
- this(context, attrs, defStyle, InputManager.getInstance());
+ this(context, attrs, defStyle, InputManager.getInstance(), new UiEventLoggerImpl());
}
@VisibleForTesting
- public KeyButtonView(Context context, AttributeSet attrs, int defStyle, InputManager manager) {
+ public KeyButtonView(Context context, AttributeSet attrs, int defStyle, InputManager manager,
+ UiEventLogger uiEventLogger) {
super(context, attrs);
+ mUiEventLogger = uiEventLogger;
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.KeyButtonView,
defStyle, 0);
@@ -326,13 +366,48 @@ public class KeyButtonView extends ImageView implements ButtonInterface {
sendEvent(action, flags, SystemClock.uptimeMillis());
}
+ private void logSomePresses(int action, int flags) {
+ boolean longPressSet = (flags & KeyEvent.FLAG_LONG_PRESS) != 0;
+ NavBarButtonEvent uiEvent = NavBarButtonEvent.NONE;
+ if (action == MotionEvent.ACTION_UP && mLongClicked) {
+ return; // don't log the up after a long press
+ }
+ if (action == MotionEvent.ACTION_DOWN && !longPressSet) {
+ return; // don't log a down unless it is also the long press marker
+ }
+ if ((flags & KeyEvent.FLAG_CANCELED) != 0
+ || (flags & KeyEvent.FLAG_CANCELED_LONG_PRESS) != 0) {
+ return; // don't log various cancels
+ }
+ switch(mCode) {
+ case KeyEvent.KEYCODE_BACK:
+ uiEvent = longPressSet
+ ? NavBarButtonEvent.NAVBAR_BACK_BUTTON_LONGPRESS
+ : NavBarButtonEvent.NAVBAR_BACK_BUTTON_TAP;
+ break;
+ case KeyEvent.KEYCODE_HOME:
+ uiEvent = longPressSet
+ ? NavBarButtonEvent.NAVBAR_HOME_BUTTON_LONGPRESS
+ : NavBarButtonEvent.NAVBAR_HOME_BUTTON_TAP;
+ break;
+ case KeyEvent.KEYCODE_APP_SWITCH:
+ uiEvent = longPressSet
+ ? NavBarButtonEvent.NAVBAR_OVERVIEW_BUTTON_LONGPRESS
+ : NavBarButtonEvent.NAVBAR_OVERVIEW_BUTTON_TAP;
+ break;
+ }
+ if (uiEvent != NavBarButtonEvent.NONE) {
+ mUiEventLogger.log(uiEvent);
+ }
+ }
+
private void sendEvent(int action, int flags, long when) {
mMetricsLogger.write(new LogMaker(MetricsEvent.ACTION_NAV_BUTTON_EVENT)
.setType(MetricsEvent.TYPE_ACTION)
.setSubtype(mCode)
.addTaggedData(MetricsEvent.FIELD_NAV_ACTION, action)
.addTaggedData(MetricsEvent.FIELD_FLAGS, flags));
- // TODO(b/122195391): Added logs to make sure sysui is sending back button events
+ logSomePresses(action, flags);
if (mCode == KeyEvent.KEYCODE_BACK && flags != KeyEvent.FLAG_LONG_PRESS) {
Log.i(TAG, "Back button event: " + KeyEvent.actionToString(action));
if (action == MotionEvent.ACTION_UP) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcher.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcher.java
index df3748a8606b..512d0f3910f8 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcher.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcher.java
@@ -16,11 +16,15 @@
package com.android.systemui.statusbar.policy;
+import static com.android.systemui.statusbar.policy.UserSwitcherController.USER_SWITCH_DISABLED_ALPHA;
+import static com.android.systemui.statusbar.policy.UserSwitcherController.USER_SWITCH_ENABLED_ALPHA;
+
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.ObjectAnimator;
import android.content.Context;
import android.database.DataSetObserver;
+import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.LayerDrawable;
import android.util.AttributeSet;
@@ -46,8 +50,6 @@ public class KeyguardUserSwitcher {
private static final String TAG = "KeyguardUserSwitcher";
private static final boolean ALWAYS_ON = false;
- private static final float USER_SWITCH_ENABLED_ALPHA = 1.0f;
- private static final float USER_SWITCH_DISABLED_ALPHA = 0.38f;
private final Container mUserSwitcherContainer;
private final KeyguardStatusBarView mStatusBarView;
@@ -286,27 +288,34 @@ public class KeyguardUserSwitcher {
if (item.picture == null) {
v.bind(name, getDrawable(mContext, item).mutate(), item.resolveId());
} else {
- v.bind(name, item.picture, item.info.id);
+ Drawable drawable = new BitmapDrawable(v.getResources(), item.picture);
+ drawable.setColorFilter(
+ item.isSwitchToEnabled ? null : getDisabledUserAvatarColorFilter());
+ v.bind(name, drawable, item.info.id);
}
- // Disable the icon if switching is disabled
- v.setAvatarEnabled(item.isSwitchToEnabled);
- convertView.setActivated(item.isCurrent);
+ v.setActivated(item.isCurrent);
+ v.setDisabledByAdmin(item.isDisabledByAdmin);
+ v.setEnabled(item.isSwitchToEnabled);
+ v.setAlpha(v.isEnabled() ? USER_SWITCH_ENABLED_ALPHA : USER_SWITCH_DISABLED_ALPHA);
+
if (item.isCurrent) {
- mCurrentUserView = convertView;
+ mCurrentUserView = v;
}
- convertView.setTag(item);
- convertView.setAlpha(
- item.isCurrent || item.isSwitchToEnabled ? USER_SWITCH_ENABLED_ALPHA
- : USER_SWITCH_DISABLED_ALPHA);
- convertView.setEnabled(item.isSwitchToEnabled);
- return convertView;
+ v.setTag(item);
+ return v;
}
private static Drawable getDrawable(Context context,
UserSwitcherController.UserRecord item) {
Drawable drawable = getIconDrawable(context, item);
- int iconColorRes = item.isCurrent ? R.color.kg_user_switcher_selected_avatar_icon_color
- : R.color.kg_user_switcher_avatar_icon_color;
+ int iconColorRes;
+ if (item.isCurrent) {
+ iconColorRes = R.color.kg_user_switcher_selected_avatar_icon_color;
+ } else if (!item.isSwitchToEnabled) {
+ iconColorRes = R.color.GM2_grey_600;
+ } else {
+ iconColorRes = R.color.kg_user_switcher_avatar_icon_color;
+ }
drawable.setTint(context.getResources().getColor(iconColorRes, context.getTheme()));
if (item.isCurrent) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java
index b4de3cd5d43b..18a7adda3f7d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java
@@ -640,8 +640,7 @@ public class MobileSignalController extends SignalController<
+ " dataState=" + state.getDataRegistrationState());
}
mServiceState = state;
- // onDisplayInfoChanged is invoked directly after onServiceStateChanged, so not calling
- // updateTelephony() to prevent icon flickering in case of overrides.
+ updateTelephony();
}
@Override
@@ -651,12 +650,6 @@ public class MobileSignalController extends SignalController<
+ " type=" + networkType);
}
mDataState = state;
- if (networkType != mTelephonyDisplayInfo.getNetworkType()) {
- Log.d(mTag, "onDataConnectionStateChanged:"
- + " network type change and reset displayInfo. type=" + networkType);
- mTelephonyDisplayInfo = new TelephonyDisplayInfo(networkType,
- TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NONE);
- }
updateTelephony();
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java
index db00770f0638..270f248e1a34 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java
@@ -31,6 +31,9 @@ import android.content.IntentFilter;
import android.content.pm.UserInfo;
import android.database.ContentObserver;
import android.graphics.Bitmap;
+import android.graphics.ColorFilter;
+import android.graphics.ColorMatrix;
+import android.graphics.ColorMatrixColorFilter;
import android.graphics.drawable.Drawable;
import android.os.AsyncTask;
import android.os.Handler;
@@ -81,6 +84,9 @@ import javax.inject.Singleton;
@Singleton
public class UserSwitcherController implements Dumpable {
+ public static final float USER_SWITCH_ENABLED_ALPHA = 1.0f;
+ public static final float USER_SWITCH_DISABLED_ALPHA = 0.38f;
+
private static final String TAG = "UserSwitcherController";
private static final boolean DEBUG = false;
private static final String SIMPLE_USER_SWITCHER_GLOBAL_SETTING =
@@ -674,6 +680,12 @@ public class UserSwitcherController implements Dumpable {
}
}
+ protected static ColorFilter getDisabledUserAvatarColorFilter() {
+ ColorMatrix matrix = new ColorMatrix();
+ matrix.setSaturation(0f); // 0 - grayscale
+ return new ColorMatrixColorFilter(matrix);
+ }
+
protected static Drawable getIconDrawable(Context context, UserRecord item) {
int iconRes;
if (item.isAddUser) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/tv/micdisclosure/AudioRecordingDisclosureBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/tv/micdisclosure/AudioRecordingDisclosureBar.java
index 914868301d72..8b85a0961463 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/tv/micdisclosure/AudioRecordingDisclosureBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/tv/micdisclosure/AudioRecordingDisclosureBar.java
@@ -29,6 +29,8 @@ import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.graphics.PixelFormat;
+import android.provider.Settings;
+import android.text.TextUtils;
import android.util.ArraySet;
import android.util.Log;
import android.view.Gravity;
@@ -63,6 +65,9 @@ public class AudioRecordingDisclosureBar implements
// CtsSystemUiHostTestCases:TvMicrophoneCaptureIndicatorTest
private static final String LAYOUT_PARAMS_TITLE = "MicrophoneCaptureIndicator";
+ private static final String EXEMPT_PACKAGES_LIST = "sysui_mic_disclosure_exempt";
+ private static final String FORCED_PACKAGES_LIST = "sysui_mic_disclosure_forced";
+
@Retention(RetentionPolicy.SOURCE)
@IntDef(prefix = {"STATE_"}, value = {
STATE_NOT_SHOWN,
@@ -134,6 +139,8 @@ public class AudioRecordingDisclosureBar implements
mExemptPackages = new ArraySet<>(
Arrays.asList(mContext.getResources().getStringArray(
R.array.audio_recording_disclosure_exempt_apps)));
+ mExemptPackages.addAll(Arrays.asList(getGlobalStringArray(EXEMPT_PACKAGES_LIST)));
+ mExemptPackages.removeAll(Arrays.asList(getGlobalStringArray(FORCED_PACKAGES_LIST)));
mAudioActivityObservers = new AudioActivityObserver[]{
new RecordAudioAppOpObserver(mContext, this),
@@ -141,6 +148,11 @@ public class AudioRecordingDisclosureBar implements
};
}
+ private String[] getGlobalStringArray(String setting) {
+ String result = Settings.Global.getString(mContext.getContentResolver(), setting);
+ return TextUtils.isEmpty(result) ? new String[0] : result.split(",");
+ }
+
@UiThread
@Override
public void onAudioActivityStateChange(boolean active, String packageName) {
diff --git a/packages/SystemUI/src/com/android/systemui/usb/UsbDebuggingActivity.java b/packages/SystemUI/src/com/android/systemui/usb/UsbDebuggingActivity.java
index 2973e0aedd43..bc2a55c8d5c4 100644
--- a/packages/SystemUI/src/com/android/systemui/usb/UsbDebuggingActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/usb/UsbDebuggingActivity.java
@@ -16,13 +16,19 @@
package com.android.systemui.usb;
+import android.app.Activity;
import android.app.AlertDialog;
+import android.content.BroadcastReceiver;
+import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
+import android.content.IntentFilter;
import android.debug.IAdbManager;
+import android.hardware.usb.UsbManager;
import android.os.Bundle;
import android.os.IBinder;
import android.os.ServiceManager;
+import android.os.SystemProperties;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
@@ -33,13 +39,25 @@ import android.widget.CheckBox;
import com.android.internal.app.AlertActivity;
import com.android.internal.app.AlertController;
import com.android.systemui.R;
+import com.android.systemui.broadcast.BroadcastDispatcher;
+
+import javax.inject.Inject;
public class UsbDebuggingActivity extends AlertActivity
implements DialogInterface.OnClickListener {
private static final String TAG = "UsbDebuggingActivity";
private CheckBox mAlwaysAllow;
+ private UsbDisconnectedReceiver mDisconnectedReceiver;
+ private final BroadcastDispatcher mBroadcastDispatcher;
private String mKey;
+ private boolean mServiceNotified;
+
+ @Inject
+ public UsbDebuggingActivity(BroadcastDispatcher broadcastDispatcher) {
+ super();
+ mBroadcastDispatcher = broadcastDispatcher;
+ }
@Override
public void onCreate(Bundle icicle) {
@@ -50,6 +68,10 @@ public class UsbDebuggingActivity extends AlertActivity
super.onCreate(icicle);
+ if (SystemProperties.getInt("service.adb.tcp.port", 0) == 0) {
+ mDisconnectedReceiver = new UsbDisconnectedReceiver(this);
+ }
+
Intent intent = getIntent();
String fingerprints = intent.getStringExtra("fingerprints");
mKey = intent.getStringExtra("key");
@@ -83,10 +105,77 @@ public class UsbDebuggingActivity extends AlertActivity
super.onWindowAttributesChanged(params);
}
+ private class UsbDisconnectedReceiver extends BroadcastReceiver {
+ private final Activity mActivity;
+ UsbDisconnectedReceiver(Activity activity) {
+ mActivity = activity;
+ }
+
+ @Override
+ public void onReceive(Context content, Intent intent) {
+ String action = intent.getAction();
+ if (!UsbManager.ACTION_USB_STATE.equals(action)) {
+ return;
+ }
+ boolean connected = intent.getBooleanExtra(UsbManager.USB_CONNECTED, false);
+ if (!connected) {
+ notifyService(false);
+ mActivity.finish();
+ }
+ }
+ }
+
+ @Override
+ public void onStart() {
+ super.onStart();
+ if (mDisconnectedReceiver != null) {
+ IntentFilter filter = new IntentFilter(UsbManager.ACTION_USB_STATE);
+ mBroadcastDispatcher.registerReceiver(mDisconnectedReceiver, filter);
+ }
+ }
+
+ @Override
+ protected void onStop() {
+ if (mDisconnectedReceiver != null) {
+ mBroadcastDispatcher.unregisterReceiver(mDisconnectedReceiver);
+ }
+ // If the ADB service has not yet been notified due to this dialog being closed in some
+ // other way then notify the service to deny the connection to ensure system_server sends
+ // a response to adbd.
+ if (!mServiceNotified) {
+ notifyService(false);
+ }
+ super.onStop();
+ }
+
@Override
public void onClick(DialogInterface dialog, int which) {
boolean allow = (which == AlertDialog.BUTTON_POSITIVE);
boolean alwaysAllow = allow && mAlwaysAllow.isChecked();
+ notifyService(allow, alwaysAllow);
+ finish();
+ }
+
+ /**
+ * Notifies the ADB service as to whether the current ADB request should be allowed; if the
+ * request is allowed it is only allowed for this session, and the user should be prompted again
+ * on subsequent requests from this key.
+ *
+ * @param allow whether the connection should be allowed for this session
+ */
+ private void notifyService(boolean allow) {
+ notifyService(allow, false);
+ }
+
+ /**
+ * Notifies the ADB service as to whether the current ADB request should be allowed, and if
+ * subsequent requests from this key should be allowed without user consent.
+ *
+ * @param allow whether the connection should be allowed
+ * @param alwaysAllow whether subsequent requests from this key should be allowed without user
+ * consent
+ */
+ private void notifyService(boolean allow, boolean alwaysAllow) {
try {
IBinder b = ServiceManager.getService(ADB_SERVICE);
IAdbManager service = IAdbManager.Stub.asInterface(b);
@@ -95,9 +184,9 @@ public class UsbDebuggingActivity extends AlertActivity
} else {
service.denyDebugging();
}
+ mServiceNotified = true;
} catch (Exception e) {
Log.e(TAG, "Unable to notify Usb service", e);
}
- finish();
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/usb/UsbDebuggingSecondaryUserActivity.java b/packages/SystemUI/src/com/android/systemui/usb/UsbDebuggingSecondaryUserActivity.java
index 421424206370..4850a025b684 100644
--- a/packages/SystemUI/src/com/android/systemui/usb/UsbDebuggingSecondaryUserActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/usb/UsbDebuggingSecondaryUserActivity.java
@@ -16,19 +16,47 @@
package com.android.systemui.usb;
+import android.app.Activity;
+import android.content.BroadcastReceiver;
+import android.content.Context;
import android.content.DialogInterface;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.debug.IAdbManager;
+import android.hardware.usb.UsbManager;
import android.os.Bundle;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.os.SystemProperties;
+import android.util.Log;
import com.android.internal.app.AlertActivity;
import com.android.internal.app.AlertController;
import com.android.systemui.R;
+import com.android.systemui.broadcast.BroadcastDispatcher;
+
+import javax.inject.Inject;
public class UsbDebuggingSecondaryUserActivity extends AlertActivity
implements DialogInterface.OnClickListener {
+ private static final String TAG = "UsbDebuggingSecondaryUserActivity";
+ private UsbDisconnectedReceiver mDisconnectedReceiver;
+ private final BroadcastDispatcher mBroadcastDispatcher;
+
+ @Inject
+ public UsbDebuggingSecondaryUserActivity(BroadcastDispatcher broadcastDispatcher) {
+ mBroadcastDispatcher = broadcastDispatcher;
+ }
+
@Override
public void onCreate(Bundle icicle) {
super.onCreate(icicle);
+ if (SystemProperties.getInt("service.adb.tcp.port", 0) == 0) {
+ mDisconnectedReceiver = new UsbDisconnectedReceiver(this);
+ }
+
final AlertController.AlertParams ap = mAlertParams;
ap.mTitle = getString(R.string.usb_debugging_secondary_user_title);
ap.mMessage = getString(R.string.usb_debugging_secondary_user_message);
@@ -38,6 +66,48 @@ public class UsbDebuggingSecondaryUserActivity extends AlertActivity
setupAlert();
}
+ private class UsbDisconnectedReceiver extends BroadcastReceiver {
+ private final Activity mActivity;
+ UsbDisconnectedReceiver(Activity activity) {
+ mActivity = activity;
+ }
+
+ @Override
+ public void onReceive(Context content, Intent intent) {
+ String action = intent.getAction();
+ if (UsbManager.ACTION_USB_STATE.equals(action)) {
+ boolean connected = intent.getBooleanExtra(UsbManager.USB_CONNECTED, false);
+ if (!connected) {
+ mActivity.finish();
+ }
+ }
+ }
+ }
+
+ @Override
+ public void onStart() {
+ super.onStart();
+ if (mDisconnectedReceiver != null) {
+ IntentFilter filter = new IntentFilter(UsbManager.ACTION_USB_STATE);
+ mBroadcastDispatcher.registerReceiver(mDisconnectedReceiver, filter);
+ }
+ }
+
+ @Override
+ protected void onStop() {
+ if (mDisconnectedReceiver != null) {
+ mBroadcastDispatcher.unregisterReceiver(mDisconnectedReceiver);
+ }
+ try {
+ IBinder b = ServiceManager.getService(ADB_SERVICE);
+ IAdbManager service = IAdbManager.Stub.asInterface(b);
+ service.denyDebugging();
+ } catch (RemoteException e) {
+ Log.e(TAG, "Unable to notify Usb service", e);
+ }
+ super.onStop();
+ }
+
@Override
public void onClick(DialogInterface dialog, int which) {
finish();
diff --git a/packages/SystemUI/src/com/android/systemui/util/DismissCircleView.java b/packages/SystemUI/src/com/android/systemui/util/DismissCircleView.java
index 6c3538cb6142..a31ea7c3ab17 100644
--- a/packages/SystemUI/src/com/android/systemui/util/DismissCircleView.java
+++ b/packages/SystemUI/src/com/android/systemui/util/DismissCircleView.java
@@ -40,7 +40,7 @@ public class DismissCircleView extends FrameLayout {
setBackground(res.getDrawable(R.drawable.dismiss_circle_background));
- mIconView.setImageDrawable(res.getDrawable(R.drawable.dismiss_target_x));
+ mIconView.setImageDrawable(res.getDrawable(R.drawable.ic_close_white));
addView(mIconView);
setViewSizes();
diff --git a/packages/SystemUI/src/com/android/systemui/util/Utils.java b/packages/SystemUI/src/com/android/systemui/util/Utils.java
index b1792d003290..5c9db54a0f00 100644
--- a/packages/SystemUI/src/com/android/systemui/util/Utils.java
+++ b/packages/SystemUI/src/com/android/systemui/util/Utils.java
@@ -133,4 +133,13 @@ public class Utils {
Settings.Global.SHOW_MEDIA_ON_QUICK_SETTINGS, 1);
return flag > 0;
}
+
+ /**
+ * Allow media resumption controls. Requires {@link #useQsMediaPlayer(Context)} to be enabled.
+ * Off by default, but can be enabled by setting to 1
+ */
+ public static boolean useMediaResumption(Context context) {
+ int flag = Settings.System.getInt(context.getContentResolver(), "qs_media_resumption", 0);
+ return useQsMediaPlayer(context) && flag > 0;
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/util/animation/PhysicsAnimator.kt b/packages/SystemUI/src/com/android/systemui/util/animation/PhysicsAnimator.kt
index 5df5f405b169..016f4de724b6 100644
--- a/packages/SystemUI/src/com/android/systemui/util/animation/PhysicsAnimator.kt
+++ b/packages/SystemUI/src/com/android/systemui/util/animation/PhysicsAnimator.kt
@@ -26,6 +26,7 @@ import androidx.dynamicanimation.animation.FloatPropertyCompat
import androidx.dynamicanimation.animation.SpringAnimation
import androidx.dynamicanimation.animation.SpringForce
import com.android.systemui.util.animation.PhysicsAnimator.Companion.getInstance
+import java.lang.ref.WeakReference
import java.util.WeakHashMap
import kotlin.math.abs
import kotlin.math.max
@@ -87,7 +88,9 @@ private var verboseLogging = false
*
* @param T The type of the object being animated.
*/
-class PhysicsAnimator<T> private constructor (val target: T) {
+class PhysicsAnimator<T> private constructor (target: T) {
+ /** Weak reference to the animation target. */
+ val weakTarget = WeakReference(target)
/** Data class for representing animation frame updates. */
data class AnimationUpdate(val value: Float, val velocity: Float)
@@ -307,6 +310,11 @@ class PhysicsAnimator<T> private constructor (val target: T) {
springConfig: SpringConfig,
flingMustReachMinOrMax: Boolean = false
): PhysicsAnimator<T> {
+ val target = weakTarget.get()
+ if (target == null) {
+ Log.w(TAG, "Trying to animate a GC-ed target.")
+ return this
+ }
val flingConfigCopy = flingConfig.copy()
val springConfigCopy = springConfig.copy()
val toAtLeast = if (startVelocity < 0) flingConfig.min else flingConfig.max
@@ -454,6 +462,11 @@ class PhysicsAnimator<T> private constructor (val target: T) {
"this message in a test, call PhysicsAnimatorTestUtils#prepareForTest in " +
"your test setup.")
}
+ val target = weakTarget.get()
+ if (target == null) {
+ Log.w(TAG, "Trying to animate a GC-ed object.")
+ return
+ }
// Functions that will actually start the animations. These are run after we build and add
// the InternalListener, since some animations might update/end immediately and we don't
@@ -489,7 +502,7 @@ class PhysicsAnimator<T> private constructor (val target: T) {
cancel(animatedProperty)
// Apply the configuration and start the animation.
- getFlingAnimation(animatedProperty)
+ getFlingAnimation(animatedProperty, target)
.also { flingConfig.applyToAnimation(it) }
.start()
}
@@ -502,7 +515,7 @@ class PhysicsAnimator<T> private constructor (val target: T) {
// If there is no corresponding fling config, we're only springing.
if (flingConfig == null) {
// Apply the configuration and start the animation.
- val springAnim = getSpringAnimation(animatedProperty)
+ val springAnim = getSpringAnimation(animatedProperty, target)
springConfig.applyToAnimation(springAnim)
animationStartActions.add(springAnim::start)
} else {
@@ -558,7 +571,7 @@ class PhysicsAnimator<T> private constructor (val target: T) {
}
// Apply the configuration and start the spring animation.
- getSpringAnimation(animatedProperty)
+ getSpringAnimation(animatedProperty, target)
.also { springConfig.applyToAnimation(it) }
.start()
}
@@ -570,6 +583,7 @@ class PhysicsAnimator<T> private constructor (val target: T) {
// Add an internal listener that will dispatch animation events to the provided listeners.
internalListeners.add(InternalListener(
+ target,
getAnimatedProperties(),
ArrayList(updateListeners),
ArrayList(endListeners),
@@ -594,7 +608,10 @@ class PhysicsAnimator<T> private constructor (val target: T) {
}
/** Retrieves a spring animation for the given property, building one if needed. */
- private fun getSpringAnimation(property: FloatPropertyCompat<in T>): SpringAnimation {
+ private fun getSpringAnimation(
+ property: FloatPropertyCompat<in T>,
+ target: T
+ ): SpringAnimation {
return springAnimations.getOrPut(
property,
{ configureDynamicAnimation(SpringAnimation(target, property), property)
@@ -602,7 +619,7 @@ class PhysicsAnimator<T> private constructor (val target: T) {
}
/** Retrieves a fling animation for the given property, building one if needed. */
- private fun getFlingAnimation(property: FloatPropertyCompat<in T>): FlingAnimation {
+ private fun getFlingAnimation(property: FloatPropertyCompat<in T>, target: T): FlingAnimation {
return flingAnimations.getOrPut(
property,
{ configureDynamicAnimation(FlingAnimation(target, property), property)
@@ -627,6 +644,12 @@ class PhysicsAnimator<T> private constructor (val target: T) {
it.onInternalAnimationEnd(
property, canceled, value, velocity, anim is FlingAnimation)
}
+ if (springAnimations[property] == anim) {
+ springAnimations.remove(property)
+ }
+ if (flingAnimations[property] == anim) {
+ flingAnimations.remove(property)
+ }
}
return anim
}
@@ -638,6 +661,7 @@ class PhysicsAnimator<T> private constructor (val target: T) {
* appropriate value for allEnded to [EndListener.onAnimationEnd].
*/
internal inner class InternalListener constructor(
+ private val target: T,
private var properties: Set<FloatPropertyCompat<in T>>,
private var updateListeners: List<UpdateListener<T>>,
private var endListeners: List<EndListener<T>>,
@@ -1008,4 +1032,4 @@ class PhysicsAnimator<T> private constructor (val target: T) {
}
}
}
-} \ No newline at end of file
+}
diff --git a/packages/SystemUI/src/com/android/systemui/util/magnetictarget/MagnetizedObject.kt b/packages/SystemUI/src/com/android/systemui/util/magnetictarget/MagnetizedObject.kt
index e905e6772074..5a2b064c5389 100644
--- a/packages/SystemUI/src/com/android/systemui/util/magnetictarget/MagnetizedObject.kt
+++ b/packages/SystemUI/src/com/android/systemui/util/magnetictarget/MagnetizedObject.kt
@@ -32,6 +32,7 @@ import androidx.dynamicanimation.animation.DynamicAnimation
import androidx.dynamicanimation.animation.FloatPropertyCompat
import androidx.dynamicanimation.animation.SpringForce
import com.android.systemui.util.animation.PhysicsAnimator
+import kotlin.math.abs
import kotlin.math.hypot
/**
@@ -231,11 +232,11 @@ abstract class MagnetizedObject<T : Any>(
var flingUnstuckFromTargetMinVelocity = 1000f
/**
- * Sets the maximum velocity above which the object will not stick to the target. Even if the
+ * Sets the maximum X velocity above which the object will not stick to the target. Even if the
* object is dragged through the magnetic field, it will not stick to the target until the
- * velocity is below this value.
+ * horizontal velocity is below this value.
*/
- var stickToTargetMaxVelocity = 2000f
+ var stickToTargetMaxXVelocity = 2000f
/**
* Enable or disable haptic vibration effects when the object interacts with the magnetic field.
@@ -245,9 +246,6 @@ abstract class MagnetizedObject<T : Any>(
*/
var hapticsEnabled = true
- /** Whether the HAPTIC_FEEDBACK_ENABLED setting is true. */
- private var systemHapticsEnabled = false
-
/** Default spring configuration to use for animating the object into a target. */
var springConfig = PhysicsAnimator.SpringConfig(
SpringForce.STIFFNESS_MEDIUM, SpringForce.DAMPING_RATIO_NO_BOUNCY)
@@ -259,24 +257,7 @@ abstract class MagnetizedObject<T : Any>(
var flungIntoTargetSpringConfig = springConfig
init {
- val hapticSettingObserver =
- object : ContentObserver(Handler.getMain()) {
- override fun onChange(selfChange: Boolean) {
- systemHapticsEnabled =
- Settings.System.getIntForUser(
- context.contentResolver,
- Settings.System.HAPTIC_FEEDBACK_ENABLED,
- 0,
- UserHandle.USER_CURRENT) != 0
- }
- }
-
- context.contentResolver.registerContentObserver(
- Settings.System.getUriFor(Settings.System.HAPTIC_FEEDBACK_ENABLED),
- true /* notifyForDescendants */, hapticSettingObserver)
-
- // Trigger the observer once to initialize systemHapticsEnabled.
- hapticSettingObserver.onChange(false /* selfChange */)
+ initHapticSettingObserver(context)
}
/**
@@ -383,7 +364,7 @@ abstract class MagnetizedObject<T : Any>(
// If the object is moving too quickly within the magnetic field, do not stick it. This
// only applies to objects newly stuck to a target. If the object is moved into a new
// target, it wasn't moving at all (since it was stuck to the previous one).
- if (objectNewlyStuckToTarget && hypot(velX, velY) > stickToTargetMaxVelocity) {
+ if (objectNewlyStuckToTarget && abs(velX) > stickToTargetMaxXVelocity) {
return false
}
@@ -623,6 +604,43 @@ abstract class MagnetizedObject<T : Any>(
companion object {
/**
+ * Whether the HAPTIC_FEEDBACK_ENABLED setting is true.
+ *
+ * We put it in the companion object because we need to register a settings observer and
+ * [MagnetizedObject] doesn't have an obvious lifecycle so we don't have a good time to
+ * remove that observer. Since this settings is shared among all instances we just let all
+ * instances read from this value.
+ */
+ private var systemHapticsEnabled = false
+ private var hapticSettingObserverInitialized = false
+
+ private fun initHapticSettingObserver(context: Context) {
+ if (hapticSettingObserverInitialized) {
+ return
+ }
+
+ val hapticSettingObserver =
+ object : ContentObserver(Handler.getMain()) {
+ override fun onChange(selfChange: Boolean) {
+ systemHapticsEnabled =
+ Settings.System.getIntForUser(
+ context.contentResolver,
+ Settings.System.HAPTIC_FEEDBACK_ENABLED,
+ 0,
+ UserHandle.USER_CURRENT) != 0
+ }
+ }
+
+ context.contentResolver.registerContentObserver(
+ Settings.System.getUriFor(Settings.System.HAPTIC_FEEDBACK_ENABLED),
+ true /* notifyForDescendants */, hapticSettingObserver)
+
+ // Trigger the observer once to initialize systemHapticsEnabled.
+ hapticSettingObserver.onChange(false /* selfChange */)
+ hapticSettingObserverInitialized = true
+ }
+
+ /**
* Magnetizes the given view. Magnetized views are attracted to one or more magnetic
* targets. Magnetic targets attract objects that are dragged near them, and hold them there
* unless they're moved away or released. Releasing objects inside a magnetic target
diff --git a/packages/SystemUI/src/com/android/systemui/util/sensors/ProximitySensor.java b/packages/SystemUI/src/com/android/systemui/util/sensors/ProximitySensor.java
index 708b5a7a45f7..6794a2a3f72f 100644
--- a/packages/SystemUI/src/com/android/systemui/util/sensors/ProximitySensor.java
+++ b/packages/SystemUI/src/com/android/systemui/util/sensors/ProximitySensor.java
@@ -222,7 +222,9 @@ public class ProximitySensor {
if (mAlerting.getAndSet(true)) {
return;
}
- mListeners.forEach(proximitySensorListener ->
+
+ List<ProximitySensorListener> listeners = new ArrayList<>(mListeners);
+ listeners.forEach(proximitySensorListener ->
proximitySensorListener.onSensorEvent(mLastEvent));
mAlerting.set(false);
}
@@ -247,22 +249,15 @@ public class ProximitySensor {
private final ProximitySensor mSensor;
private final DelayableExecutor mDelayableExecutor;
private List<Consumer<Boolean>> mCallbacks = new ArrayList<>();
+ private final ProximitySensor.ProximitySensorListener mListener;
+ private final AtomicBoolean mRegistered = new AtomicBoolean();
@Inject
public ProximityCheck(ProximitySensor sensor, DelayableExecutor delayableExecutor) {
mSensor = sensor;
mSensor.setTag("prox_check");
mDelayableExecutor = delayableExecutor;
- mSensor.pause();
- ProximitySensorListener listener = proximityEvent -> {
- mCallbacks.forEach(
- booleanConsumer ->
- booleanConsumer.accept(
- proximityEvent == null ? null : proximityEvent.getNear()));
- mCallbacks.clear();
- mSensor.pause();
- };
- mSensor.register(listener);
+ mListener = this::onProximityEvent;
}
/** Set a descriptive tag for the sensors registration. */
@@ -272,7 +267,7 @@ public class ProximitySensor {
@Override
public void run() {
- mSensor.pause();
+ unregister();
mSensor.alertListeners();
}
@@ -284,11 +279,26 @@ public class ProximitySensor {
callback.accept(null);
}
mCallbacks.add(callback);
- if (!mSensor.isRegistered()) {
- mSensor.resume();
+ if (!mRegistered.getAndSet(true)) {
+ mSensor.register(mListener);
mDelayableExecutor.executeDelayed(this, timeoutMs);
}
}
+
+ private void unregister() {
+ mSensor.unregister(mListener);
+ mRegistered.set(false);
+ }
+
+ private void onProximityEvent(ProximityEvent proximityEvent) {
+ mCallbacks.forEach(
+ booleanConsumer ->
+ booleanConsumer.accept(
+ proximityEvent == null ? null : proximityEvent.getNear()));
+ mCallbacks.clear();
+ unregister();
+ mRegistered.set(false);
+ }
}
/** Implement to be notified of ProximityEvents. */
diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
index ce032e2ceaec..3455ff47de8d 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
@@ -212,7 +212,6 @@ public class VolumeDialogImpl implements VolumeDialog,
mWindow.clearFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND
| WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR);
mWindow.addFlags(WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
- | WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
| WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
| WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED
| WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthContainerViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthContainerViewTest.java
index 74d0610ee0d6..29d7a524dd8b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthContainerViewTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthContainerViewTest.java
@@ -45,6 +45,7 @@ import android.testing.TestableLooper.RunWithLooper;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
+import android.view.WindowInsets;
import android.view.WindowManager;
import android.widget.FrameLayout;
import android.widget.ImageView;
@@ -210,6 +211,14 @@ public class AuthContainerViewTest extends SysuiTestCase {
assertTrue((layoutParams.flags & WindowManager.LayoutParams.FLAG_SECURE) != 0);
}
+ @Test
+ public void testLayoutParams_excludesImeInsets() {
+ final IBinder windowToken = mock(IBinder.class);
+ final WindowManager.LayoutParams layoutParams =
+ AuthContainerView.getLayoutParams(windowToken);
+ assertTrue((layoutParams.getFitInsetsTypes() & WindowInsets.Type.ime()) == 0);
+ }
+
private void initializeContainer(int authenticators) {
AuthContainerView.Config config = new AuthContainerView.Config();
config.mContext = mContext;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java
index c89f6c2597d0..1e48b990b19d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java
@@ -44,7 +44,6 @@ import android.app.IActivityManager;
import android.app.INotificationManager;
import android.app.Notification;
import android.app.PendingIntent;
-import android.content.res.Resources;
import android.hardware.display.AmbientDisplayConfiguration;
import android.hardware.face.FaceManager;
import android.os.Handler;
@@ -59,7 +58,7 @@ import android.view.WindowManager;
import androidx.test.filters.SmallTest;
import com.android.internal.colorextraction.ColorExtractor;
-import com.android.systemui.SystemUIFactory;
+import com.android.internal.statusbar.IStatusBarService;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.colorextraction.SysuiColorExtractor;
import com.android.systemui.dump.DumpManager;
@@ -70,20 +69,16 @@ import com.android.systemui.statusbar.FeatureFlags;
import com.android.systemui.statusbar.NotificationLockscreenUserManager;
import com.android.systemui.statusbar.NotificationRemoveInterceptor;
import com.android.systemui.statusbar.RankingBuilder;
-import com.android.systemui.statusbar.SuperStatusBarViewFactory;
import com.android.systemui.statusbar.SysuiStatusBarStateController;
import com.android.systemui.statusbar.notification.NotificationEntryListener;
import com.android.systemui.statusbar.notification.NotificationEntryManager;
import com.android.systemui.statusbar.notification.NotificationFilter;
import com.android.systemui.statusbar.notification.collection.NotifPipeline;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
-import com.android.systemui.statusbar.notification.row.ActivatableNotificationView;
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
import com.android.systemui.statusbar.notification.row.NotificationTestHelper;
-import com.android.systemui.statusbar.notification.row.dagger.NotificationRowComponent;
import com.android.systemui.statusbar.phone.DozeParameters;
import com.android.systemui.statusbar.phone.KeyguardBypassController;
-import com.android.systemui.statusbar.phone.LockscreenLockIconController;
import com.android.systemui.statusbar.phone.NotificationGroupManager;
import com.android.systemui.statusbar.phone.NotificationShadeWindowController;
import com.android.systemui.statusbar.phone.NotificationShadeWindowView;
@@ -93,7 +88,6 @@ import com.android.systemui.statusbar.policy.ConfigurationController;
import com.android.systemui.statusbar.policy.HeadsUpManager;
import com.android.systemui.statusbar.policy.ZenModeController;
import com.android.systemui.util.FloatingContentCoordinator;
-import com.android.systemui.util.InjectionInflationController;
import com.google.common.collect.ImmutableList;
@@ -173,23 +167,18 @@ public class BubbleControllerTest extends SysuiTestCase {
@Mock
ColorExtractor.GradientColors mGradientColors;
@Mock
- private Resources mResources;
- @Mock
private ShadeController mShadeController;
@Mock
- private NotificationRowComponent mNotificationRowComponent;
- @Mock
private NotifPipeline mNotifPipeline;
@Mock
private FeatureFlags mFeatureFlagsOldPipeline;
@Mock
private DumpManager mDumpManager;
@Mock
- private LockscreenLockIconController mLockIconController;
- @Mock
private NotificationShadeWindowView mNotificationShadeWindowView;
+ @Mock
+ private IStatusBarService mStatusBarService;
- private SuperStatusBarViewFactory mSuperStatusBarViewFactory;
private BubbleData mBubbleData;
private TestableLooper mTestableLooper;
@@ -203,23 +192,6 @@ public class BubbleControllerTest extends SysuiTestCase {
mContext.addMockSystemService(FaceManager.class, mFaceManager);
when(mColorExtractor.getNeutralColors()).thenReturn(mGradientColors);
- mSuperStatusBarViewFactory = new SuperStatusBarViewFactory(mContext,
- new InjectionInflationController(SystemUIFactory.getInstance().getRootComponent()),
- new NotificationRowComponent.Builder() {
- @Override
- public NotificationRowComponent.Builder activatableNotificationView(
- ActivatableNotificationView view) {
- return this;
- }
-
- @Override
- public NotificationRowComponent build() {
- return mNotificationRowComponent;
- }
- },
- mLockIconController);
-
- // Bubbles get added to status bar window view
mNotificationShadeWindowController = new NotificationShadeWindowController(mContext,
mWindowManager, mActivityManager, mDozeParameters, mStatusBarStateController,
mConfigurationController, mKeyguardBypassController, mColorExtractor,
@@ -282,6 +254,7 @@ public class BubbleControllerTest extends SysuiTestCase {
mDataRepository,
mSysUiState,
mock(INotificationManager.class),
+ mStatusBarService,
mWindowManager);
mBubbleController.setExpandListener(mBubbleExpandListener);
@@ -327,7 +300,7 @@ public class BubbleControllerTest extends SysuiTestCase {
}
@Test
- public void testPromoteBubble_autoExpand() {
+ public void testPromoteBubble_autoExpand() throws Exception {
mBubbleController.updateBubble(mRow2.getEntry());
mBubbleController.updateBubble(mRow.getEntry());
mBubbleController.removeBubble(
@@ -337,13 +310,19 @@ public class BubbleControllerTest extends SysuiTestCase {
assertThat(mBubbleData.getOverflowBubbles()).isEqualTo(ImmutableList.of(b));
verify(mNotificationEntryManager, never()).performRemoveNotification(
eq(mRow.getEntry().getSbn()), anyInt());
- assertFalse(mRow.getEntry().isBubble());
+ assertThat(mRow.getEntry().isBubble()).isFalse();
Bubble b2 = mBubbleData.getBubbleInStackWithKey(mRow2.getEntry().getKey());
assertThat(mBubbleData.getSelectedBubble()).isEqualTo(b2);
mBubbleController.promoteBubbleFromOverflow(b);
- assertThat(mBubbleData.getSelectedBubble()).isEqualTo(b);
+
+ assertThat(b.isBubble()).isTrue();
+ assertThat(b.shouldAutoExpand()).isTrue();
+ int flags = Notification.BubbleMetadata.FLAG_AUTO_EXPAND_BUBBLE
+ | Notification.BubbleMetadata.FLAG_SUPPRESS_NOTIFICATION;
+ verify(mStatusBarService, times(1)).onNotificationBubbleChanged(
+ eq(b.getKey()), eq(true), eq(flags));
}
@Test
@@ -446,7 +425,8 @@ public class BubbleControllerTest extends SysuiTestCase {
BubbleStackView stackView = mBubbleController.getStackView();
mBubbleData.setExpanded(true);
assertTrue(mBubbleController.isStackExpanded());
- verify(mBubbleExpandListener).onBubbleExpandChanged(true, mRow2.getEntry().getKey());
+ verify(mBubbleExpandListener, atLeastOnce()).onBubbleExpandChanged(
+ true, mRow2.getEntry().getKey());
assertTrue(mSysUiStateBubblesExpanded);
@@ -464,9 +444,11 @@ public class BubbleControllerTest extends SysuiTestCase {
mRow.getEntry()));
// collapse for previous bubble
- verify(mBubbleExpandListener).onBubbleExpandChanged(false, mRow2.getEntry().getKey());
+ verify(mBubbleExpandListener, atLeastOnce()).onBubbleExpandChanged(
+ false, mRow2.getEntry().getKey());
// expand for selected bubble
- verify(mBubbleExpandListener).onBubbleExpandChanged(true, mRow.getEntry().getKey());
+ verify(mBubbleExpandListener, atLeastOnce()).onBubbleExpandChanged(
+ true, mRow.getEntry().getKey());
// Collapse
mBubbleController.collapseStack();
diff --git a/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleDataTest.java b/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleDataTest.java
index 8224c88e6c75..17022da3ecde 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleDataTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleDataTest.java
@@ -278,7 +278,7 @@ public class BubbleDataTest extends SysuiTestCase {
assertBubbleRemoved(mBubbleA1, BubbleController.DISMISS_AGED);
assertOverflowChangedTo(ImmutableList.of(mBubbleA1));
- Bubble bubbleA1 = mBubbleData.getOrCreateBubble(mEntryA1);
+ Bubble bubbleA1 = mBubbleData.getOrCreateBubble(mEntryA1, null /* persistedBubble */);
bubbleA1.markUpdatedAt(7000L);
mBubbleData.notificationEntryUpdated(bubbleA1, false /* suppressFlyout*/,
true /* showInShade */);
@@ -890,7 +890,7 @@ public class BubbleDataTest extends SysuiTestCase {
private void sendUpdatedEntryAtTime(NotificationEntry entry, long postTime) {
setPostTime(entry, postTime);
// BubbleController calls this:
- Bubble b = mBubbleData.getOrCreateBubble(entry);
+ Bubble b = mBubbleData.getOrCreateBubble(entry, null /* persistedBubble */);
// And then this
mBubbleData.notificationEntryUpdated(b, false /* suppressFlyout*/,
true /* showInShade */);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/bubbles/NewNotifPipelineBubbleControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/bubbles/NewNotifPipelineBubbleControllerTest.java
index ead95ca1665e..0be24729dff9 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/bubbles/NewNotifPipelineBubbleControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/bubbles/NewNotifPipelineBubbleControllerTest.java
@@ -55,7 +55,7 @@ import android.view.WindowManager;
import androidx.test.filters.SmallTest;
import com.android.internal.colorextraction.ColorExtractor;
-import com.android.systemui.SystemUIFactory;
+import com.android.internal.statusbar.IStatusBarService;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.colorextraction.SysuiColorExtractor;
import com.android.systemui.dump.DumpManager;
@@ -64,14 +64,12 @@ import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.statusbar.FeatureFlags;
import com.android.systemui.statusbar.NotificationLockscreenUserManager;
import com.android.systemui.statusbar.RankingBuilder;
-import com.android.systemui.statusbar.SuperStatusBarViewFactory;
import com.android.systemui.statusbar.SysuiStatusBarStateController;
import com.android.systemui.statusbar.notification.NotificationEntryManager;
import com.android.systemui.statusbar.notification.NotificationFilter;
import com.android.systemui.statusbar.notification.collection.NotifPipeline;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.collection.notifcollection.NotifCollectionListener;
-import com.android.systemui.statusbar.notification.row.ActivatableNotificationView;
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
import com.android.systemui.statusbar.notification.row.NotificationTestHelper;
import com.android.systemui.statusbar.notification.row.dagger.NotificationRowComponent;
@@ -87,7 +85,6 @@ import com.android.systemui.statusbar.policy.ConfigurationController;
import com.android.systemui.statusbar.policy.HeadsUpManager;
import com.android.systemui.statusbar.policy.ZenModeController;
import com.android.systemui.util.FloatingContentCoordinator;
-import com.android.systemui.util.InjectionInflationController;
import org.junit.Before;
import org.junit.Test;
@@ -174,8 +171,9 @@ public class NewNotifPipelineBubbleControllerTest extends SysuiTestCase {
private DumpManager mDumpManager;
@Mock
private LockscreenLockIconController mLockIconController;
+ @Mock
+ private IStatusBarService mStatusBarService;
- private SuperStatusBarViewFactory mSuperStatusBarViewFactory;
private BubbleData mBubbleData;
private TestableLooper mTestableLooper;
@@ -189,22 +187,6 @@ public class NewNotifPipelineBubbleControllerTest extends SysuiTestCase {
mContext.addMockSystemService(FaceManager.class, mFaceManager);
when(mColorExtractor.getNeutralColors()).thenReturn(mGradientColors);
- mSuperStatusBarViewFactory = new SuperStatusBarViewFactory(mContext,
- new InjectionInflationController(SystemUIFactory.getInstance().getRootComponent()),
- new NotificationRowComponent.Builder() {
- @Override
- public NotificationRowComponent.Builder activatableNotificationView(
- ActivatableNotificationView view) {
- return this;
- }
-
- @Override
- public NotificationRowComponent build() {
- return mNotificationRowComponent;
- }
- },
- mLockIconController);
-
// Bubbles get added to status bar window view
mNotificationShadeWindowController = new NotificationShadeWindowController(mContext,
mWindowManager, mActivityManager, mDozeParameters, mStatusBarStateController,
@@ -257,6 +239,7 @@ public class NewNotifPipelineBubbleControllerTest extends SysuiTestCase {
mDataRepository,
mSysUiState,
mock(INotificationManager.class),
+ mStatusBarService,
mWindowManager);
mBubbleController.addNotifCallback(mNotifCallback);
mBubbleController.setExpandListener(mBubbleExpandListener);
@@ -399,7 +382,8 @@ public class NewNotifPipelineBubbleControllerTest extends SysuiTestCase {
BubbleStackView stackView = mBubbleController.getStackView();
mBubbleData.setExpanded(true);
assertTrue(mBubbleController.isStackExpanded());
- verify(mBubbleExpandListener).onBubbleExpandChanged(true, mRow2.getEntry().getKey());
+ verify(mBubbleExpandListener, atLeastOnce()).onBubbleExpandChanged(
+ true, mRow.getEntry().getKey());
// Last added is the one that is expanded
assertEquals(mRow2.getEntry(), mBubbleData.getSelectedBubble().getEntry());
@@ -414,9 +398,11 @@ public class NewNotifPipelineBubbleControllerTest extends SysuiTestCase {
mRow.getEntry()));
// collapse for previous bubble
- verify(mBubbleExpandListener).onBubbleExpandChanged(false, mRow2.getEntry().getKey());
+ verify(mBubbleExpandListener, atLeastOnce()).onBubbleExpandChanged(
+ false, mRow2.getEntry().getKey());
// expand for selected bubble
- verify(mBubbleExpandListener).onBubbleExpandChanged(true, mRow.getEntry().getKey());
+ verify(mBubbleExpandListener, atLeastOnce()).onBubbleExpandChanged(
+ true, mRow.getEntry().getKey());
// Collapse
mBubbleController.collapseStack();
diff --git a/packages/SystemUI/tests/src/com/android/systemui/bubbles/TestableBubbleController.java b/packages/SystemUI/tests/src/com/android/systemui/bubbles/TestableBubbleController.java
index bdb79449ea2a..ab49134ee8c0 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/bubbles/TestableBubbleController.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/bubbles/TestableBubbleController.java
@@ -20,6 +20,7 @@ import android.app.INotificationManager;
import android.content.Context;
import android.view.WindowManager;
+import com.android.internal.statusbar.IStatusBarService;
import com.android.systemui.dump.DumpManager;
import com.android.systemui.model.SysUiState;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
@@ -59,13 +60,14 @@ public class TestableBubbleController extends BubbleController {
BubbleDataRepository dataRepository,
SysUiState sysUiState,
INotificationManager notificationManager,
+ IStatusBarService statusBarService,
WindowManager windowManager) {
super(context,
notificationShadeWindowController, statusBarStateController, shadeController,
data, Runnable::run, configurationController, interruptionStateProvider,
zenModeController, lockscreenUserManager, groupManager, entryManager,
notifPipeline, featureFlags, dumpManager, floatingContentCoordinator,
- dataRepository, sysUiState, notificationManager,
+ dataRepository, sysUiState, notificationManager, statusBarService,
windowManager);
setInflateSynchronously(true);
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/bubbles/storage/BubblePersistentRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/bubbles/storage/BubblePersistentRepositoryTest.kt
index f46819252fac..1d02b8dba910 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/bubbles/storage/BubblePersistentRepositoryTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/bubbles/storage/BubblePersistentRepositoryTest.kt
@@ -20,6 +20,8 @@ import android.testing.AndroidTestingRunner
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import junit.framework.Assert.assertEquals
+import junit.framework.Assert.assertNotNull
+import junit.framework.Assert.assertTrue
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
@@ -29,9 +31,9 @@ import org.junit.runner.RunWith
class BubblePersistentRepositoryTest : SysuiTestCase() {
private val bubbles = listOf(
- BubbleEntity(0, "com.example.messenger", "shortcut-1", "key-1"),
- BubbleEntity(10, "com.example.chat", "alice and bob", "key-2"),
- BubbleEntity(0, "com.example.messenger", "shortcut-2", "key-3")
+ BubbleEntity(0, "com.example.messenger", "shortcut-1", "key-1", 120, 0),
+ BubbleEntity(10, "com.example.chat", "alice and bob", "key-2", 0, 16537428),
+ BubbleEntity(0, "com.example.messenger", "shortcut-2", "key-3", 120, 0)
)
private lateinit var repository: BubblePersistentRepository
@@ -42,6 +44,11 @@ class BubblePersistentRepositoryTest : SysuiTestCase() {
@Test
fun testReadWriteOperation() {
+ // Verify read before write doesn't cause FileNotFoundException
+ val actual = repository.readFromDisk()
+ assertNotNull(actual)
+ assertTrue(actual.isEmpty())
+
repository.persistsToDisk(bubbles)
assertEquals(bubbles, repository.readFromDisk())
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/bubbles/storage/BubbleVolatileRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/bubbles/storage/BubbleVolatileRepositoryTest.kt
index 2bb6bb8ebe14..f9d611c2bb33 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/bubbles/storage/BubbleVolatileRepositoryTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/bubbles/storage/BubbleVolatileRepositoryTest.kt
@@ -37,9 +37,9 @@ class BubbleVolatileRepositoryTest : SysuiTestCase() {
private val user0 = UserHandle.of(0)
private val user10 = UserHandle.of(10)
- private val bubble1 = BubbleEntity(0, PKG_MESSENGER, "shortcut-1", "k1")
- private val bubble2 = BubbleEntity(10, PKG_CHAT, "alice and bob", "k2")
- private val bubble3 = BubbleEntity(0, PKG_MESSENGER, "shortcut-2", "k3")
+ private val bubble1 = BubbleEntity(0, PKG_MESSENGER, "shortcut-1", "k1", 120, 0)
+ private val bubble2 = BubbleEntity(10, PKG_CHAT, "alice and bob", "k2", 0, 16537428)
+ private val bubble3 = BubbleEntity(0, PKG_MESSENGER, "shortcut-2", "k3", 120, 0)
private val bubbles = listOf(bubble1, bubble2, bubble3)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/bubbles/storage/BubbleXmlHelperTest.kt b/packages/SystemUI/tests/src/com/android/systemui/bubbles/storage/BubbleXmlHelperTest.kt
index 79701ecf70f8..49467874dd8b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/bubbles/storage/BubbleXmlHelperTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/bubbles/storage/BubbleXmlHelperTest.kt
@@ -31,17 +31,17 @@ import java.io.ByteArrayOutputStream
class BubbleXmlHelperTest : SysuiTestCase() {
private val bubbles = listOf(
- BubbleEntity(0, "com.example.messenger", "shortcut-1", "k1"),
- BubbleEntity(10, "com.example.chat", "alice and bob", "k2"),
- BubbleEntity(0, "com.example.messenger", "shortcut-2", "k3")
+ BubbleEntity(0, "com.example.messenger", "shortcut-1", "k1", 120, 0),
+ BubbleEntity(10, "com.example.chat", "alice and bob", "k2", 0, 16537428),
+ BubbleEntity(0, "com.example.messenger", "shortcut-2", "k3", 120, 0)
)
@Test
fun testWriteXml() {
val expectedEntries = """
- <bb uid="0" pkg="com.example.messenger" sid="shortcut-1" key="k1" />
- <bb uid="10" pkg="com.example.chat" sid="alice and bob" key="k2" />
- <bb uid="0" pkg="com.example.messenger" sid="shortcut-2" key="k3" />
+ <bb uid="0" pkg="com.example.messenger" sid="shortcut-1" key="k1" h="120" hid="0" />
+ <bb uid="10" pkg="com.example.chat" sid="alice and bob" key="k2" h="0" hid="16537428" />
+ <bb uid="0" pkg="com.example.messenger" sid="shortcut-2" key="k3" h="120" hid="0" />
""".trimIndent()
ByteArrayOutputStream().use {
writeXml(it, bubbles)
@@ -56,9 +56,9 @@ class BubbleXmlHelperTest : SysuiTestCase() {
val src = """
<?xml version='1.0' encoding='utf-8' standalone='yes' ?>
<bs>
- <bb uid="0" pkg="com.example.messenger" sid="shortcut-1" key="k1" />
- <bb uid="10" pkg="com.example.chat" sid="alice and bob" key="k2" />
- <bb uid="0" pkg="com.example.messenger" sid="shortcut-2" key="k3" />
+ <bb uid="0" pkg="com.example.messenger" sid="shortcut-1" key="k1" h="120" hid="0" />
+ <bb uid="10" pkg="com.example.chat" sid="alice and bob" key="k2" h="0" hid="16537428" />
+ <bb uid="0" pkg="com.example.messenger" sid="shortcut-2" key="k3" h="120" hid="0" />
</bs>
""".trimIndent()
val actual = readXml(ByteArrayInputStream(src.toByteArray(Charsets.UTF_8)))
diff --git a/packages/SystemUI/tests/src/com/android/systemui/globalactions/GlobalActionsDialogTest.java b/packages/SystemUI/tests/src/com/android/systemui/globalactions/GlobalActionsDialogTest.java
index 32546333aac3..329af2b7f62b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/globalactions/GlobalActionsDialogTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/globalactions/GlobalActionsDialogTest.java
@@ -19,6 +19,7 @@ package com.android.systemui.globalactions;
import static com.google.common.truth.Truth.assertThat;
import static junit.framework.Assert.assertEquals;
+import static junit.framework.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyBoolean;
@@ -244,7 +245,7 @@ public class GlobalActionsDialogTest extends SysuiTestCase {
}
@Test
- public void testCreateActionItems_maxThree() {
+ public void testCreateActionItems_maxThree_noOverflow() {
mGlobalActionsDialog = spy(mGlobalActionsDialog);
// allow 3 items to be shown
doReturn(3).when(mGlobalActionsDialog).getMaxShownPowerItems();
@@ -254,13 +255,129 @@ public class GlobalActionsDialogTest extends SysuiTestCase {
GlobalActionsDialog.GLOBAL_ACTION_KEY_EMERGENCY,
GlobalActionsDialog.GLOBAL_ACTION_KEY_POWER,
GlobalActionsDialog.GLOBAL_ACTION_KEY_RESTART,
+ };
+ doReturn(actions).when(mGlobalActionsDialog).getDefaultActions();
+ mGlobalActionsDialog.createActionItems();
+
+ assertEquals(3, mGlobalActionsDialog.mItems.size());
+ assertEquals(0, mGlobalActionsDialog.mOverflowItems.size());
+ assertEquals(0, mGlobalActionsDialog.mPowerItems.size());
+ }
+
+ @Test
+ public void testCreateActionItems_maxThree_condensePower() {
+ mGlobalActionsDialog = spy(mGlobalActionsDialog);
+ // allow 3 items to be shown
+ doReturn(3).when(mGlobalActionsDialog).getMaxShownPowerItems();
+ // ensure items are not blocked by keyguard or device provisioning
+ doReturn(true).when(mGlobalActionsDialog).shouldShowAction(any());
+ // make sure lockdown action will be shown
+ doReturn(true).when(mGlobalActionsDialog).shouldDisplayLockdown(any());
+ String[] actions = {
+ GlobalActionsDialog.GLOBAL_ACTION_KEY_EMERGENCY,
+ GlobalActionsDialog.GLOBAL_ACTION_KEY_POWER,
+ GlobalActionsDialog.GLOBAL_ACTION_KEY_RESTART,
+ GlobalActionsDialog.GLOBAL_ACTION_KEY_LOCKDOWN,
+ };
+ doReturn(actions).when(mGlobalActionsDialog).getDefaultActions();
+ mGlobalActionsDialog.createActionItems();
+
+ assertEquals(3, mGlobalActionsDialog.mItems.size());
+ assertEquals(0, mGlobalActionsDialog.mOverflowItems.size());
+ assertEquals(2, mGlobalActionsDialog.mPowerItems.size());
+
+ // PowerOptionsAction should appear immediately after the Emergency action
+
+ GlobalActionsDialog.Action firstItem = mGlobalActionsDialog.mItems.get(0);
+ GlobalActionsDialog.Action secondItem = mGlobalActionsDialog.mItems.get(1);
+
+ assertTrue(firstItem instanceof GlobalActionsDialog.EmergencyAction);
+ assertTrue(secondItem instanceof GlobalActionsDialog.PowerOptionsAction);
+ }
+
+ @Test
+ public void testCreateActionItems_maxThree_condensePower_noEmergency() {
+ mGlobalActionsDialog = spy(mGlobalActionsDialog);
+ // allow 3 items to be shown
+ doReturn(3).when(mGlobalActionsDialog).getMaxShownPowerItems();
+ // make sure lockdown action will be shown
+ doReturn(true).when(mGlobalActionsDialog).shouldDisplayLockdown(any());
+ // ensure items are not blocked by keyguard or device provisioning
+ doReturn(true).when(mGlobalActionsDialog).shouldShowAction(any());
+ String[] actions = {
+ GlobalActionsDialog.GLOBAL_ACTION_KEY_POWER,
+ GlobalActionsDialog.GLOBAL_ACTION_KEY_RESTART,
+ GlobalActionsDialog.GLOBAL_ACTION_KEY_SCREENSHOT,
+ GlobalActionsDialog.GLOBAL_ACTION_KEY_LOCKDOWN,
+ };
+ doReturn(actions).when(mGlobalActionsDialog).getDefaultActions();
+ mGlobalActionsDialog.createActionItems();
+
+ assertEquals(3, mGlobalActionsDialog.mItems.size());
+ assertEquals(0, mGlobalActionsDialog.mOverflowItems.size());
+ assertEquals(2, mGlobalActionsDialog.mPowerItems.size());
+
+ // When Emergency isn't used, PowerOptionsAction should be first
+
+ GlobalActionsDialog.Action firstItem = mGlobalActionsDialog.mItems.get(0);
+ GlobalActionsDialog.Action secondItem = mGlobalActionsDialog.mItems.get(1);
+
+ assertTrue(firstItem instanceof GlobalActionsDialog.PowerOptionsAction);
+ assertTrue(secondItem instanceof GlobalActionsDialog.ScreenshotAction);
+ }
+
+ @Test
+ public void testCreateActionItems_maxFour_condensePower() {
+ mGlobalActionsDialog = spy(mGlobalActionsDialog);
+ // allow 3 items to be shown
+ doReturn(4).when(mGlobalActionsDialog).getMaxShownPowerItems();
+ // make sure lockdown action will be shown
+ doReturn(true).when(mGlobalActionsDialog).shouldDisplayLockdown(any());
+ // ensure items are not blocked by keyguard or device provisioning
+ doReturn(true).when(mGlobalActionsDialog).shouldShowAction(any());
+ String[] actions = {
+ GlobalActionsDialog.GLOBAL_ACTION_KEY_EMERGENCY,
+ GlobalActionsDialog.GLOBAL_ACTION_KEY_POWER,
+ GlobalActionsDialog.GLOBAL_ACTION_KEY_RESTART,
+ GlobalActionsDialog.GLOBAL_ACTION_KEY_LOCKDOWN,
+ GlobalActionsDialog.GLOBAL_ACTION_KEY_SCREENSHOT
+ };
+ doReturn(actions).when(mGlobalActionsDialog).getDefaultActions();
+ mGlobalActionsDialog.createActionItems();
+
+ assertEquals(4, mGlobalActionsDialog.mItems.size());
+ assertEquals(0, mGlobalActionsDialog.mOverflowItems.size());
+ assertEquals(2, mGlobalActionsDialog.mPowerItems.size());
+
+ // with four items, make sure power still shows up immediately after Emergency
+ GlobalActionsDialog.Action firstItem = mGlobalActionsDialog.mItems.get(0);
+ GlobalActionsDialog.Action secondItem = mGlobalActionsDialog.mItems.get(1);
+
+ assertTrue(firstItem instanceof GlobalActionsDialog.EmergencyAction);
+ assertTrue(secondItem instanceof GlobalActionsDialog.PowerOptionsAction);
+ }
+
+ @Test
+ public void testCreateActionItems_maxThree_doNotCondensePower() {
+ mGlobalActionsDialog = spy(mGlobalActionsDialog);
+ // allow 3 items to be shown
+ doReturn(3).when(mGlobalActionsDialog).getMaxShownPowerItems();
+ // make sure lockdown action will be shown
+ doReturn(true).when(mGlobalActionsDialog).shouldDisplayLockdown(any());
+ // ensure items are not blocked by keyguard or device provisioning
+ doReturn(true).when(mGlobalActionsDialog).shouldShowAction(any());
+ String[] actions = {
+ GlobalActionsDialog.GLOBAL_ACTION_KEY_EMERGENCY,
+ GlobalActionsDialog.GLOBAL_ACTION_KEY_POWER,
GlobalActionsDialog.GLOBAL_ACTION_KEY_SCREENSHOT,
+ GlobalActionsDialog.GLOBAL_ACTION_KEY_LOCKDOWN,
};
doReturn(actions).when(mGlobalActionsDialog).getDefaultActions();
mGlobalActionsDialog.createActionItems();
assertEquals(3, mGlobalActionsDialog.mItems.size());
assertEquals(1, mGlobalActionsDialog.mOverflowItems.size());
+ assertEquals(0, mGlobalActionsDialog.mPowerItems.size());
}
@Test
@@ -270,11 +387,13 @@ public class GlobalActionsDialogTest extends SysuiTestCase {
doReturn(Integer.MAX_VALUE).when(mGlobalActionsDialog).getMaxShownPowerItems();
// ensure items are not blocked by keyguard or device provisioning
doReturn(true).when(mGlobalActionsDialog).shouldShowAction(any());
+ // make sure lockdown action will be shown
+ doReturn(true).when(mGlobalActionsDialog).shouldDisplayLockdown(any());
String[] actions = {
GlobalActionsDialog.GLOBAL_ACTION_KEY_EMERGENCY,
GlobalActionsDialog.GLOBAL_ACTION_KEY_POWER,
GlobalActionsDialog.GLOBAL_ACTION_KEY_RESTART,
- GlobalActionsDialog.GLOBAL_ACTION_KEY_SCREENSHOT,
+ GlobalActionsDialog.GLOBAL_ACTION_KEY_LOCKDOWN,
};
doReturn(actions).when(mGlobalActionsDialog).getDefaultActions();
mGlobalActionsDialog.createActionItems();
@@ -288,10 +407,12 @@ public class GlobalActionsDialogTest extends SysuiTestCase {
mGlobalActionsDialog = spy(mGlobalActionsDialog);
// allow only 3 items to be shown
doReturn(3).when(mGlobalActionsDialog).getMaxShownPowerItems();
+ // make sure lockdown action will NOT be shown
+ doReturn(false).when(mGlobalActionsDialog).shouldDisplayLockdown(any());
String[] actions = {
GlobalActionsDialog.GLOBAL_ACTION_KEY_EMERGENCY,
- // screenshot blocked because device not provisioned
- GlobalActionsDialog.GLOBAL_ACTION_KEY_SCREENSHOT,
+ // lockdown action not allowed
+ GlobalActionsDialog.GLOBAL_ACTION_KEY_LOCKDOWN,
GlobalActionsDialog.GLOBAL_ACTION_KEY_POWER,
GlobalActionsDialog.GLOBAL_ACTION_KEY_RESTART,
};
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/MediaControlPanelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/MediaControlPanelTest.kt
index 9d2b6f4deb14..737ced63eed0 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/MediaControlPanelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/MediaControlPanelTest.kt
@@ -31,6 +31,7 @@ import android.widget.ImageButton
import android.widget.ImageView
import android.widget.SeekBar
import android.widget.TextView
+import androidx.lifecycle.LiveData
import androidx.test.filters.SmallTest
import com.android.systemui.R
import com.android.systemui.SysuiTestCase
@@ -41,6 +42,7 @@ import com.android.systemui.util.time.FakeSystemClock
import com.google.common.truth.Truth.assertThat
import org.junit.After
import org.junit.Before
+import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.ArgumentCaptor
@@ -48,6 +50,7 @@ import org.mockito.Mock
import org.mockito.Mockito.mock
import org.mockito.Mockito.verify
import org.mockito.Mockito.`when` as whenever
+import org.mockito.junit.MockitoJUnit
private const val KEY = "TEST_KEY"
private const val APP = "APP"
@@ -67,13 +70,14 @@ public class MediaControlPanelTest : SysuiTestCase() {
private lateinit var player: MediaControlPanel
- private lateinit var fgExecutor: FakeExecutor
private lateinit var bgExecutor: FakeExecutor
@Mock private lateinit var activityStarter: ActivityStarter
@Mock private lateinit var holder: PlayerViewHolder
@Mock private lateinit var view: TransitionLayout
@Mock private lateinit var mediaHostStatesManager: MediaHostStatesManager
+ @Mock private lateinit var seekBarViewModel: SeekBarViewModel
+ @Mock private lateinit var seekBarData: LiveData<SeekBarViewModel.Progress>
private lateinit var appIcon: ImageView
private lateinit var appName: TextView
private lateinit var albumView: ImageView
@@ -95,20 +99,17 @@ public class MediaControlPanelTest : SysuiTestCase() {
private val device = MediaDeviceData(true, null, DEVICE_NAME)
private val disabledDevice = MediaDeviceData(false, null, null)
+ @JvmField @Rule val mockito = MockitoJUnit.rule()
+
@Before
fun setUp() {
- fgExecutor = FakeExecutor(FakeSystemClock())
bgExecutor = FakeExecutor(FakeSystemClock())
- activityStarter = mock(ActivityStarter::class.java)
- mediaHostStatesManager = mock(MediaHostStatesManager::class.java)
-
- player = MediaControlPanel(context, fgExecutor, bgExecutor, activityStarter,
- mediaHostStatesManager)
+ player = MediaControlPanel(context, bgExecutor, activityStarter, mediaHostStatesManager,
+ seekBarViewModel)
+ whenever(seekBarViewModel.progress).thenReturn(seekBarData)
// Mock out a view holder for the player to attach to.
- holder = mock(PlayerViewHolder::class.java)
- view = mock(TransitionLayout::class.java)
whenever(holder.player).thenReturn(view)
appIcon = ImageView(context)
whenever(holder.appIcon).thenReturn(appIcon)
@@ -171,7 +172,7 @@ public class MediaControlPanelTest : SysuiTestCase() {
@Test
fun bindWhenUnattached() {
val state = MediaData(true, BG_COLOR, APP, null, ARTIST, TITLE, null, emptyList(),
- emptyList(), PACKAGE, null, null, device)
+ emptyList(), PACKAGE, null, null, device, null)
player.bind(state)
assertThat(player.isPlaying()).isFalse()
}
@@ -180,7 +181,7 @@ public class MediaControlPanelTest : SysuiTestCase() {
fun bindText() {
player.attach(holder)
val state = MediaData(true, BG_COLOR, APP, null, ARTIST, TITLE, null, emptyList(),
- emptyList(), PACKAGE, session.getSessionToken(), null, device)
+ emptyList(), PACKAGE, session.getSessionToken(), null, device, null)
player.bind(state)
assertThat(appName.getText()).isEqualTo(APP)
assertThat(titleText.getText()).isEqualTo(TITLE)
@@ -191,7 +192,7 @@ public class MediaControlPanelTest : SysuiTestCase() {
fun bindBackgroundColor() {
player.attach(holder)
val state = MediaData(true, BG_COLOR, APP, null, ARTIST, TITLE, null, emptyList(),
- emptyList(), PACKAGE, session.getSessionToken(), null, device)
+ emptyList(), PACKAGE, session.getSessionToken(), null, device, null)
player.bind(state)
val list = ArgumentCaptor.forClass(ColorStateList::class.java)
verify(view).setBackgroundTintList(list.capture())
@@ -202,7 +203,7 @@ public class MediaControlPanelTest : SysuiTestCase() {
fun bindDevice() {
player.attach(holder)
val state = MediaData(true, BG_COLOR, APP, null, ARTIST, TITLE, null, emptyList(),
- emptyList(), PACKAGE, session.getSessionToken(), null, device)
+ emptyList(), PACKAGE, session.getSessionToken(), null, device, null)
player.bind(state)
assertThat(seamlessText.getText()).isEqualTo(DEVICE_NAME)
assertThat(seamless.isEnabled()).isTrue()
@@ -212,7 +213,7 @@ public class MediaControlPanelTest : SysuiTestCase() {
fun bindDisabledDevice() {
player.attach(holder)
val state = MediaData(true, BG_COLOR, APP, null, ARTIST, TITLE, null, emptyList(),
- emptyList(), PACKAGE, session.getSessionToken(), null, disabledDevice)
+ emptyList(), PACKAGE, session.getSessionToken(), null, disabledDevice, null)
player.bind(state)
assertThat(seamless.isEnabled()).isFalse()
assertThat(seamlessText.getText()).isEqualTo(context.getResources().getString(
@@ -223,7 +224,7 @@ public class MediaControlPanelTest : SysuiTestCase() {
fun bindNullDevice() {
player.attach(holder)
val state = MediaData(true, BG_COLOR, APP, null, ARTIST, TITLE, null, emptyList(),
- emptyList(), PACKAGE, session.getSessionToken(), null, null)
+ emptyList(), PACKAGE, session.getSessionToken(), null, null, null)
player.bind(state)
assertThat(seamless.isEnabled()).isTrue()
assertThat(seamlessText.getText()).isEqualTo(context.getResources().getString(
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/MediaDataCombineLatestTest.java b/packages/SystemUI/tests/src/com/android/systemui/media/MediaDataCombineLatestTest.java
index 48e3b0a9d993..bed5c9eb6df5 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/MediaDataCombineLatestTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/MediaDataCombineLatestTest.java
@@ -79,16 +79,16 @@ public class MediaDataCombineLatestTest extends SysuiTestCase {
mManager.addListener(mListener);
mMediaData = new MediaData(true, BG_COLOR, APP, null, ARTIST, TITLE, null,
- new ArrayList<>(), new ArrayList<>(), PACKAGE, null, null, null, KEY);
+ new ArrayList<>(), new ArrayList<>(), PACKAGE, null, null, null, null, KEY, false);
mDeviceData = new MediaDeviceData(true, null, DEVICE_NAME);
}
@Test
public void eventNotEmittedWithoutDevice() {
// WHEN data source emits an event without device data
- mDataListener.onMediaDataLoaded(KEY, mMediaData);
+ mDataListener.onMediaDataLoaded(KEY, null, mMediaData);
// THEN an event isn't emitted
- verify(mListener, never()).onMediaDataLoaded(eq(KEY), any());
+ verify(mListener, never()).onMediaDataLoaded(eq(KEY), any(), any());
}
@Test
@@ -96,7 +96,7 @@ public class MediaDataCombineLatestTest extends SysuiTestCase {
// WHEN device source emits an event without media data
mDeviceListener.onMediaDeviceChanged(KEY, mDeviceData);
// THEN an event isn't emitted
- verify(mListener, never()).onMediaDataLoaded(eq(KEY), any());
+ verify(mListener, never()).onMediaDataLoaded(eq(KEY), any(), any());
}
@Test
@@ -104,22 +104,22 @@ public class MediaDataCombineLatestTest extends SysuiTestCase {
// GIVEN that a device event has already been received
mDeviceListener.onMediaDeviceChanged(KEY, mDeviceData);
// WHEN media event is received
- mDataListener.onMediaDataLoaded(KEY, mMediaData);
+ mDataListener.onMediaDataLoaded(KEY, null, mMediaData);
// THEN the listener receives a combined event
ArgumentCaptor<MediaData> captor = ArgumentCaptor.forClass(MediaData.class);
- verify(mListener).onMediaDataLoaded(eq(KEY), captor.capture());
+ verify(mListener).onMediaDataLoaded(eq(KEY), any(), captor.capture());
assertThat(captor.getValue().getDevice()).isNotNull();
}
@Test
public void emitEventAfterMediaFirst() {
// GIVEN that media event has already been received
- mDataListener.onMediaDataLoaded(KEY, mMediaData);
+ mDataListener.onMediaDataLoaded(KEY, null, mMediaData);
// WHEN device event is received
mDeviceListener.onMediaDeviceChanged(KEY, mDeviceData);
// THEN the listener receives a combined event
ArgumentCaptor<MediaData> captor = ArgumentCaptor.forClass(MediaData.class);
- verify(mListener).onMediaDataLoaded(eq(KEY), captor.capture());
+ verify(mListener).onMediaDataLoaded(eq(KEY), any(), captor.capture());
assertThat(captor.getValue().getDevice()).isNotNull();
}
@@ -133,7 +133,7 @@ public class MediaDataCombineLatestTest extends SysuiTestCase {
@Test
public void mediaDataRemovedAfterMediaEvent() {
- mDataListener.onMediaDataLoaded(KEY, mMediaData);
+ mDataListener.onMediaDataLoaded(KEY, null, mMediaData);
mDataListener.onMediaDataRemoved(KEY);
verify(mListener).onMediaDataRemoved(eq(KEY));
}
@@ -145,6 +145,18 @@ public class MediaDataCombineLatestTest extends SysuiTestCase {
verify(mListener).onMediaDataRemoved(eq(KEY));
}
+ @Test
+ public void mediaDataKeyUpdated() {
+ // GIVEN that device and media events have already been received
+ mDataListener.onMediaDataLoaded(KEY, null, mMediaData);
+ mDeviceListener.onMediaDeviceChanged(KEY, mDeviceData);
+ // WHEN the key is changed
+ mDataListener.onMediaDataLoaded("NEW_KEY", KEY, mMediaData);
+ // THEN the listener gets a load event with the correct keys
+ ArgumentCaptor<MediaData> captor = ArgumentCaptor.forClass(MediaData.class);
+ verify(mListener).onMediaDataLoaded(eq("NEW_KEY"), any(), captor.capture());
+ }
+
private MediaDataManager.Listener captureDataListener() {
ArgumentCaptor<MediaDataManager.Listener> captor = ArgumentCaptor.forClass(
MediaDataManager.Listener.class);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/MediaDeviceManagerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/MediaDeviceManagerTest.kt
index c0aef8adc4af..6fcf6e37572b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/MediaDeviceManagerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/MediaDeviceManagerTest.kt
@@ -23,8 +23,6 @@ import android.media.MediaRouter2Manager
import android.media.RoutingSessionInfo
import android.media.session.MediaSession
import android.media.session.PlaybackState
-import android.os.Process
-import android.service.notification.StatusBarNotification
import android.testing.AndroidTestingRunner
import android.testing.TestableLooper
import androidx.test.filters.SmallTest
@@ -53,6 +51,7 @@ import org.mockito.Mockito.`when` as whenever
import org.mockito.junit.MockitoJUnit
private const val KEY = "TEST_KEY"
+private const val KEY_OLD = "TEST_KEY_OLD"
private const val PACKAGE = "PKG"
private const val SESSION_KEY = "SESSION_KEY"
private const val SESSION_ARTIST = "SESSION_ARTIST"
@@ -67,10 +66,10 @@ private fun <T> eq(value: T): T = Mockito.eq(value) ?: value
public class MediaDeviceManagerTest : SysuiTestCase() {
private lateinit var manager: MediaDeviceManager
+ @Mock private lateinit var mediaDataManager: MediaDataManager
@Mock private lateinit var lmmFactory: LocalMediaManagerFactory
@Mock private lateinit var lmm: LocalMediaManager
@Mock private lateinit var mr2: MediaRouter2Manager
- @Mock private lateinit var featureFlag: MediaFeatureFlag
private lateinit var fakeExecutor: FakeExecutor
@Mock private lateinit var listener: MediaDeviceManager.Listener
@Mock private lateinit var device: MediaDevice
@@ -80,13 +79,13 @@ public class MediaDeviceManagerTest : SysuiTestCase() {
private lateinit var metadataBuilder: MediaMetadata.Builder
private lateinit var playbackBuilder: PlaybackState.Builder
private lateinit var notifBuilder: Notification.Builder
- private lateinit var sbn: StatusBarNotification
+ private lateinit var mediaData: MediaData
@JvmField @Rule val mockito = MockitoJUnit.rule()
@Before
fun setUp() {
fakeExecutor = FakeExecutor(FakeSystemClock())
- manager = MediaDeviceManager(context, lmmFactory, mr2, featureFlag, fakeExecutor)
+ manager = MediaDeviceManager(context, lmmFactory, mr2, fakeExecutor, mediaDataManager)
manager.addListener(listener)
// Configure mocks.
@@ -95,7 +94,6 @@ public class MediaDeviceManagerTest : SysuiTestCase() {
whenever(lmmFactory.create(PACKAGE)).thenReturn(lmm)
whenever(lmm.getCurrentConnectedDevice()).thenReturn(device)
whenever(mr2.getRoutingSessionForMediaController(any())).thenReturn(route)
- whenever(featureFlag.enabled).thenReturn(true)
// Create a media sesssion and notification for testing.
metadataBuilder = MediaMetadata.Builder().apply {
@@ -117,8 +115,8 @@ public class MediaDeviceManagerTest : SysuiTestCase() {
setSmallIcon(android.R.drawable.ic_media_pause)
setStyle(Notification.MediaStyle().setMediaSession(session.getSessionToken()))
}
- sbn = StatusBarNotification(PACKAGE, PACKAGE, 0, "TAG", Process.myUid(), 0, 0,
- notifBuilder.build(), Process.myUserHandle(), 0)
+ mediaData = MediaData(true, 0, PACKAGE, null, null, SESSION_TITLE, null,
+ emptyList(), emptyList(), PACKAGE, session.sessionToken, null, null, null)
}
@After
@@ -128,33 +126,84 @@ public class MediaDeviceManagerTest : SysuiTestCase() {
@Test
fun removeUnknown() {
- manager.onNotificationRemoved("unknown")
+ manager.onMediaDataRemoved("unknown")
}
@Test
- fun addNotification() {
- manager.onNotificationAdded(KEY, sbn)
+ fun loadMediaData() {
+ manager.onMediaDataLoaded(KEY, null, mediaData)
verify(lmmFactory).create(PACKAGE)
}
@Test
- fun featureDisabled() {
- whenever(featureFlag.enabled).thenReturn(false)
- manager.onNotificationAdded(KEY, sbn)
- verify(lmmFactory, never()).create(PACKAGE)
+ fun loadAndRemoveMediaData() {
+ manager.onMediaDataLoaded(KEY, null, mediaData)
+ manager.onMediaDataRemoved(KEY)
+ verify(lmm).unregisterCallback(any())
+ }
+
+ @Test
+ fun loadMediaDataWithNullToken() {
+ manager.onMediaDataLoaded(KEY, null, mediaData.copy(token = null))
+ fakeExecutor.runAllReady()
+ val data = captureDeviceData(KEY)
+ assertThat(data.enabled).isTrue()
+ assertThat(data.name).isEqualTo(DEVICE_NAME)
}
@Test
- fun addAndRemoveNotification() {
- manager.onNotificationAdded(KEY, sbn)
- manager.onNotificationRemoved(KEY)
+ fun loadWithNewKey() {
+ // GIVEN that media data has been loaded with an old key
+ manager.onMediaDataLoaded(KEY_OLD, null, mediaData)
+ reset(listener)
+ // WHEN data is loaded with a new key
+ manager.onMediaDataLoaded(KEY, KEY_OLD, mediaData)
+ // THEN the listener for the old key should removed.
verify(lmm).unregisterCallback(any())
+ // AND a new device event emitted
+ val data = captureDeviceData(KEY)
+ assertThat(data.enabled).isTrue()
+ assertThat(data.name).isEqualTo(DEVICE_NAME)
+ }
+
+ @Test
+ fun newKeySameAsOldKey() {
+ // GIVEN that media data has been loaded
+ manager.onMediaDataLoaded(KEY, null, mediaData)
+ reset(listener)
+ // WHEN the new key is the same as the old key
+ manager.onMediaDataLoaded(KEY, KEY, mediaData)
+ // THEN no event should be emitted
+ verify(listener, never()).onMediaDeviceChanged(eq(KEY), any())
+ }
+
+ @Test
+ fun unknownOldKey() {
+ manager.onMediaDataLoaded(KEY, "unknown", mediaData)
+ verify(listener).onMediaDeviceChanged(eq(KEY), any())
+ }
+
+ @Test
+ fun updateToSessionTokenWithNullRoute() {
+ // GIVEN that media data has been loaded with a null token
+ manager.onMediaDataLoaded(KEY, null, mediaData.copy(token = null))
+ // WHEN media data is loaded with a different token
+ // AND that token results in a null route
+ reset(listener)
+ whenever(mr2.getRoutingSessionForMediaController(any())).thenReturn(null)
+ manager.onMediaDataLoaded(KEY, null, mediaData)
+ // THEN the device should be disabled
+ fakeExecutor.runAllReady()
+ val data = captureDeviceData(KEY)
+ assertThat(data.enabled).isFalse()
+ assertThat(data.name).isNull()
+ assertThat(data.icon).isNull()
}
@Test
fun deviceEventOnAddNotification() {
// WHEN a notification is added
- manager.onNotificationAdded(KEY, sbn)
+ manager.onMediaDataLoaded(KEY, null, mediaData)
val deviceCallback = captureCallback()
// THEN the update is dispatched to the listener
val data = captureDeviceData(KEY)
@@ -164,8 +213,17 @@ public class MediaDeviceManagerTest : SysuiTestCase() {
}
@Test
+ fun removeListener() {
+ // WHEN a listener is removed
+ manager.removeListener(listener)
+ // THEN it doesn't receive device events
+ manager.onMediaDataLoaded(KEY, null, mediaData)
+ verify(listener, never()).onMediaDeviceChanged(eq(KEY), any())
+ }
+
+ @Test
fun deviceListUpdate() {
- manager.onNotificationAdded(KEY, sbn)
+ manager.onMediaDataLoaded(KEY, null, mediaData)
val deviceCallback = captureCallback()
// WHEN the device list changes
deviceCallback.onDeviceListUpdate(mutableListOf(device))
@@ -179,7 +237,7 @@ public class MediaDeviceManagerTest : SysuiTestCase() {
@Test
fun selectedDeviceStateChanged() {
- manager.onNotificationAdded(KEY, sbn)
+ manager.onMediaDataLoaded(KEY, null, mediaData)
val deviceCallback = captureCallback()
// WHEN the selected device changes state
deviceCallback.onSelectedDeviceStateChanged(device, 1)
@@ -193,9 +251,9 @@ public class MediaDeviceManagerTest : SysuiTestCase() {
@Test
fun listenerReceivesKeyRemoved() {
- manager.onNotificationAdded(KEY, sbn)
+ manager.onMediaDataLoaded(KEY, null, mediaData)
// WHEN the notification is removed
- manager.onNotificationRemoved(KEY)
+ manager.onMediaDataRemoved(KEY)
// THEN the listener receives key removed event
verify(listener).onKeyRemoved(eq(KEY))
}
@@ -205,7 +263,7 @@ public class MediaDeviceManagerTest : SysuiTestCase() {
// GIVEN that MR2Manager returns null for routing session
whenever(mr2.getRoutingSessionForMediaController(any())).thenReturn(null)
// WHEN a notification is added
- manager.onNotificationAdded(KEY, sbn)
+ manager.onMediaDataLoaded(KEY, null, mediaData)
// THEN the device is disabled
val data = captureDeviceData(KEY)
assertThat(data.enabled).isFalse()
@@ -216,7 +274,7 @@ public class MediaDeviceManagerTest : SysuiTestCase() {
@Test
fun deviceDisabledWhenMR2ReturnsNullRouteInfoOnDeviceChanged() {
// GIVEN a notif is added
- manager.onNotificationAdded(KEY, sbn)
+ manager.onMediaDataLoaded(KEY, null, mediaData)
reset(listener)
// AND MR2Manager returns null for routing session
whenever(mr2.getRoutingSessionForMediaController(any())).thenReturn(null)
@@ -234,7 +292,7 @@ public class MediaDeviceManagerTest : SysuiTestCase() {
@Test
fun deviceDisabledWhenMR2ReturnsNullRouteInfoOnDeviceListUpdate() {
// GIVEN a notif is added
- manager.onNotificationAdded(KEY, sbn)
+ manager.onMediaDataLoaded(KEY, null, mediaData)
reset(listener)
// GIVEN that MR2Manager returns null for routing session
whenever(mr2.getRoutingSessionForMediaController(any())).thenReturn(null)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/MediaTimeoutListenerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/MediaTimeoutListenerTest.kt
index c21343cb5423..7d44327b0d38 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/MediaTimeoutListenerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/MediaTimeoutListenerTest.kt
@@ -16,7 +16,9 @@
package com.android.systemui.media
+import android.media.MediaMetadata
import android.media.session.MediaController
+import android.media.session.MediaSession
import android.media.session.PlaybackState
import android.testing.AndroidTestingRunner
import androidx.test.filters.SmallTest
@@ -41,6 +43,10 @@ import org.mockito.Mockito.verify
import org.mockito.junit.MockitoJUnit
private const val KEY = "KEY"
+private const val PACKAGE = "PKG"
+private const val SESSION_KEY = "SESSION_KEY"
+private const val SESSION_ARTIST = "SESSION_ARTIST"
+private const val SESSION_TITLE = "SESSION_TITLE"
private fun <T> eq(value: T): T = Mockito.eq(value) ?: value
private fun <T> anyObject(): T {
@@ -54,12 +60,15 @@ class MediaTimeoutListenerTest : SysuiTestCase() {
@Mock private lateinit var mediaControllerFactory: MediaControllerFactory
@Mock private lateinit var mediaController: MediaController
@Mock private lateinit var executor: DelayableExecutor
- @Mock private lateinit var mediaData: MediaData
@Mock private lateinit var timeoutCallback: (String, Boolean) -> Unit
@Mock private lateinit var cancellationRunnable: Runnable
@Captor private lateinit var timeoutCaptor: ArgumentCaptor<Runnable>
@Captor private lateinit var mediaCallbackCaptor: ArgumentCaptor<MediaController.Callback>
@JvmField @Rule val mockito = MockitoJUnit.rule()
+ private lateinit var metadataBuilder: MediaMetadata.Builder
+ private lateinit var playbackBuilder: PlaybackState.Builder
+ private lateinit var session: MediaSession
+ private lateinit var mediaData: MediaData
private lateinit var mediaTimeoutListener: MediaTimeoutListener
@Before
@@ -68,22 +77,39 @@ class MediaTimeoutListenerTest : SysuiTestCase() {
`when`(executor.executeDelayed(any(), anyLong())).thenReturn(cancellationRunnable)
mediaTimeoutListener = MediaTimeoutListener(mediaControllerFactory, executor)
mediaTimeoutListener.timeoutCallback = timeoutCallback
+
+ // Create a media session and notification for testing.
+ metadataBuilder = MediaMetadata.Builder().apply {
+ putString(MediaMetadata.METADATA_KEY_ARTIST, SESSION_ARTIST)
+ putString(MediaMetadata.METADATA_KEY_TITLE, SESSION_TITLE)
+ }
+ playbackBuilder = PlaybackState.Builder().apply {
+ setState(PlaybackState.STATE_PAUSED, 6000L, 1f)
+ setActions(PlaybackState.ACTION_PLAY)
+ }
+ session = MediaSession(context, SESSION_KEY).apply {
+ setMetadata(metadataBuilder.build())
+ setPlaybackState(playbackBuilder.build())
+ }
+ session.setActive(true)
+ mediaData = MediaData(true, 0, PACKAGE, null, null, SESSION_TITLE, null,
+ emptyList(), emptyList(), PACKAGE, session.sessionToken, null, null, null)
}
@Test
fun testOnMediaDataLoaded_registersPlaybackListener() {
- mediaTimeoutListener.onMediaDataLoaded(KEY, mediaData)
+ mediaTimeoutListener.onMediaDataLoaded(KEY, null, mediaData)
verify(mediaController).registerCallback(capture(mediaCallbackCaptor))
// Ignores is same key
clearInvocations(mediaController)
- mediaTimeoutListener.onMediaDataLoaded(KEY, mediaData)
+ mediaTimeoutListener.onMediaDataLoaded(KEY, KEY, mediaData)
verify(mediaController, never()).registerCallback(anyObject())
}
@Test
fun testOnMediaDataRemoved_unregistersPlaybackListener() {
- mediaTimeoutListener.onMediaDataLoaded(KEY, mediaData)
+ mediaTimeoutListener.onMediaDataLoaded(KEY, null, mediaData)
mediaTimeoutListener.onMediaDataRemoved(KEY)
verify(mediaController).unregisterCallback(anyObject())
@@ -105,7 +131,7 @@ class MediaTimeoutListenerTest : SysuiTestCase() {
@Test
fun testOnPlaybackStateChanged_cancelsTimeout_whenResumed() {
- // Assuming we're have a pending timeout
+ // Assuming we have a pending timeout
testOnPlaybackStateChanged_schedulesTimeout_whenPaused()
mediaCallbackCaptor.value.onPlaybackStateChanged(PlaybackState.Builder()
@@ -114,6 +140,17 @@ class MediaTimeoutListenerTest : SysuiTestCase() {
}
@Test
+ fun testOnPlaybackStateChanged_reusesTimeout_whenNotPlaying() {
+ // Assuming we have a pending timeout
+ testOnPlaybackStateChanged_schedulesTimeout_whenPaused()
+
+ clearInvocations(cancellationRunnable)
+ mediaCallbackCaptor.value.onPlaybackStateChanged(PlaybackState.Builder()
+ .setState(PlaybackState.STATE_STOPPED, 0L, 0f).build())
+ verify(cancellationRunnable, never()).run()
+ }
+
+ @Test
fun testTimeoutCallback_invokedIfTimeout() {
// Assuming we're have a pending timeout
testOnPlaybackStateChanged_schedulesTimeout_whenPaused()
@@ -124,7 +161,7 @@ class MediaTimeoutListenerTest : SysuiTestCase() {
@Test
fun testIsTimedOut() {
- mediaTimeoutListener.onMediaDataLoaded(KEY, mediaData)
+ mediaTimeoutListener.onMediaDataLoaded(KEY, null, mediaData)
assertThat(mediaTimeoutListener.isTimedOut(KEY)).isFalse()
}
} \ No newline at end of file
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/SeekBarViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/SeekBarViewModelTest.kt
index 19e15b3c4307..24e9bd837d5d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/SeekBarViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/SeekBarViewModelTest.kt
@@ -29,6 +29,7 @@ import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.util.concurrency.FakeExecutor
+import com.android.systemui.util.concurrency.FakeRepeatableExecutor
import com.android.systemui.util.time.FakeSystemClock
import com.google.common.truth.Truth.assertThat
@@ -71,7 +72,7 @@ public class SeekBarViewModelTest : SysuiTestCase() {
@Before
fun setUp() {
fakeExecutor = FakeExecutor(FakeSystemClock())
- viewModel = SeekBarViewModel(fakeExecutor)
+ viewModel = SeekBarViewModel(FakeRepeatableExecutor(fakeExecutor))
mockController = mock(MediaController::class.java)
whenever(mockController.sessionToken).thenReturn(token1)
mockTransport = mock(MediaController.TransportControls::class.java)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/QSTileHostTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/QSTileHostTest.java
index 11477395a781..5d4ef550b36c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/QSTileHostTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/QSTileHostTest.java
@@ -219,13 +219,43 @@ public class QSTileHostTest extends SysuiTestCase {
public void testNoRepeatedSpecs_customTile() {
mQSTileHost.onTuningChanged(QSTileHost.TILES_SETTING, CUSTOM_TILE_SPEC);
- mQSTileHost.addTile(CUSTOM_TILE);
+ mQSTileHost.addTile(CUSTOM_TILE, /* end */ false);
assertEquals(1, mQSTileHost.mTileSpecs.size());
assertEquals(CUSTOM_TILE_SPEC, mQSTileHost.mTileSpecs.get(0));
}
@Test
+ public void testAddedAtBeginningOnDefault_customTile() {
+ mQSTileHost.onTuningChanged(QSTileHost.TILES_SETTING, "spec1"); // seed
+
+ mQSTileHost.addTile(CUSTOM_TILE);
+
+ assertEquals(2, mQSTileHost.mTileSpecs.size());
+ assertEquals(CUSTOM_TILE_SPEC, mQSTileHost.mTileSpecs.get(0));
+ }
+
+ @Test
+ public void testAddedAtBeginning_customTile() {
+ mQSTileHost.onTuningChanged(QSTileHost.TILES_SETTING, "spec1"); // seed
+
+ mQSTileHost.addTile(CUSTOM_TILE, /* end */ false);
+
+ assertEquals(2, mQSTileHost.mTileSpecs.size());
+ assertEquals(CUSTOM_TILE_SPEC, mQSTileHost.mTileSpecs.get(0));
+ }
+
+ @Test
+ public void testAddedAtEnd_customTile() {
+ mQSTileHost.onTuningChanged(QSTileHost.TILES_SETTING, "spec1"); // seed
+
+ mQSTileHost.addTile(CUSTOM_TILE, /* end */ true);
+
+ assertEquals(2, mQSTileHost.mTileSpecs.size());
+ assertEquals(CUSTOM_TILE_SPEC, mQSTileHost.mTileSpecs.get(1));
+ }
+
+ @Test
public void testLoadTileSpec_repeated() {
List<String> specs = QSTileHost.loadTileSpecs(mContext, "spec1,spec1,spec2");
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileServicesTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileServicesTest.java
index 2fc3d72c2672..53ed4cf12b2f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileServicesTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileServicesTest.java
@@ -18,13 +18,22 @@ package com.android.systemui.qs.external;
import static junit.framework.Assert.assertEquals;
import static junit.framework.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyLong;
+import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.content.ComponentName;
+import android.content.IntentFilter;
import android.os.Handler;
import android.os.Looper;
+import android.os.UserHandle;
import android.service.quicksettings.Tile;
+import android.service.quicksettings.TileService;
import android.test.suitebuilder.annotation.SmallTest;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
@@ -50,7 +59,6 @@ import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
-import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;
import java.util.ArrayList;
@@ -99,7 +107,7 @@ public class TileServicesTest extends SysuiTestCase {
mTunerService,
() -> mAutoTileManager,
mDumpManager,
- mBroadcastDispatcher,
+ mock(BroadcastDispatcher.class),
Optional.of(mStatusBar),
mQSLogger,
mUiEventLogger);
@@ -113,6 +121,14 @@ public class TileServicesTest extends SysuiTestCase {
}
@Test
+ public void testActiveTileListenerRegisteredOnAllUsers() {
+ ArgumentCaptor<IntentFilter> captor = ArgumentCaptor.forClass(IntentFilter.class);
+ verify(mBroadcastDispatcher).registerReceiver(any(), captor.capture(), any(), eq(
+ UserHandle.ALL));
+ assertTrue(captor.getValue().hasAction(TileService.ACTION_REQUEST_LISTENING));
+ }
+
+ @Test
public void testRecalculateBindAllowance() {
// Add some fake tiles.
for (int i = 0; i < NUM_FAKES; i++) {
@@ -125,10 +141,9 @@ public class TileServicesTest extends SysuiTestCase {
}
mTileService.recalculateBindAllowance();
for (int i = 0; i < NUM_FAKES; i++) {
- Mockito.verify(mManagers.get(i), Mockito.times(1)).calculateBindPriority(
- Mockito.anyLong());
+ verify(mManagers.get(i), times(1)).calculateBindPriority(anyLong());
ArgumentCaptor<Boolean> captor = ArgumentCaptor.forClass(Boolean.class);
- Mockito.verify(mManagers.get(i), Mockito.times(1)).setBindAllowed(captor.capture());
+ verify(mManagers.get(i), times(1)).setBindAllowed(captor.capture());
assertEquals("" + i + "th service", i >= (NUM_FAKES - TileServices.DEFAULT_MAX_BOUND),
(boolean) captor.getValue());
@@ -142,7 +157,7 @@ public class TileServicesTest extends SysuiTestCase {
for (int i = 0; i < NUM_FAKES; i++) {
ArgumentCaptor<Boolean> captor = ArgumentCaptor.forClass(Boolean.class);
- Mockito.verify(mManagers.get(i), Mockito.times(2)).setBindAllowed(captor.capture());
+ verify(mManagers.get(i), times(2)).setBindAllowed(captor.capture());
assertEquals("" + i + "th service", i >= (NUM_FAKES - TileServices.REDUCED_MAX_BOUND),
(boolean) captor.getValue());
@@ -158,12 +173,12 @@ public class TileServicesTest extends SysuiTestCase {
for (int i = 0; i < TileServices.DEFAULT_MAX_BOUND - 1; i++) {
// Shouldn't get bind prioirities calculated when there are less than the max services.
- Mockito.verify(mManagers.get(i), Mockito.never()).calculateBindPriority(
- Mockito.anyLong());
+ verify(mManagers.get(i), never()).calculateBindPriority(
+ anyLong());
// All should be bound since there are less than the max services.
ArgumentCaptor<Boolean> captor = ArgumentCaptor.forClass(Boolean.class);
- Mockito.verify(mManagers.get(i), Mockito.times(1)).setBindAllowed(captor.capture());
+ verify(mManagers.get(i), times(1)).setBindAllowed(captor.capture());
assertTrue(captor.getValue());
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/ScreenRecordTileTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/ScreenRecordTileTest.java
index 8a8d2272d563..e5024595d97e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/ScreenRecordTileTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/ScreenRecordTileTest.java
@@ -29,6 +29,7 @@ import android.testing.TestableLooper;
import androidx.test.filters.SmallTest;
+import com.android.internal.logging.UiEventLogger;
import com.android.systemui.Dependency;
import com.android.systemui.R;
import com.android.systemui.SysuiTestCase;
@@ -53,6 +54,8 @@ public class ScreenRecordTileTest extends SysuiTestCase {
private ActivityStarter mActivityStarter;
@Mock
private QSTileHost mHost;
+ @Mock
+ private UiEventLogger mUiEventLogger;
private TestableLooper mTestableLooper;
private ScreenRecordTile mTile;
@@ -68,7 +71,7 @@ public class ScreenRecordTileTest extends SysuiTestCase {
when(mHost.getContext()).thenReturn(mContext);
- mTile = new ScreenRecordTile(mHost, mController, mActivityStarter);
+ mTile = new ScreenRecordTile(mHost, mController, mActivityStarter, mUiEventLogger);
}
// Test that the tile is inactive and labeled correctly when the controller is neither starting
diff --git a/packages/SystemUI/tests/src/com/android/systemui/screenrecord/RecordingServiceTest.java b/packages/SystemUI/tests/src/com/android/systemui/screenrecord/RecordingServiceTest.java
new file mode 100644
index 000000000000..283a47ca3622
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/screenrecord/RecordingServiceTest.java
@@ -0,0 +1,114 @@
+/*
+ * 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.screenrecord;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.Mockito.doNothing;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+
+import android.app.Notification;
+import android.app.NotificationManager;
+import android.content.Intent;
+import android.testing.AndroidTestingRunner;
+
+import androidx.test.filters.SmallTest;
+
+import com.android.internal.logging.UiEventLogger;
+import com.android.systemui.SysuiTestCase;
+
+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;
+
+import java.util.concurrent.Executor;
+
+@RunWith(AndroidTestingRunner.class)
+@SmallTest
+public class RecordingServiceTest extends SysuiTestCase {
+
+ @Mock
+ private UiEventLogger mUiEventLogger;
+ @Mock
+ private RecordingController mController;
+ @Mock
+ private NotificationManager mNotificationManager;
+ @Mock
+ private ScreenMediaRecorder mScreenMediaRecorder;
+ @Mock
+ private Notification mNotification;
+ @Mock
+ private Executor mExecutor;
+
+ private RecordingService mRecordingService;
+
+ @Before
+ public void setUp() throws Exception {
+ MockitoAnnotations.initMocks(this);
+ mRecordingService = Mockito.spy(new RecordingService(mController, mExecutor, mUiEventLogger,
+ mNotificationManager));
+
+ // Return actual context info
+ doReturn(mContext).when(mRecordingService).getApplicationContext();
+ doReturn(mContext.getUserId()).when(mRecordingService).getUserId();
+ doReturn(mContext.getPackageName()).when(mRecordingService).getPackageName();
+ doReturn(mContext.getContentResolver()).when(mRecordingService).getContentResolver();
+
+ // Mock notifications
+ doNothing().when(mRecordingService).createRecordingNotification();
+ doReturn(mNotification).when(mRecordingService).createProcessingNotification();
+ doReturn(mNotification).when(mRecordingService).createSaveNotification(any());
+
+ doNothing().when(mRecordingService).startForeground(anyInt(), any());
+ doReturn(mScreenMediaRecorder).when(mRecordingService).getRecorder();
+ }
+
+ @Test
+ public void testLogStartRecording() {
+ Intent startIntent = RecordingService.getStartIntent(mContext, 0, 0, false);
+ mRecordingService.onStartCommand(startIntent, 0, 0);
+
+ verify(mUiEventLogger, times(1)).log(Events.ScreenRecordEvent.SCREEN_RECORD_START);
+ }
+
+ @Test
+ public void testLogStopFromQsTile() {
+ Intent stopIntent = RecordingService.getStopIntent(mContext);
+ mRecordingService.onStartCommand(stopIntent, 0, 0);
+
+ // Verify that we log the correct event
+ verify(mUiEventLogger, times(1)).log(Events.ScreenRecordEvent.SCREEN_RECORD_END_QS_TILE);
+ verify(mUiEventLogger, times(0))
+ .log(Events.ScreenRecordEvent.SCREEN_RECORD_END_NOTIFICATION);
+ }
+
+ @Test
+ public void testLogStopFromNotificationIntent() {
+ Intent stopIntent = RecordingService.getNotificationIntent(mContext);
+ mRecordingService.onStartCommand(stopIntent, 0, 0);
+
+ // Verify that we log the correct event
+ verify(mUiEventLogger, times(1))
+ .log(Events.ScreenRecordEvent.SCREEN_RECORD_END_NOTIFICATION);
+ verify(mUiEventLogger, times(0)).log(Events.ScreenRecordEvent.SCREEN_RECORD_END_QS_TILE);
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationFilterTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationFilterTest.java
index 595ba89ca3b6..5a81d36ea744 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationFilterTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationFilterTest.java
@@ -27,8 +27,10 @@ import static org.mockito.Mockito.when;
import android.Manifest;
import android.app.Notification;
+import android.app.Notification.MediaStyle;
import android.content.pm.IPackageManager;
import android.content.pm.PackageManager;
+import android.media.session.MediaSession;
import android.os.Bundle;
import android.service.notification.StatusBarNotification;
import android.testing.AndroidTestingRunner;
@@ -40,6 +42,7 @@ import androidx.test.filters.SmallTest;
import com.android.systemui.ForegroundServiceController;
import com.android.systemui.SysuiTestCase;
+import com.android.systemui.media.MediaFeatureFlag;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.statusbar.NotificationLockscreenUserManager;
import com.android.systemui.statusbar.notification.NotificationEntryManager.KeyguardEnvironment;
@@ -51,6 +54,7 @@ import com.android.systemui.statusbar.notification.row.NotificationTestHelper;
import com.android.systemui.statusbar.phone.NotificationGroupManager;
import com.android.systemui.statusbar.phone.ShadeController;
+import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -73,10 +77,16 @@ public class NotificationFilterTest extends SysuiTestCase {
ForegroundServiceController mFsc;
@Mock
KeyguardEnvironment mEnvironment;
+ @Mock
+ MediaFeatureFlag mMediaFeatureFlag;
+ @Mock
+ StatusBarStateController mStatusBarStateController;
private final IPackageManager mMockPackageManager = mock(IPackageManager.class);
private NotificationFilter mNotificationFilter;
private ExpandableNotificationRow mRow;
+ private NotificationEntry mMediaEntry;
+ private MediaSession mMediaSession;
@Before
public void setUp() throws Exception {
@@ -84,6 +94,12 @@ public class NotificationFilterTest extends SysuiTestCase {
MockitoAnnotations.initMocks(this);
when(mMockStatusBarNotification.getUid()).thenReturn(UID_NORMAL);
+ mMediaSession = new MediaSession(mContext, "TEST_MEDIA_SESSION");
+ NotificationEntryBuilder builder = new NotificationEntryBuilder();
+ builder.modifyNotification(mContext).setStyle(
+ new MediaStyle().setMediaSession(mMediaSession.getSessionToken()));
+ mMediaEntry = builder.build();
+
when(mMockPackageManager.checkUidPermission(
eq(Manifest.permission.NOTIFICATION_DURING_SETUP),
eq(UID_NORMAL)))
@@ -107,7 +123,12 @@ public class NotificationFilterTest extends SysuiTestCase {
mDependency,
TestableLooper.get(this));
mRow = testHelper.createRow();
- mNotificationFilter = new NotificationFilter(mock(StatusBarStateController.class));
+ mNotificationFilter = new NotificationFilter(mStatusBarStateController, mMediaFeatureFlag);
+ }
+
+ @After
+ public void tearDown() {
+ mMediaSession.release();
}
@Test
@@ -218,6 +239,56 @@ public class NotificationFilterTest extends SysuiTestCase {
assertFalse(mNotificationFilter.shouldFilterOut(entry));
}
+ @Test
+ public void shouldFilterOtherNotificationWhenDisabled() {
+ // GIVEN that the media feature is disabled
+ when(mMediaFeatureFlag.getEnabled()).thenReturn(false);
+ NotificationFilter filter = new NotificationFilter(mStatusBarStateController,
+ mMediaFeatureFlag);
+ // WHEN the media filter is asked about an entry
+ NotificationEntry otherEntry = new NotificationEntryBuilder().build();
+ final boolean shouldFilter = filter.shouldFilterOut(otherEntry);
+ // THEN it shouldn't be filtered
+ assertFalse(shouldFilter);
+ }
+
+ @Test
+ public void shouldFilterOtherNotificationWhenEnabled() {
+ // GIVEN that the media feature is enabled
+ when(mMediaFeatureFlag.getEnabled()).thenReturn(true);
+ NotificationFilter filter = new NotificationFilter(mStatusBarStateController,
+ mMediaFeatureFlag);
+ // WHEN the media filter is asked about an entry
+ NotificationEntry otherEntry = new NotificationEntryBuilder().build();
+ final boolean shouldFilter = filter.shouldFilterOut(otherEntry);
+ // THEN it shouldn't be filtered
+ assertFalse(shouldFilter);
+ }
+
+ @Test
+ public void shouldFilterMediaNotificationWhenDisabled() {
+ // GIVEN that the media feature is disabled
+ when(mMediaFeatureFlag.getEnabled()).thenReturn(false);
+ NotificationFilter filter = new NotificationFilter(mStatusBarStateController,
+ mMediaFeatureFlag);
+ // WHEN the media filter is asked about a media entry
+ final boolean shouldFilter = filter.shouldFilterOut(mMediaEntry);
+ // THEN it shouldn't be filtered
+ assertFalse(shouldFilter);
+ }
+
+ @Test
+ public void shouldFilterMediaNotificationWhenEnabled() {
+ // GIVEN that the media feature is enabled
+ when(mMediaFeatureFlag.getEnabled()).thenReturn(true);
+ NotificationFilter filter = new NotificationFilter(mStatusBarStateController,
+ mMediaFeatureFlag);
+ // WHEN the media filter is asked about a media entry
+ final boolean shouldFilter = filter.shouldFilterOut(mMediaEntry);
+ // THEN it should be filtered
+ assertTrue(shouldFilter);
+ }
+
private void initStatusBarNotification(boolean allowDuringSetup) {
Bundle bundle = new Bundle();
bundle.putBoolean(Notification.EXTRA_ALLOW_DURING_SETUP, allowDuringSetup);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/HighPriorityProviderTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/HighPriorityProviderTest.java
index 78e9b336f79a..2b12c22cae39 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/HighPriorityProviderTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/HighPriorityProviderTest.java
@@ -38,6 +38,7 @@ import com.android.systemui.SysuiTestCase;
import com.android.systemui.statusbar.RankingBuilder;
import com.android.systemui.statusbar.notification.collection.provider.HighPriorityProvider;
import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier;
+import com.android.systemui.statusbar.phone.NotificationGroupManager;
import org.junit.Before;
import org.junit.Test;
@@ -45,16 +46,22 @@ import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
+import java.util.ArrayList;
+import java.util.Arrays;
+
@SmallTest
@RunWith(AndroidTestingRunner.class)
public class HighPriorityProviderTest extends SysuiTestCase {
@Mock private PeopleNotificationIdentifier mPeopleNotificationIdentifier;
+ @Mock private NotificationGroupManager mGroupManager;
private HighPriorityProvider mHighPriorityProvider;
@Before
public void setup() {
MockitoAnnotations.initMocks(this);
- mHighPriorityProvider = new HighPriorityProvider(mPeopleNotificationIdentifier);
+ mHighPriorityProvider = new HighPriorityProvider(
+ mPeopleNotificationIdentifier,
+ mGroupManager);
}
@Test
@@ -166,6 +173,22 @@ public class HighPriorityProviderTest extends SysuiTestCase {
}
@Test
+ public void testIsHighPriority_checkChildrenToCalculatePriority() {
+ // GIVEN: a summary with low priority has a highPriorityChild and a lowPriorityChild
+ final NotificationEntry summary = createNotifEntry(false);
+ final NotificationEntry lowPriorityChild = createNotifEntry(false);
+ final NotificationEntry highPriorityChild = createNotifEntry(true);
+ when(mGroupManager.isGroupSummary(summary.getSbn())).thenReturn(true);
+ when(mGroupManager.getChildren(summary.getSbn())).thenReturn(
+ new ArrayList<>(Arrays.asList(lowPriorityChild, highPriorityChild)));
+
+ // THEN the summary is high priority since it has a high priority child
+ assertTrue(mHighPriorityProvider.isHighPriority(summary));
+ }
+
+ // Tests below here are only relevant to the NEW notification pipeline which uses GroupEntry
+
+ @Test
public void testIsHighPriority_summaryUpdated() {
// GIVEN a GroupEntry with a lowPrioritySummary and no children
final GroupEntry parentEntry = new GroupEntry("test_group_key");
@@ -186,7 +209,7 @@ public class HighPriorityProviderTest extends SysuiTestCase {
}
@Test
- public void testIsHighPriority_checkChildrenToCalculatePriority() {
+ public void testIsHighPriority_checkChildrenToCalculatePriorityOf() {
// GIVEN:
// GroupEntry = parentEntry, summary = lowPrioritySummary
// NotificationEntry = lowPriorityChild
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotificationRankingManagerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotificationRankingManagerTest.kt
index 1c47131e2e86..82a7774b4d82 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotificationRankingManagerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotificationRankingManagerTest.kt
@@ -77,7 +77,8 @@ class NotificationRankingManagerTest : SysuiTestCase() {
mock(NotificationEntryManagerLogger::class.java),
sectionsManager,
personNotificationIdentifier,
- HighPriorityProvider(personNotificationIdentifier)
+ HighPriorityProvider(personNotificationIdentifier,
+ mock(NotificationGroupManager::class.java))
)
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/MediaCoordinatorTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/MediaCoordinatorTest.java
new file mode 100644
index 000000000000..c5dc2b4d4f03
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/MediaCoordinatorTest.java
@@ -0,0 +1,126 @@
+/*
+ * 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.statusbar.notification.collection.coordinator;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.app.Notification.MediaStyle;
+import android.media.session.MediaSession;
+import android.testing.AndroidTestingRunner;
+
+import androidx.test.filters.SmallTest;
+
+import com.android.systemui.SysuiTestCase;
+import com.android.systemui.media.MediaFeatureFlag;
+import com.android.systemui.statusbar.notification.collection.NotifPipeline;
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
+import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder;
+import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifFilter;
+
+import org.junit.After;
+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(AndroidTestingRunner.class)
+public final class MediaCoordinatorTest extends SysuiTestCase {
+
+ private MediaSession mMediaSession;
+ private NotificationEntry mOtherEntry;
+ private NotificationEntry mMediaEntry;
+
+ @Mock private NotifPipeline mNotifPipeline;
+ @Mock private MediaFeatureFlag mMediaFeatureFlag;
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+ mOtherEntry = new NotificationEntryBuilder().build();
+ mMediaSession = new MediaSession(mContext, "TEST_MEDIA_SESSION");
+ NotificationEntryBuilder builder = new NotificationEntryBuilder();
+ builder.modifyNotification(mContext).setStyle(
+ new MediaStyle().setMediaSession(mMediaSession.getSessionToken()));
+ mMediaEntry = builder.build();
+ }
+
+ @After
+ public void tearDown() {
+ mMediaSession.release();
+ }
+
+ @Test
+ public void shouldFilterOtherNotificationWhenDisabled() {
+ // GIVEN that the media feature is disabled
+ when(mMediaFeatureFlag.getEnabled()).thenReturn(false);
+ MediaCoordinator coordinator = new MediaCoordinator(mMediaFeatureFlag);
+ // WHEN the media filter is asked about an entry
+ NotifFilter filter = captureFilter(coordinator);
+ final boolean shouldFilter = filter.shouldFilterOut(mOtherEntry, 0);
+ // THEN it shouldn't be filtered
+ assertThat(shouldFilter).isFalse();
+ }
+
+ @Test
+ public void shouldFilterOtherNotificationWhenEnabled() {
+ // GIVEN that the media feature is enabled
+ when(mMediaFeatureFlag.getEnabled()).thenReturn(true);
+ MediaCoordinator coordinator = new MediaCoordinator(mMediaFeatureFlag);
+ // WHEN the media filter is asked about an entry
+ NotifFilter filter = captureFilter(coordinator);
+ final boolean shouldFilter = filter.shouldFilterOut(mOtherEntry, 0);
+ // THEN it shouldn't be filtered
+ assertThat(shouldFilter).isFalse();
+ }
+
+ @Test
+ public void shouldFilterMediaNotificationWhenDisabled() {
+ // GIVEN that the media feature is disabled
+ when(mMediaFeatureFlag.getEnabled()).thenReturn(false);
+ MediaCoordinator coordinator = new MediaCoordinator(mMediaFeatureFlag);
+ // WHEN the media filter is asked about a media entry
+ NotifFilter filter = captureFilter(coordinator);
+ final boolean shouldFilter = filter.shouldFilterOut(mMediaEntry, 0);
+ // THEN it shouldn't be filtered
+ assertThat(shouldFilter).isFalse();
+ }
+
+ @Test
+ public void shouldFilterMediaNotificationWhenEnabled() {
+ // GIVEN that the media feature is enabled
+ when(mMediaFeatureFlag.getEnabled()).thenReturn(true);
+ MediaCoordinator coordinator = new MediaCoordinator(mMediaFeatureFlag);
+ // WHEN the media filter is asked about a media entry
+ NotifFilter filter = captureFilter(coordinator);
+ final boolean shouldFilter = filter.shouldFilterOut(mMediaEntry, 0);
+ // THEN it should be filtered
+ assertThat(shouldFilter).isTrue();
+ }
+
+ private NotifFilter captureFilter(MediaCoordinator coordinator) {
+ ArgumentCaptor<NotifFilter> filterCaptor = ArgumentCaptor.forClass(NotifFilter.class);
+ coordinator.attach(mNotifPipeline);
+ verify(mNotifPipeline).addFinalizeFilter(filterCaptor.capture());
+ return filterCaptor.getValue();
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/AppOpsInfoTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/AppOpsInfoTest.java
index dd5cb585d0aa..ec73a7571969 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/AppOpsInfoTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/AppOpsInfoTest.java
@@ -144,7 +144,7 @@ public class AppOpsInfoTest extends SysuiTestCase {
final View okButton = mAppOpsInfo.findViewById(R.id.ok);
okButton.performClick();
assertEquals(1, latch.getCount());
- verify(mGutsParent, times(1)).closeControls(anyInt(), anyInt(), anyBoolean(), anyBoolean());
+ verify(mGutsParent, times(1)).closeControls(eq(okButton), anyBoolean());
}
@Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationContentViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationContentViewTest.java
index b018b59e4389..ed4f8b330e23 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationContentViewTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationContentViewTest.java
@@ -16,7 +16,6 @@
package com.android.systemui.statusbar.notification.row;
-import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyFloat;
import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.doReturn;
@@ -30,11 +29,13 @@ import android.app.AppOpsManager;
import android.util.ArraySet;
import android.view.NotificationHeaderView;
import android.view.View;
+import android.view.ViewPropertyAnimator;
import androidx.test.annotation.UiThreadTest;
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
+import com.android.internal.widget.NotificationExpandButton;
import com.android.systemui.SysuiTestCase;
import org.junit.Before;
@@ -98,4 +99,42 @@ public class NotificationContentViewTest extends SysuiTestCase {
verify(mockExpanded, times(1)).setVisibility(View.VISIBLE);
verify(mockHeadsUp, times(1)).setVisibility(View.VISIBLE);
}
+
+ @Test
+ @UiThreadTest
+ public void testExpandButtonFocusIsCalled() {
+ View mockContractedEB = mock(NotificationExpandButton.class);
+ View mockContracted = mock(NotificationHeaderView.class);
+ when(mockContracted.animate()).thenReturn(mock(ViewPropertyAnimator.class));
+ when(mockContracted.findViewById(com.android.internal.R.id.expand_button)).thenReturn(
+ mockContractedEB);
+
+ View mockExpandedEB = mock(NotificationExpandButton.class);
+ View mockExpanded = mock(NotificationHeaderView.class);
+ when(mockExpanded.animate()).thenReturn(mock(ViewPropertyAnimator.class));
+ when(mockExpanded.findViewById(com.android.internal.R.id.expand_button)).thenReturn(
+ mockExpandedEB);
+
+ View mockHeadsUpEB = mock(NotificationExpandButton.class);
+ View mockHeadsUp = mock(NotificationHeaderView.class);
+ when(mockHeadsUp.animate()).thenReturn(mock(ViewPropertyAnimator.class));
+ when(mockHeadsUp.findViewById(com.android.internal.R.id.expand_button)).thenReturn(
+ mockHeadsUpEB);
+
+ // Set up all 3 child forms
+ mView.setContractedChild(mockContracted);
+ mView.setExpandedChild(mockExpanded);
+ mView.setHeadsUpChild(mockHeadsUp);
+
+ // This is required to call requestAccessibilityFocus()
+ mView.setFocusOnVisibilityChange();
+
+ // The following will initialize the view and switch from not visible to expanded.
+ // (heads-up is actually an alternate form of contracted, hence this enters expanded state)
+ mView.setHeadsUp(true);
+
+ verify(mockContractedEB, times(0)).requestAccessibilityFocus();
+ verify(mockExpandedEB, times(1)).requestAccessibilityFocus();
+ verify(mockHeadsUpEB, times(0)).requestAccessibilityFocus();
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationConversationInfoTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationConversationInfoTest.java
index 0272028e62fc..4122cf5466e2 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationConversationInfoTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationConversationInfoTest.java
@@ -173,7 +173,7 @@ public class NotificationConversationInfoTest extends SysuiTestCase {
doAnswer((Answer<Object>) invocation -> {
mNotificationInfo.handleCloseControls(true, false);
return null;
- }).when(mNotificationGuts).closeControls(anyInt(), anyInt(), eq(true), eq(false));
+ }).when(mNotificationGuts).closeControls(any(View.class), eq(true));
// Our view is never attached to a window so the View#post methods in NotificationInfo never
// get called. Setting this will skip the post and do the action immediately.
mNotificationInfo.mSkipPost = true;
@@ -256,7 +256,7 @@ public class NotificationConversationInfoTest extends SysuiTestCase {
mBuilderProvider,
true,
mTestHandler,
- mTestHandler);
+ mTestHandler, null);
final ImageView view = mNotificationInfo.findViewById(R.id.conversation_icon);
assertEquals(mIconDrawable, view.getDrawable());
}
@@ -280,7 +280,7 @@ public class NotificationConversationInfoTest extends SysuiTestCase {
mBuilderProvider,
true,
mTestHandler,
- mTestHandler);
+ mTestHandler, null);
final TextView textView = mNotificationInfo.findViewById(R.id.pkg_name);
assertTrue(textView.getText().toString().contains("App Name"));
assertEquals(VISIBLE, mNotificationInfo.findViewById(R.id.header).getVisibility());
@@ -331,12 +331,11 @@ public class NotificationConversationInfoTest extends SysuiTestCase {
mBuilderProvider,
true,
mTestHandler,
- mTestHandler);
+ mTestHandler, null);
final TextView textView = mNotificationInfo.findViewById(R.id.group_name);
assertTrue(textView.getText().toString().contains(group.getName()));
assertEquals(VISIBLE, mNotificationInfo.findViewById(R.id.header).getVisibility());
assertEquals(VISIBLE, textView.getVisibility());
- assertEquals(VISIBLE, mNotificationInfo.findViewById(R.id.group_divider).getVisibility());
}
@Test
@@ -357,11 +356,10 @@ public class NotificationConversationInfoTest extends SysuiTestCase {
mBuilderProvider,
true,
mTestHandler,
- mTestHandler);
+ mTestHandler, null);
final TextView textView = mNotificationInfo.findViewById(R.id.group_name);
assertEquals(VISIBLE, mNotificationInfo.findViewById(R.id.header).getVisibility());
assertEquals(GONE, textView.getVisibility());
- assertEquals(GONE, mNotificationInfo.findViewById(R.id.group_divider).getVisibility());
}
@Test
@@ -382,7 +380,7 @@ public class NotificationConversationInfoTest extends SysuiTestCase {
mBuilderProvider,
true,
mTestHandler,
- mTestHandler);
+ mTestHandler, null);
final TextView nameView = mNotificationInfo.findViewById(R.id.delegate_name);
assertEquals(GONE, nameView.getVisibility());
}
@@ -417,7 +415,7 @@ public class NotificationConversationInfoTest extends SysuiTestCase {
mBuilderProvider,
true,
mTestHandler,
- mTestHandler);
+ mTestHandler, null);
final TextView nameView = mNotificationInfo.findViewById(R.id.delegate_name);
assertEquals(VISIBLE, nameView.getVisibility());
assertTrue(nameView.getText().toString().contains("Proxied"));
@@ -445,7 +443,7 @@ public class NotificationConversationInfoTest extends SysuiTestCase {
mBuilderProvider,
true,
mTestHandler,
- mTestHandler);
+ mTestHandler, null);
final View settingsButton = mNotificationInfo.findViewById(R.id.info);
settingsButton.performClick();
@@ -471,7 +469,7 @@ public class NotificationConversationInfoTest extends SysuiTestCase {
mBuilderProvider,
true,
mTestHandler,
- mTestHandler);
+ mTestHandler, null);
final View settingsButton = mNotificationInfo.findViewById(R.id.info);
assertTrue(settingsButton.getVisibility() != View.VISIBLE);
}
@@ -498,7 +496,7 @@ public class NotificationConversationInfoTest extends SysuiTestCase {
mBuilderProvider,
false,
mTestHandler,
- mTestHandler);
+ mTestHandler, null);
final View settingsButton = mNotificationInfo.findViewById(R.id.info);
assertTrue(settingsButton.getVisibility() != View.VISIBLE);
}
@@ -523,7 +521,7 @@ public class NotificationConversationInfoTest extends SysuiTestCase {
mBuilderProvider,
true,
mTestHandler,
- mTestHandler);
+ mTestHandler, null);
View view = mNotificationInfo.findViewById(R.id.silence);
assertThat(view.isSelected()).isTrue();
}
@@ -551,7 +549,7 @@ public class NotificationConversationInfoTest extends SysuiTestCase {
mBuilderProvider,
true,
mTestHandler,
- mTestHandler);
+ mTestHandler, null);
View view = mNotificationInfo.findViewById(R.id.default_behavior);
assertThat(view.isSelected()).isTrue();
assertThat(((TextView) view.findViewById(R.id.default_summary)).getText()).isEqualTo(
@@ -582,7 +580,7 @@ public class NotificationConversationInfoTest extends SysuiTestCase {
mBuilderProvider,
true,
mTestHandler,
- mTestHandler);
+ mTestHandler, null);
View view = mNotificationInfo.findViewById(R.id.default_behavior);
assertThat(view.isSelected()).isTrue();
assertThat(((TextView) view.findViewById(R.id.default_summary)).getText()).isEqualTo(
@@ -612,7 +610,7 @@ public class NotificationConversationInfoTest extends SysuiTestCase {
mBuilderProvider,
true,
mTestHandler,
- mTestHandler);
+ mTestHandler, null);
View fave = mNotificationInfo.findViewById(R.id.priority);
fave.performClick();
@@ -656,7 +654,7 @@ public class NotificationConversationInfoTest extends SysuiTestCase {
mBuilderProvider,
true,
mTestHandler,
- mTestHandler);
+ mTestHandler, null);
mNotificationInfo.findViewById(R.id.default_behavior).performClick();
mTestableLooper.processAllMessages();
@@ -699,7 +697,7 @@ public class NotificationConversationInfoTest extends SysuiTestCase {
mBuilderProvider,
true,
mTestHandler,
- mTestHandler);
+ mTestHandler, null);
View silence = mNotificationInfo.findViewById(R.id.silence);
@@ -743,7 +741,7 @@ public class NotificationConversationInfoTest extends SysuiTestCase {
mBuilderProvider,
true,
mTestHandler,
- mTestHandler);
+ mTestHandler, null);
View fave = mNotificationInfo.findViewById(R.id.priority);
fave.performClick();
@@ -780,7 +778,7 @@ public class NotificationConversationInfoTest extends SysuiTestCase {
mBuilderProvider,
true,
mTestHandler,
- mTestHandler);
+ mTestHandler, null);
View fave = mNotificationInfo.findViewById(R.id.priority);
fave.performClick();
@@ -795,6 +793,45 @@ public class NotificationConversationInfoTest extends SysuiTestCase {
}
@Test
+ public void testFavorite_thenDefaultThenFavorite_andSave_nothingChanged() throws Exception {
+ mConversationChannel.setOriginalImportance(IMPORTANCE_HIGH);
+ mConversationChannel.setImportance(IMPORTANCE_HIGH);
+ mConversationChannel.setImportantConversation(true);
+
+ mNotificationInfo.bindNotification(
+ mShortcutManager,
+ mMockPackageManager,
+ mMockINotificationManager,
+ mVisualStabilityManager,
+ TEST_PACKAGE_NAME,
+ mNotificationChannel,
+ mEntry,
+ mBubbleMetadata,
+ null,
+ null,
+ mIconFactory,
+ mContext,
+ mBuilderProvider,
+ true,
+ mTestHandler,
+ mTestHandler, null);
+
+ View fave = mNotificationInfo.findViewById(R.id.priority);
+ fave.performClick();
+ mNotificationInfo.findViewById(R.id.default_behavior).performClick();
+ fave.performClick();
+ mNotificationInfo.findViewById(R.id.done).performClick();
+ mTestableLooper.processAllMessages();
+
+ ArgumentCaptor<NotificationChannel> captor =
+ ArgumentCaptor.forClass(NotificationChannel.class);
+ verify(mMockINotificationManager, times(1)).updateNotificationChannelForPackage(
+ anyString(), anyInt(), captor.capture());
+ assertEquals(IMPORTANCE_HIGH, captor.getValue().getImportance());
+ assertTrue(captor.getValue().isImportantConversation());
+ }
+
+ @Test
public void testDefault_andSave() throws Exception {
mConversationChannel.setAllowBubbles(true);
mConversationChannel.setOriginalImportance(IMPORTANCE_HIGH);
@@ -815,7 +852,7 @@ public class NotificationConversationInfoTest extends SysuiTestCase {
mBuilderProvider,
true,
mTestHandler,
- mTestHandler);
+ mTestHandler, null);
mNotificationInfo.findViewById(R.id.default_behavior).performClick();
mNotificationInfo.findViewById(R.id.done).performClick();
@@ -851,7 +888,7 @@ public class NotificationConversationInfoTest extends SysuiTestCase {
mBuilderProvider,
true,
mTestHandler,
- mTestHandler);
+ mTestHandler, null);
mNotificationInfo.findViewById(R.id.default_behavior).performClick();
mNotificationInfo.findViewById(R.id.done).performClick();
@@ -887,7 +924,7 @@ public class NotificationConversationInfoTest extends SysuiTestCase {
mBuilderProvider,
true,
mTestHandler,
- mTestHandler);
+ mTestHandler, null);
mNotificationInfo.findViewById(R.id.default_behavior).performClick();
mNotificationInfo.findViewById(R.id.done).performClick();
@@ -922,7 +959,7 @@ public class NotificationConversationInfoTest extends SysuiTestCase {
mBuilderProvider,
true,
mTestHandler,
- mTestHandler);
+ mTestHandler, null);
View silence = mNotificationInfo.findViewById(R.id.silence);
silence.performClick();
@@ -956,7 +993,7 @@ public class NotificationConversationInfoTest extends SysuiTestCase {
mBuilderProvider,
true,
mTestHandler,
- mTestHandler);
+ mTestHandler, null);
verify(mMockINotificationManager, times(1)).createConversationNotificationChannelForPackage(
anyString(), anyInt(), anyString(), any(), eq(CONVERSATION_ID));
@@ -981,7 +1018,7 @@ public class NotificationConversationInfoTest extends SysuiTestCase {
mBuilderProvider,
true,
mTestHandler,
- mTestHandler);
+ mTestHandler, null);
verify(mMockINotificationManager, never()).createConversationNotificationChannelForPackage(
anyString(), anyInt(), anyString(), any(), eq(CONVERSATION_ID));
@@ -1016,10 +1053,14 @@ public class NotificationConversationInfoTest extends SysuiTestCase {
() -> b,
true,
mTestHandler,
- mTestHandler);
+ mTestHandler, null);
// WHEN user clicks "priority"
mNotificationInfo.setSelectedAction(NotificationConversationInfo.ACTION_FAVORITE);
+ verify(controller, never()).show();
+
+ // and then done
+ mNotificationInfo.findViewById(R.id.done).performClick();
// THEN the user is presented with the priority onboarding screen
verify(controller, atLeastOnce()).show();
@@ -1052,7 +1093,7 @@ public class NotificationConversationInfoTest extends SysuiTestCase {
() -> b,
true,
mTestHandler,
- mTestHandler);
+ mTestHandler, null);
// WHEN user clicks "priority"
mNotificationInfo.setSelectedAction(NotificationConversationInfo.ACTION_FAVORITE);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationInfoTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationInfoTest.java
index 8ee86a237e32..6bf60721cd8e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationInfoTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationInfoTest.java
@@ -236,8 +236,6 @@ public class NotificationInfoTest extends SysuiTestCase {
true);
final TextView nameView = mNotificationInfo.findViewById(R.id.delegate_name);
assertEquals(GONE, nameView.getVisibility());
- final TextView dividerView = mNotificationInfo.findViewById(R.id.group_divider);
- assertEquals(GONE, dividerView.getVisibility());
}
@Test
@@ -288,8 +286,6 @@ public class NotificationInfoTest extends SysuiTestCase {
true);
final TextView groupNameView = mNotificationInfo.findViewById(R.id.group_name);
assertEquals(GONE, groupNameView.getVisibility());
- final TextView dividerView = mNotificationInfo.findViewById(R.id.group_divider);
- assertEquals(GONE, dividerView.getVisibility());
}
@Test
@@ -317,8 +313,6 @@ public class NotificationInfoTest extends SysuiTestCase {
final TextView groupNameView = mNotificationInfo.findViewById(R.id.group_name);
assertEquals(View.VISIBLE, groupNameView.getVisibility());
assertEquals("Test Group Name", groupNameView.getText());
- final TextView dividerView = mNotificationInfo.findViewById(R.id.group_divider);
- assertEquals(View.VISIBLE, dividerView.getVisibility());
}
@Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/PartialConversationInfoTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/PartialConversationInfoTest.java
index 545b59a4556a..43aa8fef76a9 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/PartialConversationInfoTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/PartialConversationInfoTest.java
@@ -25,6 +25,7 @@ import static android.view.View.VISIBLE;
import static junit.framework.Assert.assertEquals;
import static junit.framework.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.anyObject;
import static org.mockito.Mockito.any;
import static org.mockito.Mockito.anyBoolean;
import static org.mockito.Mockito.anyInt;
@@ -161,26 +162,8 @@ public class PartialConversationInfoTest extends SysuiTestCase {
}
@Test
- public void testBindNotification_SetsTextApplicationName() throws Exception {
- when(mMockPackageManager.getApplicationLabel(any())).thenReturn("App Name");
- mInfo.bindNotification(
- mMockPackageManager,
- mMockINotificationManager,
- mChannelEditorDialogController,
- TEST_PACKAGE_NAME,
- mNotificationChannel,
- mNotificationChannelSet,
- mEntry,
- null,
- true,
- false);
- final TextView textView = mInfo.findViewById(R.id.pkg_name);
- assertTrue(textView.getText().toString().contains("App Name"));
- assertEquals(VISIBLE, mInfo.findViewById(R.id.header).getVisibility());
- }
-
- @Test
public void testBindNotification_SetsName() {
+ when(mMockPackageManager.getApplicationLabel(any())).thenReturn("Package");
mInfo.bindNotification(
mMockPackageManager,
mMockINotificationManager,
@@ -193,42 +176,13 @@ public class PartialConversationInfoTest extends SysuiTestCase {
true,
false);
final TextView textView = mInfo.findViewById(R.id.name);
- assertTrue(textView.getText().toString().contains("title"));
+ assertTrue(textView.getText().toString().equals("Package"));
}
- @Test
- public void testBindNotification_groupSetsPackageIcon() {
- mEntry.getSbn().getNotification().extras.putBoolean(EXTRA_IS_GROUP_CONVERSATION, true);
- final Drawable iconDrawable = mock(Drawable.class);
- when(mMockPackageManager.getApplicationIcon(any(ApplicationInfo.class)))
- .thenReturn(iconDrawable);
- mInfo.bindNotification(
- mMockPackageManager,
- mMockINotificationManager,
- mChannelEditorDialogController,
- TEST_PACKAGE_NAME,
- mNotificationChannel,
- mNotificationChannelSet,
- mEntry,
- null,
- true,
- false);
- final ImageView iconView = mInfo.findViewById(R.id.conversation_icon);
- assertEquals(iconDrawable, iconView.getDrawable());
- }
@Test
- public void testBindNotification_notGroupSetsMessageIcon() {
- Notification n = new Notification.Builder(mContext, TEST_CHANNEL_NAME)
- .setStyle(new Notification.MessagingStyle(
- new Person.Builder().setName("me").build())
- .addMessage(new Notification.MessagingStyle.Message("hello", 0,
- new Person.Builder().setName("friend").setIcon(mIcon).build())))
- .build();
- mSbn = new StatusBarNotification(TEST_PACKAGE_NAME, TEST_PACKAGE_NAME, 0, null, TEST_UID, 0,
- n, UserHandle.CURRENT, null, 0);
- mEntry.setSbn(mSbn);
- mEntry.getSbn().getNotification().extras.putBoolean(EXTRA_IS_GROUP_CONVERSATION, false);
+ public void testBindNotification_setsIcon() {
+ when(mMockPackageManager.getApplicationIcon((ApplicationInfo) any())).thenReturn(mDrawable);
mInfo.bindNotification(
mMockPackageManager,
mMockINotificationManager,
@@ -240,7 +194,7 @@ public class PartialConversationInfoTest extends SysuiTestCase {
null,
true,
false);
- final ImageView iconView = mInfo.findViewById(R.id.conversation_icon);
+ final ImageView iconView = mInfo.findViewById(R.id.icon);
assertEquals(mDrawable.hashCode() + "", mDrawable, iconView.getDrawable());
}
@@ -259,8 +213,6 @@ public class PartialConversationInfoTest extends SysuiTestCase {
false);
final TextView nameView = mInfo.findViewById(R.id.delegate_name);
assertEquals(GONE, nameView.getVisibility());
- final TextView dividerView = mInfo.findViewById(R.id.group_divider);
- assertEquals(GONE, dividerView.getVisibility());
}
@Test
@@ -291,68 +243,6 @@ public class PartialConversationInfoTest extends SysuiTestCase {
}
@Test
- public void testBindNotification_GroupNameHiddenIfNoGroup() throws Exception {
- mInfo.bindNotification(
- mMockPackageManager,
- mMockINotificationManager,
- mChannelEditorDialogController,
- TEST_PACKAGE_NAME,
- mNotificationChannel,
- mNotificationChannelSet,
- mEntry,
- null,
- true,
- false);
- final TextView groupNameView = mInfo.findViewById(R.id.group_name);
- assertEquals(GONE, groupNameView.getVisibility());
- final TextView dividerView = mInfo.findViewById(R.id.group_divider);
- assertEquals(GONE, dividerView.getVisibility());
- }
-
- @Test
- public void testBindNotification_SetsGroupNameIfNonNull() throws Exception {
- mNotificationChannel.setGroup("test_group_id");
- final NotificationChannelGroup notificationChannelGroup =
- new NotificationChannelGroup("test_group_id", "Test Group Name");
- when(mMockINotificationManager.getNotificationChannelGroupForPackage(
- eq("test_group_id"), eq(TEST_PACKAGE_NAME), eq(TEST_UID)))
- .thenReturn(notificationChannelGroup);
- mInfo.bindNotification(
- mMockPackageManager,
- mMockINotificationManager,
- mChannelEditorDialogController,
- TEST_PACKAGE_NAME,
- mNotificationChannel,
- mNotificationChannelSet,
- mEntry,
- null,
- true,
- false);
- final TextView groupNameView = mInfo.findViewById(R.id.group_name);
- assertEquals(View.VISIBLE, groupNameView.getVisibility());
- assertEquals("Test Group Name", groupNameView.getText());
- final TextView dividerView = mInfo.findViewById(R.id.group_divider);
- assertEquals(View.VISIBLE, dividerView.getVisibility());
- }
-
- @Test
- public void testBindNotification_SetsTextChannelName() {
- mInfo.bindNotification(
- mMockPackageManager,
- mMockINotificationManager,
- mChannelEditorDialogController,
- TEST_PACKAGE_NAME,
- mNotificationChannel,
- mNotificationChannelSet,
- mEntry,
- null,
- true,
- false);
- final TextView textView = mInfo.findViewById(R.id.parent_channel_name);
- assertEquals(TEST_CHANNEL_NAME, textView.getText());
- }
-
- @Test
public void testBindNotification_SetsOnClickListenerForSettings() {
final CountDownLatch latch = new CountDownLatch(1);
mInfo.bindNotification(
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManagerTest.java
index 3dc941a0bd20..c55391a387d8 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManagerTest.java
@@ -403,11 +403,11 @@ public class NotificationSectionsManagerTest extends SysuiTestCase {
enablePeopleFiltering();
setupMockStack(
- PERSON.headsUp(),
- INCOMING_HEADER,
- ALERTING.headsUp(),
- PEOPLE_HEADER,
- PERSON
+ PERSON.headsUp(), // personHeaderTarget = 0
+ INCOMING_HEADER, // currentIncomingHeaderIdx = 1
+ ALERTING.headsUp(), // alertingHeaderTarget = 1
+ PEOPLE_HEADER, // currentPeopleHeaderIdx = 3
+ PERSON //
);
mSectionsManager.updateSectionBoundaries();
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/AutoTileManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/AutoTileManagerTest.java
index 1a6921a1d136..05cdd802167a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/AutoTileManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/AutoTileManagerTest.java
@@ -172,11 +172,12 @@ public class AutoTileManagerTest extends SysuiTestCase {
}
@Test
- public void testSettingTileAddedComponent_onChanged() {
+ public void testSettingTileAddedComponentAtEnd_onChanged() {
changeValue(TEST_SETTING_COMPONENT, 1);
waitForIdleSync();
verify(mAutoAddTracker).setTileAdded(TEST_CUSTOM_SPEC);
- verify(mQsTileHost).addTile(ComponentName.unflattenFromString(TEST_COMPONENT));
+ verify(mQsTileHost).addTile(ComponentName.unflattenFromString(TEST_COMPONENT)
+ , /* end */ true);
}
@Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NavigationBarFragmentTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NavigationBarFragmentTest.java
index a77f8c649f30..00cbddc87726 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NavigationBarFragmentTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NavigationBarFragmentTest.java
@@ -21,6 +21,8 @@ import static android.inputmethodservice.InputMethodService.IME_VISIBLE;
import static android.view.Display.DEFAULT_DISPLAY;
import static android.view.DisplayAdjustments.DEFAULT_DISPLAY_ADJUSTMENTS;
+import static com.android.systemui.statusbar.phone.NavigationBarFragment.NavBarActionEvent.NAVBAR_ASSIST_LONGPRESS;
+
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
@@ -28,6 +30,7 @@ import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@@ -59,6 +62,7 @@ import android.view.accessibility.AccessibilityManager.AccessibilityServicesStat
import androidx.test.filters.SmallTest;
import com.android.internal.logging.MetricsLogger;
+import com.android.internal.logging.UiEventLogger;
import com.android.systemui.Dependency;
import com.android.systemui.SysuiBaseFragmentTest;
import com.android.systemui.SysuiTestableContext;
@@ -105,6 +109,8 @@ public class NavigationBarFragmentTest extends SysuiBaseFragmentTest {
private Recents mRecents;
@Mock
private SystemActions mSystemActions;
+ @Mock
+ private UiEventLogger mUiEventLogger;
private AccessibilityManagerWrapper mAccessibilityWrapper =
new AccessibilityManagerWrapper(mContext) {
@@ -187,6 +193,8 @@ public class NavigationBarFragmentTest extends SysuiBaseFragmentTest {
mFragments.dispatchResume();
processAllMessages();
navigationBarFragment.onHomeLongClick(navigationBarFragment.getView());
+
+ verify(mUiEventLogger, times(1)).log(NAVBAR_ASSIST_LONGPRESS);
}
@Test
@@ -242,6 +250,7 @@ public class NavigationBarFragmentTest extends SysuiBaseFragmentTest {
protected Fragment instantiate(Context context, String className, Bundle arguments) {
DeviceProvisionedController deviceProvisionedController =
mock(DeviceProvisionedController.class);
+ when(deviceProvisionedController.isDeviceProvisioned()).thenReturn(true);
assertNotNull(mAccessibilityWrapper);
return new NavigationBarFragment(
context.getDisplayId() == DEFAULT_DISPLAY ? mAccessibilityWrapper
@@ -261,7 +270,8 @@ public class NavigationBarFragmentTest extends SysuiBaseFragmentTest {
mock(ShadeController.class),
mock(NotificationRemoteInputManager.class),
mock(SystemActions.class),
- mHandler);
+ mHandler,
+ mUiEventLogger);
}
private class HostCallbacksForExternalDisplay extends
@@ -319,6 +329,7 @@ public class NavigationBarFragmentTest extends SysuiBaseFragmentTest {
mock(LightBarTransitionsController.class));
when(view.getRotationButtonController()).thenReturn(
mock(RotationButtonController.class));
+ when(view.isRecentsButtonVisible()).thenReturn(true);
return view;
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationIconAreaControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationIconAreaControllerTest.java
index be43e19cfc70..d1a439f99702 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationIconAreaControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationIconAreaControllerTest.java
@@ -19,6 +19,7 @@ import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.testing.AndroidTestingRunner;
@@ -27,6 +28,7 @@ import android.testing.TestableLooper;
import androidx.test.filters.SmallTest;
import com.android.systemui.SysuiTestCase;
+import com.android.systemui.bubbles.BubbleController;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.statusbar.NotificationListener;
import com.android.systemui.statusbar.NotificationMediaManager;
@@ -56,10 +58,14 @@ public class NotificationIconAreaControllerTest extends SysuiTestCase {
@Mock
NotificationMediaManager mNotificationMediaManager;
@Mock
+ NotificationIconContainer mNotificationIconContainer;
+ @Mock
DozeParameters mDozeParameters;
@Mock
NotificationShadeWindowView mNotificationShadeWindowView;
private NotificationIconAreaController mController;
+ @Mock
+ private BubbleController mBubbleController;
@Before
public void setup() {
@@ -67,11 +73,11 @@ public class NotificationIconAreaControllerTest extends SysuiTestCase {
when(mStatusBar.getNotificationShadeWindowView()).thenReturn(mNotificationShadeWindowView);
when(mNotificationShadeWindowView.findViewById(anyInt())).thenReturn(
- mock(NotificationIconContainer.class));
+ mNotificationIconContainer);
mController = new NotificationIconAreaController(mContext, mStatusBar,
mStatusBarStateController, mWakeUpCoordinator, mKeyguardBypassController,
- mNotificationMediaManager, mListener, mDozeParameters);
+ mNotificationMediaManager, mListener, mDozeParameters, mBubbleController);
}
@Test
@@ -87,4 +93,12 @@ public class NotificationIconAreaControllerTest extends SysuiTestCase {
assertTrue(mController.shouldShouldLowPriorityIcons());
}
+
+ @Test
+ public void testAppearResetsTranslation() {
+ when(mDozeParameters.shouldControlScreenOff()).thenReturn(false);
+ mController.appearAodIcons();
+ verify(mNotificationIconContainer).setTranslationY(0);
+ verify(mNotificationIconContainer).setAlpha(1.0f);
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/KeyButtonViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/KeyButtonViewTest.java
index 943674a7bf64..d52d6860bf42 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/KeyButtonViewTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/KeyButtonViewTest.java
@@ -14,21 +14,33 @@
package com.android.systemui.statusbar.policy;
-import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.ACTION_NAV_BUTTON_EVENT;
-import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.FIELD_FLAGS;
-import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.FIELD_NAV_ACTION;
+import static android.view.KeyEvent.ACTION_DOWN;
+import static android.view.KeyEvent.ACTION_UP;
+import static android.view.KeyEvent.FLAG_CANCELED;
+import static android.view.KeyEvent.FLAG_LONG_PRESS;
+import static android.view.KeyEvent.KEYCODE_0;
+import static android.view.KeyEvent.KEYCODE_APP_SWITCH;
+import static android.view.KeyEvent.KEYCODE_BACK;
+import static android.view.KeyEvent.KEYCODE_HOME;
+
+import static com.android.systemui.statusbar.policy.KeyButtonView.NavBarButtonEvent.NAVBAR_BACK_BUTTON_LONGPRESS;
+import static com.android.systemui.statusbar.policy.KeyButtonView.NavBarButtonEvent.NAVBAR_BACK_BUTTON_TAP;
+import static com.android.systemui.statusbar.policy.KeyButtonView.NavBarButtonEvent.NAVBAR_HOME_BUTTON_LONGPRESS;
+import static com.android.systemui.statusbar.policy.KeyButtonView.NavBarButtonEvent.NAVBAR_HOME_BUTTON_TAP;
+import static com.android.systemui.statusbar.policy.KeyButtonView.NavBarButtonEvent.NAVBAR_OVERVIEW_BUTTON_LONGPRESS;
+import static com.android.systemui.statusbar.policy.KeyButtonView.NavBarButtonEvent.NAVBAR_OVERVIEW_BUTTON_TAP;
import static junit.framework.Assert.assertEquals;
+import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
-import static org.mockito.ArgumentMatchers.argThat;
import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.hardware.input.InputManager;
-import android.metrics.LogMaker;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
import android.testing.TestableLooper.RunWithLooper;
@@ -37,7 +49,7 @@ import android.view.KeyEvent;
import androidx.test.filters.SmallTest;
import com.android.internal.logging.MetricsLogger;
-import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
+import com.android.internal.logging.UiEventLogger;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.bubbles.BubbleController;
import com.android.systemui.recents.OverviewProxyService;
@@ -46,12 +58,9 @@ import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
-import org.mockito.ArgumentMatcher;
import org.mockito.Captor;
import org.mockito.MockitoAnnotations;
-import java.util.Objects;
-
@RunWith(AndroidTestingRunner.class)
@RunWithLooper
@SmallTest
@@ -60,6 +69,7 @@ public class KeyButtonViewTest extends SysuiTestCase {
private KeyButtonView mKeyButtonView;
private MetricsLogger mMetricsLogger;
private BubbleController mBubbleController;
+ private UiEventLogger mUiEventLogger;
private InputManager mInputManager = mock(InputManager.class);
@Captor
private ArgumentCaptor<KeyEvent> mInputEventCaptor;
@@ -70,45 +80,74 @@ public class KeyButtonViewTest extends SysuiTestCase {
mMetricsLogger = mDependency.injectMockDependency(MetricsLogger.class);
mBubbleController = mDependency.injectMockDependency(BubbleController.class);
mDependency.injectMockDependency(OverviewProxyService.class);
+ mUiEventLogger = mDependency.injectMockDependency(UiEventLogger.class);
+
TestableLooper.get(this).runWithLooper(() -> {
- mKeyButtonView = new KeyButtonView(mContext, null, 0, mInputManager);
+ mKeyButtonView = new KeyButtonView(mContext, null, 0, mInputManager, mUiEventLogger);
});
}
@Test
- public void testMetrics() {
- int action = 42;
- int flags = 0x141;
- int code = KeyEvent.KEYCODE_ENTER;
- mKeyButtonView.setCode(code);
- mKeyButtonView.sendEvent(action, flags);
+ public void testLogBackPress() {
+ checkmetrics(KEYCODE_BACK, ACTION_UP, 0, NAVBAR_BACK_BUTTON_TAP);
+ }
+
+ @Test
+ public void testLogOverviewPress() {
+ checkmetrics(KEYCODE_APP_SWITCH, ACTION_UP, 0, NAVBAR_OVERVIEW_BUTTON_TAP);
+ }
+
+ @Test
+ public void testLogHomePress() {
+ checkmetrics(KEYCODE_HOME, ACTION_UP, 0, NAVBAR_HOME_BUTTON_TAP);
+ }
+
+ @Test
+ public void testLogBackLongPressLog() {
+ checkmetrics(KEYCODE_BACK, ACTION_DOWN, FLAG_LONG_PRESS, NAVBAR_BACK_BUTTON_LONGPRESS);
+ }
+
+ @Test
+ public void testLogOverviewLongPress() {
+ checkmetrics(KEYCODE_APP_SWITCH, ACTION_DOWN, FLAG_LONG_PRESS,
+ NAVBAR_OVERVIEW_BUTTON_LONGPRESS);
+ }
- verify(mMetricsLogger).write(argThat(new ArgumentMatcher<LogMaker>() {
- public String mReason;
-
- @Override
- public boolean matches(LogMaker argument) {
- return checkField("category", argument.getCategory(), ACTION_NAV_BUTTON_EVENT)
- && checkField("type", argument.getType(), MetricsEvent.TYPE_ACTION)
- && checkField("subtype", argument.getSubtype(), code)
- && checkField("FIELD_FLAGS", argument.getTaggedData(FIELD_FLAGS), flags)
- && checkField("FIELD_NAV_ACTION", argument.getTaggedData(FIELD_NAV_ACTION),
- action);
- }
-
- private boolean checkField(String field, Object val, Object val2) {
- if (!Objects.equals(val, val2)) {
- mReason = "Expected " + field + " " + val2 + " but was " + val;
- return false;
- }
- return true;
- }
-
- @Override
- public String toString() {
- return mReason;
- }
- }));
+ @Test
+ public void testLogHomeLongPress() {
+ checkmetrics(KEYCODE_HOME, ACTION_DOWN, FLAG_LONG_PRESS, NAVBAR_HOME_BUTTON_LONGPRESS);
+ }
+
+ @Test
+ public void testNoLogKeyDown() {
+ checkmetrics(KEYCODE_BACK, ACTION_DOWN, 0, null);
+ }
+
+ @Test
+ public void testNoLogTapAfterLong() {
+ mKeyButtonView.mLongClicked = true;
+ checkmetrics(KEYCODE_BACK, ACTION_UP, 0, null);
+ }
+
+ @Test
+ public void testNoLogCanceled() {
+ checkmetrics(KEYCODE_HOME, ACTION_UP, FLAG_CANCELED, null);
+ }
+
+ @Test
+ public void testNoLogArbitraryKeys() {
+ checkmetrics(KEYCODE_0, ACTION_UP, 0, null);
+ }
+
+ private void checkmetrics(int code, int action, int flag,
+ KeyButtonView.NavBarButtonEvent expected) {
+ mKeyButtonView.setCode(code);
+ mKeyButtonView.sendEvent(action, flag);
+ if (expected == null) {
+ verify(mUiEventLogger, never()).log(any(KeyButtonView.NavBarButtonEvent.class));
+ } else {
+ verify(mUiEventLogger, times(1)).log(expected);
+ }
}
@Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/util/animation/PhysicsAnimatorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/util/animation/PhysicsAnimatorTest.kt
index eb435f9314e7..661fad2d6d5c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/util/animation/PhysicsAnimatorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/util/animation/PhysicsAnimatorTest.kt
@@ -21,6 +21,7 @@ import org.junit.Assert
import org.junit.Assert.assertEquals
import org.junit.Assert.assertFalse
import org.junit.Assert.assertNotEquals
+import org.junit.Assert.assertNotNull
import org.junit.Assert.assertTrue
import org.junit.Before
import org.junit.Ignore
@@ -590,8 +591,10 @@ class PhysicsAnimatorTest : SysuiTestCase() {
updatesForProperty.remove(update)
}
+ val target = animator.weakTarget.get()
+ assertNotNull(target)
// Mark this invocation verified.
- verify(mockUpdateListener).onAnimationUpdateForProperty(animator.target, updateMap)
+ verify(mockUpdateListener).onAnimationUpdateForProperty(target!!, updateMap)
}
verifyNoMoreInteractions(mockUpdateListener)
@@ -604,4 +607,4 @@ class PhysicsAnimatorTest : SysuiTestCase() {
clearAnimationUpdateFrames(animator)
}
-} \ No newline at end of file
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/util/concurrency/FakeRepeatableExecutor.java b/packages/SystemUI/tests/src/com/android/systemui/util/concurrency/FakeRepeatableExecutor.java
new file mode 100644
index 000000000000..477f615faf2b
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/util/concurrency/FakeRepeatableExecutor.java
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.util.concurrency;
+
+/**
+ * A fake to use in tests.
+ */
+public class FakeRepeatableExecutor extends RepeatableExecutorImpl {
+
+ /**
+ * Initializes a fake RepeatableExecutor from a fake executor.
+ *
+ * Use the fake executor to actually process tasks.
+ *
+ * @param executor fake executor.
+ */
+ public FakeRepeatableExecutor(FakeExecutor executor) {
+ super(executor);
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/util/sensors/ProximityCheckTest.java b/packages/SystemUI/tests/src/com/android/systemui/util/sensors/ProximityCheckTest.java
index 7221095a1eaf..dae6b284ff15 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/util/sensors/ProximityCheckTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/util/sensors/ProximityCheckTest.java
@@ -81,6 +81,32 @@ public class ProximityCheckTest extends SysuiTestCase {
assertFalse(mFakeProximitySensor.isRegistered());
}
+ @Test
+ public void testProxDoesntCancelOthers() {
+ assertFalse(mFakeProximitySensor.isRegistered());
+ // We don't need our "other" listener to do anything. Just ensure our sensor is registered.
+ ProximitySensor.ProximitySensorListener emptyListener = event -> { };
+ mFakeProximitySensor.register(emptyListener);
+ assertTrue(mFakeProximitySensor.isRegistered());
+
+ // Now run a basic check. This is just like testCheck()
+ mProximityCheck.check(100, mTestableCallback);
+
+ assertNull(mTestableCallback.mLastResult);
+
+ mFakeProximitySensor.setLastEvent(new ProximitySensor.ProximityEvent(true, 0));
+ mFakeProximitySensor.alertListeners();
+
+ assertTrue(mTestableCallback.mLastResult);
+
+ // We should still be registered, since we have another listener.
+ assertTrue(mFakeProximitySensor.isRegistered());
+
+ mFakeProximitySensor.unregister(emptyListener);
+ assertFalse(mFakeProximitySensor.isRegistered());
+
+ }
+
private static class TestableCallback implements Consumer<Boolean> {
Boolean mLastResult;
@Override
diff --git a/packages/Tethering/Android.bp b/packages/Tethering/Android.bp
index 8ae30a5c6f92..32e2b04e8e4f 100644
--- a/packages/Tethering/Android.bp
+++ b/packages/Tethering/Android.bp
@@ -25,7 +25,7 @@ java_defaults {
],
static_libs: [
"androidx.annotation_annotation",
- "netd_aidl_interface-V3-java",
+ "netd_aidl_interface-java",
"netlink-client",
"networkstack-aidl-interfaces-java",
"android.hardware.tetheroffload.config-V1.0-java",
@@ -34,7 +34,7 @@ java_defaults {
],
libs: [
"framework-tethering.impl",
- "framework-wifi-stubs-systemapi",
+ "framework-wifi",
"unsupportedappusage",
],
plugins: ["java_api_finder"],
diff --git a/packages/Tethering/common/TetheringLib/Android.bp b/packages/Tethering/common/TetheringLib/Android.bp
index 6c05b11258f0..c8becce7be82 100644
--- a/packages/Tethering/common/TetheringLib/Android.bp
+++ b/packages/Tethering/common/TetheringLib/Android.bp
@@ -30,11 +30,6 @@ java_sdk_library {
":framework-tethering-srcs",
],
- // TODO(b/155480189) - Remove naming_scheme once references have been resolved.
- // Temporary java_sdk_library component naming scheme to use to ease the transition from separate
- // modules to java_sdk_library.
- naming_scheme: "framework-modules",
-
jarjar_rules: "jarjar-rules.txt",
installable: true,
diff --git a/packages/Tethering/src/android/net/ip/IpServer.java b/packages/Tethering/src/android/net/ip/IpServer.java
index f08429bb0696..1671dda4bd57 100644
--- a/packages/Tethering/src/android/net/ip/IpServer.java
+++ b/packages/Tethering/src/android/net/ip/IpServer.java
@@ -33,7 +33,6 @@ import android.net.LinkAddress;
import android.net.LinkProperties;
import android.net.MacAddress;
import android.net.RouteInfo;
-import android.net.TetherOffloadRuleParcel;
import android.net.TetheredClient;
import android.net.TetheringManager;
import android.net.TetheringRequestParcel;
@@ -65,6 +64,8 @@ import androidx.annotation.Nullable;
import com.android.internal.util.MessageUtils;
import com.android.internal.util.State;
import com.android.internal.util.StateMachine;
+import com.android.networkstack.tethering.BpfCoordinator;
+import com.android.networkstack.tethering.BpfCoordinator.Ipv6ForwardingRule;
import com.android.networkstack.tethering.PrivateAddressCoordinator;
import java.io.IOException;
@@ -76,7 +77,6 @@ import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
-import java.util.LinkedHashMap;
import java.util.List;
import java.util.Objects;
import java.util.Random;
@@ -225,6 +225,8 @@ public class IpServer extends StateMachine {
private final SharedLog mLog;
private final INetd mNetd;
+ @NonNull
+ private final BpfCoordinator mBpfCoordinator;
private final Callback mCallback;
private final InterfaceController mInterfaceCtrl;
private final PrivateAddressCoordinator mPrivateAddressCoordinator;
@@ -269,43 +271,6 @@ public class IpServer extends StateMachine {
}
}
- static class Ipv6ForwardingRule {
- public final int upstreamIfindex;
- public final int downstreamIfindex;
- public final Inet6Address address;
- public final MacAddress srcMac;
- public final MacAddress dstMac;
-
- Ipv6ForwardingRule(int upstreamIfindex, int downstreamIfIndex, Inet6Address address,
- MacAddress srcMac, MacAddress dstMac) {
- this.upstreamIfindex = upstreamIfindex;
- this.downstreamIfindex = downstreamIfIndex;
- this.address = address;
- this.srcMac = srcMac;
- this.dstMac = dstMac;
- }
-
- public Ipv6ForwardingRule onNewUpstream(int newUpstreamIfindex) {
- return new Ipv6ForwardingRule(newUpstreamIfindex, downstreamIfindex, address, srcMac,
- dstMac);
- }
-
- // Don't manipulate TetherOffloadRuleParcel directly because implementing onNewUpstream()
- // would be error-prone due to generated stable AIDL classes not having a copy constructor.
- public TetherOffloadRuleParcel toTetherOffloadRuleParcel() {
- final TetherOffloadRuleParcel parcel = new TetherOffloadRuleParcel();
- parcel.inputInterfaceIndex = upstreamIfindex;
- parcel.outputInterfaceIndex = downstreamIfindex;
- parcel.destination = address.getAddress();
- parcel.prefixLength = 128;
- parcel.srcL2Address = srcMac.toByteArray();
- parcel.dstL2Address = dstMac.toByteArray();
- return parcel;
- }
- }
- private final LinkedHashMap<Inet6Address, Ipv6ForwardingRule> mIpv6ForwardingRules =
- new LinkedHashMap<>();
-
private final IpNeighborMonitor mIpNeighborMonitor;
private LinkAddress mIpv4Address;
@@ -314,11 +279,13 @@ public class IpServer extends StateMachine {
// object. It helps to reduce the arguments of the constructor.
public IpServer(
String ifaceName, Looper looper, int interfaceType, SharedLog log,
- INetd netd, Callback callback, boolean usingLegacyDhcp, boolean usingBpfOffload,
+ INetd netd, @NonNull BpfCoordinator coordinator, Callback callback,
+ boolean usingLegacyDhcp, boolean usingBpfOffload,
PrivateAddressCoordinator addressCoordinator, Dependencies deps) {
super(ifaceName, looper);
mLog = log.forSubComponent(ifaceName);
mNetd = netd;
+ mBpfCoordinator = coordinator;
mCallback = callback;
mInterfaceCtrl = new InterfaceController(ifaceName, mNetd, mLog);
mIfaceName = ifaceName;
@@ -730,12 +697,7 @@ public class IpServer extends StateMachine {
final String upstreamIface = v6only.getInterfaceName();
params = new RaParams();
- // When BPF offload is enabled, we advertise an mtu lower by 16, which is the closest
- // multiple of 8 >= 14, the ethernet header size. This makes kernel ebpf tethering
- // offload happy. This hack should be reverted once we have the kernel fixed up.
- // Note: this will automatically clamp to at least 1280 (ipv6 minimum mtu)
- // see RouterAdvertisementDaemon.java putMtu()
- params.mtu = mUsingBpfOffload ? v6only.getMtu() - 16 : v6only.getMtu();
+ params.mtu = v6only.getMtu();
params.hasDefaultRoute = v6only.hasIpv6DefaultRoute();
if (params.hasDefaultRoute) params.hopLimit = getHopLimit(upstreamIface, ttlAdjustment);
@@ -754,6 +716,14 @@ public class IpServer extends StateMachine {
}
upstreamIfindex = mDeps.getIfindex(upstreamIface);
+
+ // Add upstream index to name mapping for the tether stats usage in the coordinator.
+ // Although this mapping could be added by both class Tethering and IpServer, adding
+ // mapping from IpServer guarantees that the mapping is added before the adding
+ // forwarding rules. That is because there are different state machines in both
+ // classes. It is hard to guarantee the link property update order between multiple
+ // state machines.
+ mBpfCoordinator.addUpstreamNameToLookupTable(upstreamIfindex, upstreamIface);
}
// If v6only is null, we pass in null to setRaParams(), which handles
@@ -869,43 +839,29 @@ public class IpServer extends StateMachine {
// TODO: Perhaps remove this protection check.
if (!mUsingBpfOffload) return;
- try {
- mNetd.tetherOffloadRuleAdd(rule.toTetherOffloadRuleParcel());
- mIpv6ForwardingRules.put(rule.address, rule);
- } catch (RemoteException | ServiceSpecificException e) {
- mLog.e("Could not add IPv6 downstream rule: ", e);
- }
+ mBpfCoordinator.tetherOffloadRuleAdd(this, rule);
}
- private void removeIpv6ForwardingRule(Ipv6ForwardingRule rule, boolean removeFromMap) {
- // Theoretically, we don't need this check because IP neighbor monitor doesn't start if BPF
- // offload is disabled. Add this check just in case.
+ private void removeIpv6ForwardingRule(Ipv6ForwardingRule rule) {
// TODO: Perhaps remove this protection check.
+ // See the related comment in #addIpv6ForwardingRule.
if (!mUsingBpfOffload) return;
- try {
- mNetd.tetherOffloadRuleRemove(rule.toTetherOffloadRuleParcel());
- if (removeFromMap) {
- mIpv6ForwardingRules.remove(rule.address);
- }
- } catch (RemoteException | ServiceSpecificException e) {
- mLog.e("Could not remove IPv6 downstream rule: ", e);
- }
+ mBpfCoordinator.tetherOffloadRuleRemove(this, rule);
}
private void clearIpv6ForwardingRules() {
- for (Ipv6ForwardingRule rule : mIpv6ForwardingRules.values()) {
- removeIpv6ForwardingRule(rule, false /*removeFromMap*/);
- }
- mIpv6ForwardingRules.clear();
+ if (!mUsingBpfOffload) return;
+
+ mBpfCoordinator.tetherOffloadRuleClear(this);
}
- // Convenience method to replace a rule with the same rule on a new upstream interface.
- // Allows replacing the rules in one iteration pass without ConcurrentModificationExceptions.
- // Relies on the fact that rules are in a map indexed by IP address.
- private void updateIpv6ForwardingRule(Ipv6ForwardingRule rule, int newIfindex) {
- addIpv6ForwardingRule(rule.onNewUpstream(newIfindex));
- removeIpv6ForwardingRule(rule, false /*removeFromMap*/);
+ private void updateIpv6ForwardingRule(int newIfindex) {
+ // TODO: Perhaps remove this protection check.
+ // See the related comment in #addIpv6ForwardingRule.
+ if (!mUsingBpfOffload) return;
+
+ mBpfCoordinator.tetherOffloadRuleUpdate(this, newIfindex);
}
// Handles all updates to IPv6 forwarding rules. These can currently change only if the upstream
@@ -921,9 +877,7 @@ public class IpServer extends StateMachine {
// If the upstream interface has changed, remove all rules and re-add them with the new
// upstream interface.
if (prevUpstreamIfindex != upstreamIfindex) {
- for (Ipv6ForwardingRule rule : mIpv6ForwardingRules.values()) {
- updateIpv6ForwardingRule(rule, upstreamIfindex);
- }
+ updateIpv6ForwardingRule(upstreamIfindex);
}
// If we're here to process a NeighborEvent, do so now.
@@ -943,7 +897,7 @@ public class IpServer extends StateMachine {
if (e.isValid()) {
addIpv6ForwardingRule(rule);
} else {
- removeIpv6ForwardingRule(rule, true /*removeFromMap*/);
+ removeIpv6ForwardingRule(rule);
}
}
diff --git a/packages/Tethering/src/android/net/util/TetheringUtils.java b/packages/Tethering/src/android/net/util/TetheringUtils.java
index dd67dddae1cd..b17b4ba77cfb 100644
--- a/packages/Tethering/src/android/net/util/TetheringUtils.java
+++ b/packages/Tethering/src/android/net/util/TetheringUtils.java
@@ -15,19 +15,94 @@
*/
package android.net.util;
+import android.net.TetherStatsParcel;
import android.net.TetheringRequestParcel;
+import androidx.annotation.NonNull;
+
import java.io.FileDescriptor;
import java.net.SocketException;
import java.util.Objects;
/**
- * Native methods for tethering utilization.
+ * The classes and the methods for tethering utilization.
*
* {@hide}
*/
public class TetheringUtils {
/**
+ * The object which records offload Tx/Rx forwarded bytes/packets.
+ * TODO: Replace the inner class ForwardedStats of class OffloadHardwareInterface with
+ * this class as well.
+ */
+ public static class ForwardedStats {
+ public final long rxBytes;
+ public final long rxPackets;
+ public final long txBytes;
+ public final long txPackets;
+
+ public ForwardedStats() {
+ rxBytes = 0;
+ rxPackets = 0;
+ txBytes = 0;
+ txPackets = 0;
+ }
+
+ public ForwardedStats(long rxBytes, long txBytes) {
+ this.rxBytes = rxBytes;
+ this.rxPackets = 0;
+ this.txBytes = txBytes;
+ this.txPackets = 0;
+ }
+
+ public ForwardedStats(long rxBytes, long rxPackets, long txBytes, long txPackets) {
+ this.rxBytes = rxBytes;
+ this.rxPackets = rxPackets;
+ this.txBytes = txBytes;
+ this.txPackets = txPackets;
+ }
+
+ public ForwardedStats(@NonNull TetherStatsParcel tetherStats) {
+ rxBytes = tetherStats.rxBytes;
+ rxPackets = tetherStats.rxPackets;
+ txBytes = tetherStats.txBytes;
+ txPackets = tetherStats.txPackets;
+ }
+
+ public ForwardedStats(@NonNull ForwardedStats other) {
+ rxBytes = other.rxBytes;
+ rxPackets = other.rxPackets;
+ txBytes = other.txBytes;
+ txPackets = other.txPackets;
+ }
+
+ /** Add Tx/Rx bytes/packets and return the result as a new object. */
+ @NonNull
+ public ForwardedStats add(@NonNull ForwardedStats other) {
+ return new ForwardedStats(rxBytes + other.rxBytes, rxPackets + other.rxPackets,
+ txBytes + other.txBytes, txPackets + other.txPackets);
+ }
+
+ /** Subtract Tx/Rx bytes/packets and return the result as a new object. */
+ @NonNull
+ public ForwardedStats subtract(@NonNull ForwardedStats other) {
+ // TODO: Perhaps throw an exception if any negative difference value just in case.
+ final long rxBytesDiff = Math.max(rxBytes - other.rxBytes, 0);
+ final long rxPacketsDiff = Math.max(rxPackets - other.rxPackets, 0);
+ final long txBytesDiff = Math.max(txBytes - other.txBytes, 0);
+ final long txPacketsDiff = Math.max(txPackets - other.txPackets, 0);
+ return new ForwardedStats(rxBytesDiff, rxPacketsDiff, txBytesDiff, txPacketsDiff);
+ }
+
+ /** Returns the string representation of this object. */
+ @NonNull
+ public String toString() {
+ return String.format("ForwardedStats(rxb: %d, rxp: %d, txb: %d, txp: %d)", rxBytes,
+ rxPackets, txBytes, txPackets);
+ }
+ }
+
+ /**
* Configures a socket for receiving ICMPv6 router solicitations and sending advertisements.
* @param fd the socket's {@link FileDescriptor}.
* @param ifIndex the interface index.
diff --git a/packages/Tethering/src/com/android/networkstack/tethering/BpfCoordinator.java b/packages/Tethering/src/com/android/networkstack/tethering/BpfCoordinator.java
new file mode 100644
index 000000000000..fc27b6add052
--- /dev/null
+++ b/packages/Tethering/src/com/android/networkstack/tethering/BpfCoordinator.java
@@ -0,0 +1,637 @@
+/*
+ * 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.networkstack.tethering;
+
+import static android.net.NetworkStats.DEFAULT_NETWORK_NO;
+import static android.net.NetworkStats.METERED_NO;
+import static android.net.NetworkStats.ROAMING_NO;
+import static android.net.NetworkStats.SET_DEFAULT;
+import static android.net.NetworkStats.TAG_NONE;
+import static android.net.NetworkStats.UID_ALL;
+import static android.net.NetworkStats.UID_TETHERING;
+import static android.net.netstats.provider.NetworkStatsProvider.QUOTA_UNLIMITED;
+
+import android.app.usage.NetworkStatsManager;
+import android.net.INetd;
+import android.net.MacAddress;
+import android.net.NetworkStats;
+import android.net.NetworkStats.Entry;
+import android.net.TetherOffloadRuleParcel;
+import android.net.TetherStatsParcel;
+import android.net.ip.IpServer;
+import android.net.netstats.provider.NetworkStatsProvider;
+import android.net.util.SharedLog;
+import android.net.util.TetheringUtils.ForwardedStats;
+import android.os.Handler;
+import android.os.RemoteException;
+import android.os.ServiceSpecificException;
+import android.text.TextUtils;
+import android.util.Log;
+import android.util.SparseArray;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
+import com.android.internal.annotations.VisibleForTesting;
+
+import java.net.Inet6Address;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.LinkedHashMap;
+import java.util.Objects;
+
+/**
+ * This coordinator is responsible for providing BPF offload relevant functionality.
+ * - Get tethering stats.
+ * - Set data limit.
+ * - Set global alert.
+ * - Add/remove forwarding rules.
+ *
+ * @hide
+ */
+public class BpfCoordinator {
+ private static final String TAG = BpfCoordinator.class.getSimpleName();
+ @VisibleForTesting
+ static final int DEFAULT_PERFORM_POLL_INTERVAL_MS = 5000; // TODO: Make it customizable.
+
+ @VisibleForTesting
+ enum StatsType {
+ STATS_PER_IFACE,
+ STATS_PER_UID,
+ }
+
+ @NonNull
+ private final Handler mHandler;
+ @NonNull
+ private final INetd mNetd;
+ @NonNull
+ private final SharedLog mLog;
+ @NonNull
+ private final Dependencies mDeps;
+ @Nullable
+ private final BpfTetherStatsProvider mStatsProvider;
+
+ // Tracks whether BPF tethering is started or not. This is set by tethering before it
+ // starts the first IpServer and is cleared by tethering shortly before the last IpServer
+ // is stopped. Note that rule updates (especially deletions, but sometimes additions as
+ // well) may arrive when this is false. If they do, they must be communicated to netd.
+ // Changes in data limits may also arrive when this is false, and if they do, they must
+ // also be communicated to netd.
+ private boolean mPollingStarted = false;
+
+ // Tracking remaining alert quota. Unlike limit quota is subject to interface, the alert
+ // quota is interface independent and global for tether offload.
+ private long mRemainingAlertQuota = QUOTA_UNLIMITED;
+
+ // Maps upstream interface index to offloaded traffic statistics.
+ // Always contains the latest total bytes/packets, since each upstream was started, received
+ // from the BPF maps for each interface.
+ private final SparseArray<ForwardedStats> mStats = new SparseArray<>();
+
+ // Maps upstream interface names to interface quotas.
+ // Always contains the latest value received from the framework for each interface, regardless
+ // of whether offload is currently running (or is even supported) on that interface. Only
+ // includes interfaces that have a quota set. Note that this map is used for storing the quota
+ // which is set from the service. Because the service uses the interface name to present the
+ // interface, this map uses the interface name to be the mapping index.
+ private final HashMap<String, Long> mInterfaceQuotas = new HashMap<>();
+
+ // Maps upstream interface index to interface names.
+ // Store all interface name since boot. Used for lookup what interface name it is from the
+ // tether stats got from netd because netd reports interface index to present an interface.
+ // TODO: Remove the unused interface name.
+ private final SparseArray<String> mInterfaceNames = new SparseArray<>();
+
+ // Map of downstream rule maps. Each of these maps represents the IPv6 forwarding rules for a
+ // given downstream. Each map:
+ // - Is owned by the IpServer that is responsible for that downstream.
+ // - Must only be modified by that IpServer.
+ // - Is created when the IpServer adds its first rule, and deleted when the IpServer deletes
+ // its last rule (or clears its rules).
+ // TODO: Perhaps seal the map and rule operations which communicates with netd into a class.
+ // TODO: Does this need to be a LinkedHashMap or can it just be a HashMap? Also, could it be
+ // a ConcurrentHashMap, in order to avoid the copies in tetherOffloadRuleClear
+ // and tetherOffloadRuleUpdate?
+ // TODO: Perhaps use one-dimensional map and access specific downstream rules via downstream
+ // index. For doing that, IpServer must guarantee that it always has a valid IPv6 downstream
+ // interface index while calling function to clear all rules. IpServer may be calling clear
+ // rules function without a valid IPv6 downstream interface index even if it may have one
+ // before. IpServer would need to call getInterfaceParams() in the constructor instead of when
+ // startIpv6() is called, and make mInterfaceParams final.
+ private final HashMap<IpServer, LinkedHashMap<Inet6Address, Ipv6ForwardingRule>>
+ mIpv6ForwardingRules = new LinkedHashMap<>();
+
+ // Runnable that used by scheduling next polling of stats.
+ private final Runnable mScheduledPollingTask = () -> {
+ updateForwardedStatsFromNetd();
+ maybeSchedulePollingStats();
+ };
+
+ @VisibleForTesting
+ public static class Dependencies {
+ int getPerformPollInterval() {
+ // TODO: Consider make this configurable.
+ return DEFAULT_PERFORM_POLL_INTERVAL_MS;
+ }
+ }
+
+ @VisibleForTesting
+ public BpfCoordinator(@NonNull Handler handler, @NonNull INetd netd,
+ @NonNull NetworkStatsManager nsm, @NonNull SharedLog log, @NonNull Dependencies deps) {
+ mHandler = handler;
+ mNetd = netd;
+ mLog = log.forSubComponent(TAG);
+ BpfTetherStatsProvider provider = new BpfTetherStatsProvider();
+ try {
+ nsm.registerNetworkStatsProvider(getClass().getSimpleName(), provider);
+ } catch (RuntimeException e) {
+ // TODO: Perhaps not allow to use BPF offload because the reregistration failure
+ // implied that no data limit could be applies on a metered upstream if any.
+ Log.wtf(TAG, "Cannot register offload stats provider: " + e);
+ provider = null;
+ }
+ mStatsProvider = provider;
+ mDeps = deps;
+ }
+
+ /**
+ * Start BPF tethering offload stats polling when the first upstream is started.
+ * Note that this can be only called on handler thread.
+ * TODO: Perhaps check BPF support before starting.
+ * TODO: Start the stats polling only if there is any client on the downstream.
+ */
+ public void startPolling() {
+ if (mPollingStarted) return;
+
+ mPollingStarted = true;
+ maybeSchedulePollingStats();
+
+ mLog.i("Polling started");
+ }
+
+ /**
+ * Stop BPF tethering offload stats polling.
+ * The data limit cleanup and the tether stats maps cleanup are not implemented here.
+ * These cleanups rely on all IpServers calling #tetherOffloadRuleRemove. After the
+ * last rule is removed from the upstream, #tetherOffloadRuleRemove does the cleanup
+ * functionality.
+ * Note that this can be only called on handler thread.
+ */
+ public void stopPolling() {
+ if (!mPollingStarted) return;
+
+ // Stop scheduled polling tasks and poll the latest stats from BPF maps.
+ if (mHandler.hasCallbacks(mScheduledPollingTask)) {
+ mHandler.removeCallbacks(mScheduledPollingTask);
+ }
+ updateForwardedStatsFromNetd();
+ mPollingStarted = false;
+
+ mLog.i("Polling stopped");
+ }
+
+ /**
+ * Add forwarding rule. After adding the first rule on a given upstream, must add the data
+ * limit on the given upstream.
+ * Note that this can be only called on handler thread.
+ */
+ public void tetherOffloadRuleAdd(
+ @NonNull final IpServer ipServer, @NonNull final Ipv6ForwardingRule rule) {
+ try {
+ // TODO: Perhaps avoid to add a duplicate rule.
+ mNetd.tetherOffloadRuleAdd(rule.toTetherOffloadRuleParcel());
+ } catch (RemoteException | ServiceSpecificException e) {
+ mLog.e("Could not add IPv6 forwarding rule: ", e);
+ return;
+ }
+
+ if (!mIpv6ForwardingRules.containsKey(ipServer)) {
+ mIpv6ForwardingRules.put(ipServer, new LinkedHashMap<Inet6Address,
+ Ipv6ForwardingRule>());
+ }
+ LinkedHashMap<Inet6Address, Ipv6ForwardingRule> rules = mIpv6ForwardingRules.get(ipServer);
+
+ // Setup the data limit on the given upstream if the first rule is added.
+ final int upstreamIfindex = rule.upstreamIfindex;
+ if (!isAnyRuleOnUpstream(upstreamIfindex)) {
+ // If failed to set a data limit, probably should not use this upstream, because
+ // the upstream may not want to blow through the data limit that was told to apply.
+ // TODO: Perhaps stop the coordinator.
+ boolean success = updateDataLimit(upstreamIfindex);
+ if (!success) {
+ final String iface = mInterfaceNames.get(upstreamIfindex);
+ mLog.e("Setting data limit for " + iface + " failed.");
+ }
+ }
+
+ // Must update the adding rule after calling #isAnyRuleOnUpstream because it needs to
+ // check if it is about adding a first rule for a given upstream.
+ rules.put(rule.address, rule);
+ }
+
+ /**
+ * Remove forwarding rule. After removing the last rule on a given upstream, must clear
+ * data limit, update the last tether stats and remove the tether stats in the BPF maps.
+ * Note that this can be only called on handler thread.
+ */
+ public void tetherOffloadRuleRemove(
+ @NonNull final IpServer ipServer, @NonNull final Ipv6ForwardingRule rule) {
+ try {
+ // TODO: Perhaps avoid to remove a non-existent rule.
+ mNetd.tetherOffloadRuleRemove(rule.toTetherOffloadRuleParcel());
+ } catch (RemoteException | ServiceSpecificException e) {
+ mLog.e("Could not remove IPv6 forwarding rule: ", e);
+ return;
+ }
+
+ LinkedHashMap<Inet6Address, Ipv6ForwardingRule> rules = mIpv6ForwardingRules.get(ipServer);
+ if (rules == null) return;
+
+ // Must remove rules before calling #isAnyRuleOnUpstream because it needs to check if
+ // the last rule is removed for a given upstream. If no rule is removed, return early.
+ // Avoid unnecessary work on a non-existent rule which may have never been added or
+ // removed already.
+ if (rules.remove(rule.address) == null) return;
+
+ // Remove the downstream entry if it has no more rule.
+ if (rules.isEmpty()) {
+ mIpv6ForwardingRules.remove(ipServer);
+ }
+
+ // Do cleanup functionality if there is no more rule on the given upstream.
+ final int upstreamIfindex = rule.upstreamIfindex;
+ if (!isAnyRuleOnUpstream(upstreamIfindex)) {
+ try {
+ final TetherStatsParcel stats =
+ mNetd.tetherOffloadGetAndClearStats(upstreamIfindex);
+ // Update the last stats delta and delete the local cache for a given upstream.
+ updateQuotaAndStatsFromSnapshot(new TetherStatsParcel[] {stats});
+ mStats.remove(upstreamIfindex);
+ } catch (RemoteException | ServiceSpecificException e) {
+ Log.wtf(TAG, "Exception when cleanup tether stats for upstream index "
+ + upstreamIfindex + ": ", e);
+ }
+ }
+ }
+
+ /**
+ * Clear all forwarding rules for a given downstream.
+ * Note that this can be only called on handler thread.
+ */
+ public void tetherOffloadRuleClear(@NonNull final IpServer ipServer) {
+ final LinkedHashMap<Inet6Address, Ipv6ForwardingRule> rules = mIpv6ForwardingRules.get(
+ ipServer);
+ if (rules == null) return;
+
+ // Need to build a rule list because the rule map may be changed in the iteration.
+ for (final Ipv6ForwardingRule rule : new ArrayList<Ipv6ForwardingRule>(rules.values())) {
+ tetherOffloadRuleRemove(ipServer, rule);
+ }
+ }
+
+ /**
+ * Update existing forwarding rules to new upstream for a given downstream.
+ * Note that this can be only called on handler thread.
+ */
+ public void tetherOffloadRuleUpdate(@NonNull final IpServer ipServer, int newUpstreamIfindex) {
+ final LinkedHashMap<Inet6Address, Ipv6ForwardingRule> rules = mIpv6ForwardingRules.get(
+ ipServer);
+ if (rules == null) return;
+
+ // Need to build a rule list because the rule map may be changed in the iteration.
+ for (final Ipv6ForwardingRule rule : new ArrayList<Ipv6ForwardingRule>(rules.values())) {
+ // Remove the old rule before adding the new one because the map uses the same key for
+ // both rules. Reversing the processing order causes that the new rule is removed as
+ // unexpected.
+ // TODO: Add new rule first to reduce the latency which has no rule.
+ tetherOffloadRuleRemove(ipServer, rule);
+ tetherOffloadRuleAdd(ipServer, rule.onNewUpstream(newUpstreamIfindex));
+ }
+ }
+
+ /**
+ * Add upstream name to lookup table. The lookup table is used for tether stats interface name
+ * lookup because the netd only reports interface index in BPF tether stats but the service
+ * expects the interface name in NetworkStats object.
+ * Note that this can be only called on handler thread.
+ */
+ public void addUpstreamNameToLookupTable(int upstreamIfindex, @NonNull String upstreamIface) {
+ if (upstreamIfindex == 0 || TextUtils.isEmpty(upstreamIface)) return;
+
+ // The same interface index to name mapping may be added by different IpServer objects or
+ // re-added by reconnection on the same upstream interface. Ignore the duplicate one.
+ final String iface = mInterfaceNames.get(upstreamIfindex);
+ if (iface == null) {
+ mInterfaceNames.put(upstreamIfindex, upstreamIface);
+ } else if (!TextUtils.equals(iface, upstreamIface)) {
+ Log.wtf(TAG, "The upstream interface name " + upstreamIface
+ + " is different from the existing interface name "
+ + iface + " for index " + upstreamIfindex);
+ }
+ }
+
+ /** IPv6 forwarding rule class. */
+ public static class Ipv6ForwardingRule {
+ public final int upstreamIfindex;
+ public final int downstreamIfindex;
+
+ @NonNull
+ public final Inet6Address address;
+ @NonNull
+ public final MacAddress srcMac;
+ @NonNull
+ public final MacAddress dstMac;
+
+ public Ipv6ForwardingRule(int upstreamIfindex, int downstreamIfIndex,
+ @NonNull Inet6Address address, @NonNull MacAddress srcMac,
+ @NonNull MacAddress dstMac) {
+ this.upstreamIfindex = upstreamIfindex;
+ this.downstreamIfindex = downstreamIfIndex;
+ this.address = address;
+ this.srcMac = srcMac;
+ this.dstMac = dstMac;
+ }
+
+ /** Return a new rule object which updates with new upstream index. */
+ @NonNull
+ public Ipv6ForwardingRule onNewUpstream(int newUpstreamIfindex) {
+ return new Ipv6ForwardingRule(newUpstreamIfindex, downstreamIfindex, address, srcMac,
+ dstMac);
+ }
+
+ /**
+ * Don't manipulate TetherOffloadRuleParcel directly because implementing onNewUpstream()
+ * would be error-prone due to generated stable AIDL classes not having a copy constructor.
+ */
+ @NonNull
+ public TetherOffloadRuleParcel toTetherOffloadRuleParcel() {
+ final TetherOffloadRuleParcel parcel = new TetherOffloadRuleParcel();
+ parcel.inputInterfaceIndex = upstreamIfindex;
+ parcel.outputInterfaceIndex = downstreamIfindex;
+ parcel.destination = address.getAddress();
+ parcel.prefixLength = 128;
+ parcel.srcL2Address = srcMac.toByteArray();
+ parcel.dstL2Address = dstMac.toByteArray();
+ return parcel;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (!(o instanceof Ipv6ForwardingRule)) return false;
+ Ipv6ForwardingRule that = (Ipv6ForwardingRule) o;
+ return this.upstreamIfindex == that.upstreamIfindex
+ && this.downstreamIfindex == that.downstreamIfindex
+ && Objects.equals(this.address, that.address)
+ && Objects.equals(this.srcMac, that.srcMac)
+ && Objects.equals(this.dstMac, that.dstMac);
+ }
+
+ @Override
+ public int hashCode() {
+ // TODO: if this is ever used in production code, don't pass ifindices
+ // to Objects.hash() to avoid autoboxing overhead.
+ return Objects.hash(upstreamIfindex, downstreamIfindex, address, srcMac, dstMac);
+ }
+ }
+
+ /**
+ * A BPF tethering stats provider to provide network statistics to the system.
+ * Note that this class' data may only be accessed on the handler thread.
+ */
+ @VisibleForTesting
+ class BpfTetherStatsProvider extends NetworkStatsProvider {
+ // The offloaded traffic statistics per interface that has not been reported since the
+ // last call to pushTetherStats. Only the interfaces that were ever tethering upstreams
+ // and has pending tether stats delta are included in this NetworkStats object.
+ private NetworkStats mIfaceStats = new NetworkStats(0L, 0);
+
+ // The same stats as above, but counts network stats per uid.
+ private NetworkStats mUidStats = new NetworkStats(0L, 0);
+
+ @Override
+ public void onRequestStatsUpdate(int token) {
+ mHandler.post(() -> pushTetherStats());
+ }
+
+ @Override
+ public void onSetAlert(long quotaBytes) {
+ mHandler.post(() -> updateAlertQuota(quotaBytes));
+ }
+
+ @Override
+ public void onSetLimit(@NonNull String iface, long quotaBytes) {
+ if (quotaBytes < QUOTA_UNLIMITED) {
+ throw new IllegalArgumentException("invalid quota value " + quotaBytes);
+ }
+
+ mHandler.post(() -> {
+ final Long curIfaceQuota = mInterfaceQuotas.get(iface);
+
+ if (null == curIfaceQuota && QUOTA_UNLIMITED == quotaBytes) return;
+
+ if (quotaBytes == QUOTA_UNLIMITED) {
+ mInterfaceQuotas.remove(iface);
+ } else {
+ mInterfaceQuotas.put(iface, quotaBytes);
+ }
+ maybeUpdateDataLimit(iface);
+ });
+ }
+
+ @VisibleForTesting
+ void pushTetherStats() {
+ try {
+ // The token is not used for now. See b/153606961.
+ notifyStatsUpdated(0 /* token */, mIfaceStats, mUidStats);
+
+ // Clear the accumulated tether stats delta after reported. Note that create a new
+ // empty object because NetworkStats#clear is @hide.
+ mIfaceStats = new NetworkStats(0L, 0);
+ mUidStats = new NetworkStats(0L, 0);
+ } catch (RuntimeException e) {
+ mLog.e("Cannot report network stats: ", e);
+ }
+ }
+
+ private void accumulateDiff(@NonNull NetworkStats ifaceDiff,
+ @NonNull NetworkStats uidDiff) {
+ mIfaceStats = mIfaceStats.add(ifaceDiff);
+ mUidStats = mUidStats.add(uidDiff);
+ }
+ }
+
+ private int getInterfaceIndexFromRules(@NonNull String ifName) {
+ for (LinkedHashMap<Inet6Address, Ipv6ForwardingRule> rules : mIpv6ForwardingRules
+ .values()) {
+ for (Ipv6ForwardingRule rule : rules.values()) {
+ final int upstreamIfindex = rule.upstreamIfindex;
+ if (TextUtils.equals(ifName, mInterfaceNames.get(upstreamIfindex))) {
+ return upstreamIfindex;
+ }
+ }
+ }
+ return 0;
+ }
+
+ private long getQuotaBytes(@NonNull String iface) {
+ final Long limit = mInterfaceQuotas.get(iface);
+ final long quotaBytes = (limit != null) ? limit : QUOTA_UNLIMITED;
+
+ return quotaBytes;
+ }
+
+ private boolean sendDataLimitToNetd(int ifIndex, long quotaBytes) {
+ if (ifIndex == 0) {
+ Log.wtf(TAG, "Invalid interface index.");
+ return false;
+ }
+
+ try {
+ mNetd.tetherOffloadSetInterfaceQuota(ifIndex, quotaBytes);
+ } catch (RemoteException | ServiceSpecificException e) {
+ mLog.e("Exception when updating quota " + quotaBytes + ": ", e);
+ return false;
+ }
+
+ return true;
+ }
+
+ // Handle the data limit update from the service which is the stats provider registered for.
+ private void maybeUpdateDataLimit(@NonNull String iface) {
+ // Set data limit only on a given upstream which has at least one rule. If we can't get
+ // an interface index for a given interface name, it means either there is no rule for
+ // a given upstream or the interface name is not an upstream which is monitored by the
+ // coordinator.
+ final int ifIndex = getInterfaceIndexFromRules(iface);
+ if (ifIndex == 0) return;
+
+ final long quotaBytes = getQuotaBytes(iface);
+ sendDataLimitToNetd(ifIndex, quotaBytes);
+ }
+
+ // Handle the data limit update while adding forwarding rules.
+ private boolean updateDataLimit(int ifIndex) {
+ final String iface = mInterfaceNames.get(ifIndex);
+ if (iface == null) {
+ mLog.e("Fail to get the interface name for index " + ifIndex);
+ return false;
+ }
+ final long quotaBytes = getQuotaBytes(iface);
+ return sendDataLimitToNetd(ifIndex, quotaBytes);
+ }
+
+ private boolean isAnyRuleOnUpstream(int upstreamIfindex) {
+ for (LinkedHashMap<Inet6Address, Ipv6ForwardingRule> rules : mIpv6ForwardingRules
+ .values()) {
+ for (Ipv6ForwardingRule rule : rules.values()) {
+ if (upstreamIfindex == rule.upstreamIfindex) return true;
+ }
+ }
+ return false;
+ }
+
+ @NonNull
+ private NetworkStats buildNetworkStats(@NonNull StatsType type, int ifIndex,
+ @NonNull final ForwardedStats diff) {
+ NetworkStats stats = new NetworkStats(0L, 0);
+ final String iface = mInterfaceNames.get(ifIndex);
+ if (iface == null) {
+ // TODO: Use Log.wtf once the coordinator owns full control of tether stats from netd.
+ // For now, netd may add the empty stats for the upstream which is not monitored by
+ // the coordinator. Silently ignore it.
+ return stats;
+ }
+ final int uid = (type == StatsType.STATS_PER_UID) ? UID_TETHERING : UID_ALL;
+ // Note that the argument 'metered', 'roaming' and 'defaultNetwork' are not recorded for
+ // network stats snapshot. See NetworkStatsRecorder#recordSnapshotLocked.
+ return stats.addEntry(new Entry(iface, uid, SET_DEFAULT, TAG_NONE, METERED_NO,
+ ROAMING_NO, DEFAULT_NETWORK_NO, diff.rxBytes, diff.rxPackets,
+ diff.txBytes, diff.txPackets, 0L /* operations */));
+ }
+
+ private void updateAlertQuota(long newQuota) {
+ if (newQuota < QUOTA_UNLIMITED) {
+ throw new IllegalArgumentException("invalid quota value " + newQuota);
+ }
+ if (mRemainingAlertQuota == newQuota) return;
+
+ mRemainingAlertQuota = newQuota;
+ if (mRemainingAlertQuota == 0) {
+ mLog.i("onAlertReached");
+ if (mStatsProvider != null) mStatsProvider.notifyAlertReached();
+ }
+ }
+
+ private void updateQuotaAndStatsFromSnapshot(
+ @NonNull final TetherStatsParcel[] tetherStatsList) {
+ long usedAlertQuota = 0;
+ for (TetherStatsParcel tetherStats : tetherStatsList) {
+ final Integer ifIndex = tetherStats.ifIndex;
+ final ForwardedStats curr = new ForwardedStats(tetherStats);
+ final ForwardedStats base = mStats.get(ifIndex);
+ final ForwardedStats diff = (base != null) ? curr.subtract(base) : curr;
+ usedAlertQuota += diff.rxBytes + diff.txBytes;
+
+ // Update the local cache for counting tether stats delta.
+ mStats.put(ifIndex, curr);
+
+ // Update the accumulated tether stats delta to the stats provider for the service
+ // querying.
+ if (mStatsProvider != null) {
+ try {
+ mStatsProvider.accumulateDiff(
+ buildNetworkStats(StatsType.STATS_PER_IFACE, ifIndex, diff),
+ buildNetworkStats(StatsType.STATS_PER_UID, ifIndex, diff));
+ } catch (ArrayIndexOutOfBoundsException e) {
+ Log.wtf(TAG, "Fail to update the accumulated stats delta for interface index "
+ + ifIndex + " : ", e);
+ }
+ }
+ }
+
+ if (mRemainingAlertQuota > 0 && usedAlertQuota > 0) {
+ // Trim to zero if overshoot.
+ final long newQuota = Math.max(mRemainingAlertQuota - usedAlertQuota, 0);
+ updateAlertQuota(newQuota);
+ }
+
+ // TODO: Count the used limit quota for notifying data limit reached.
+ }
+
+ private void updateForwardedStatsFromNetd() {
+ final TetherStatsParcel[] tetherStatsList;
+ try {
+ // The reported tether stats are total data usage for all currently-active upstream
+ // interfaces since tethering start.
+ tetherStatsList = mNetd.tetherOffloadGetStats();
+ } catch (RemoteException | ServiceSpecificException e) {
+ mLog.e("Problem fetching tethering stats: ", e);
+ return;
+ }
+ updateQuotaAndStatsFromSnapshot(tetherStatsList);
+ }
+
+ private void maybeSchedulePollingStats() {
+ if (!mPollingStarted) return;
+
+ if (mHandler.hasCallbacks(mScheduledPollingTask)) {
+ mHandler.removeCallbacks(mScheduledPollingTask);
+ }
+
+ mHandler.postDelayed(mScheduledPollingTask, mDeps.getPerformPollInterval());
+ }
+}
diff --git a/packages/Tethering/src/com/android/networkstack/tethering/Tethering.java b/packages/Tethering/src/com/android/networkstack/tethering/Tethering.java
index 69eec8df9864..df6745855067 100644
--- a/packages/Tethering/src/com/android/networkstack/tethering/Tethering.java
+++ b/packages/Tethering/src/com/android/networkstack/tethering/Tethering.java
@@ -232,6 +232,7 @@ public class Tethering {
private final TetheringThreadExecutor mExecutor;
private final TetheringNotificationUpdater mNotificationUpdater;
private final UserManager mUserManager;
+ private final BpfCoordinator mBpfCoordinator;
private final PrivateAddressCoordinator mPrivateAddressCoordinator;
private int mActiveDataSubId = INVALID_SUBSCRIPTION_ID;
// All the usage of mTetheringEventCallback should run in the same thread.
@@ -284,6 +285,8 @@ public class Tethering {
mUpstreamNetworkMonitor = mDeps.getUpstreamNetworkMonitor(mContext, mTetherMasterSM, mLog,
TetherMasterSM.EVENT_UPSTREAM_CALLBACK);
mForwardedDownstreams = new LinkedHashSet<>();
+ mBpfCoordinator = mDeps.getBpfCoordinator(
+ mHandler, mNetd, mLog, new BpfCoordinator.Dependencies());
IntentFilter filter = new IntentFilter();
filter.addAction(ACTION_CARRIER_CONFIG_CHANGED);
@@ -1704,6 +1707,9 @@ public class Tethering {
chooseUpstreamType(true);
mTryCell = false;
}
+
+ // TODO: Check the upstream interface if it is managed by BPF offload.
+ mBpfCoordinator.startPolling();
}
@Override
@@ -1716,6 +1722,7 @@ public class Tethering {
mTetherUpstream = null;
reportUpstreamChanged(null);
}
+ mBpfCoordinator.stopPolling();
}
private boolean updateUpstreamWanted() {
@@ -2341,7 +2348,7 @@ public class Tethering {
mLog.log("adding TetheringInterfaceStateMachine for: " + iface);
final TetherState tetherState = new TetherState(
- new IpServer(iface, mLooper, interfaceType, mLog, mNetd,
+ new IpServer(iface, mLooper, interfaceType, mLog, mNetd, mBpfCoordinator,
makeControlCallback(), mConfig.enableLegacyDhcpServer,
mConfig.enableBpfOffload, mPrivateAddressCoordinator,
mDeps.getIpServerDependencies()));
diff --git a/packages/Tethering/src/com/android/networkstack/tethering/TetheringDependencies.java b/packages/Tethering/src/com/android/networkstack/tethering/TetheringDependencies.java
index ce546c701a61..d637c8646b4a 100644
--- a/packages/Tethering/src/com/android/networkstack/tethering/TetheringDependencies.java
+++ b/packages/Tethering/src/com/android/networkstack/tethering/TetheringDependencies.java
@@ -41,6 +41,17 @@ import java.util.ArrayList;
*/
public abstract class TetheringDependencies {
/**
+ * Get a reference to the BpfCoordinator to be used by tethering.
+ */
+ public @NonNull BpfCoordinator getBpfCoordinator(
+ @NonNull Handler handler, @NonNull INetd netd, @NonNull SharedLog log,
+ @NonNull BpfCoordinator.Dependencies deps) {
+ final NetworkStatsManager statsManager =
+ (NetworkStatsManager) getContext().getSystemService(Context.NETWORK_STATS_SERVICE);
+ return new BpfCoordinator(handler, netd, statsManager, log, deps);
+ }
+
+ /**
* Get a reference to the offload hardware interface to be used by tethering.
*/
public OffloadHardwareInterface getOffloadHardwareInterface(Handler h, SharedLog log) {
diff --git a/packages/Tethering/src/com/android/networkstack/tethering/TetheringNotificationUpdater.java b/packages/Tethering/src/com/android/networkstack/tethering/TetheringNotificationUpdater.java
index d03deda37fdf..593d04a06b93 100644
--- a/packages/Tethering/src/com/android/networkstack/tethering/TetheringNotificationUpdater.java
+++ b/packages/Tethering/src/com/android/networkstack/tethering/TetheringNotificationUpdater.java
@@ -24,8 +24,10 @@ import android.app.Notification.Action;
import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.app.PendingIntent;
+import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
+import android.content.pm.PackageManager;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.net.NetworkCapabilities;
@@ -253,6 +255,14 @@ public class TetheringNotificationUpdater {
}
@VisibleForTesting
+ static String getSettingsPackageName(@NonNull final PackageManager pm) {
+ final Intent settingsIntent = new Intent(Settings.ACTION_SETTINGS);
+ final ComponentName settingsComponent = settingsIntent.resolveActivity(pm);
+ return settingsComponent != null
+ ? settingsComponent.getPackageName() : "com.android.settings";
+ }
+
+ @VisibleForTesting
void notifyTetheringDisabledByRestriction() {
final Resources res = getResourcesForSubId(mContext, mActiveDataSubId);
final String title = res.getString(R.string.disable_tether_notification_title);
@@ -262,8 +272,9 @@ public class TetheringNotificationUpdater {
final PendingIntent pi = PendingIntent.getActivity(
mContext.createContextAsUser(UserHandle.CURRENT, 0 /* flags */),
0 /* requestCode */,
- new Intent(Settings.ACTION_TETHER_SETTINGS),
- Intent.FLAG_ACTIVITY_NEW_TASK,
+ new Intent(Settings.ACTION_TETHER_SETTINGS)
+ .setPackage(getSettingsPackageName(mContext.getPackageManager())),
+ Intent.FLAG_ACTIVITY_NEW_TASK | PendingIntent.FLAG_IMMUTABLE,
null /* options */);
showNotification(R.drawable.stat_sys_tether_general, title, message,
@@ -284,7 +295,7 @@ public class TetheringNotificationUpdater {
mContext.createContextAsUser(UserHandle.CURRENT, 0 /* flags */),
0 /* requestCode */,
intent,
- 0 /* flags */);
+ PendingIntent.FLAG_IMMUTABLE);
final Action action = new Action.Builder(NO_ICON_ID, disableButton, pi).build();
showNotification(R.drawable.stat_sys_tether_general, title, message,
@@ -305,8 +316,9 @@ public class TetheringNotificationUpdater {
final PendingIntent pi = PendingIntent.getActivity(
mContext.createContextAsUser(UserHandle.CURRENT, 0 /* flags */),
0 /* requestCode */,
- new Intent(Settings.ACTION_TETHER_SETTINGS),
- Intent.FLAG_ACTIVITY_NEW_TASK,
+ new Intent(Settings.ACTION_TETHER_SETTINGS)
+ .setPackage(getSettingsPackageName(mContext.getPackageManager())),
+ Intent.FLAG_ACTIVITY_NEW_TASK | PendingIntent.FLAG_IMMUTABLE,
null /* options */);
showNotification(R.drawable.stat_sys_tether_general, title, message,
diff --git a/packages/Tethering/src/com/android/networkstack/tethering/TetheringService.java b/packages/Tethering/src/com/android/networkstack/tethering/TetheringService.java
index e095afea52ca..d084ca0966e8 100644
--- a/packages/Tethering/src/com/android/networkstack/tethering/TetheringService.java
+++ b/packages/Tethering/src/com/android/networkstack/tethering/TetheringService.java
@@ -17,8 +17,10 @@
package com.android.networkstack.tethering;
import static android.Manifest.permission.ACCESS_NETWORK_STATE;
+import static android.Manifest.permission.NETWORK_STACK;
import static android.Manifest.permission.TETHER_PRIVILEGED;
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
+import static android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK;
import static android.net.TetheringManager.TETHER_ERROR_NO_ACCESS_TETHERING_PERMISSION;
import static android.net.TetheringManager.TETHER_ERROR_NO_CHANGE_TETHERING_PERMISSION;
import static android.net.TetheringManager.TETHER_ERROR_NO_ERROR;
@@ -240,15 +242,26 @@ public class TetheringService extends Service {
return false;
}
+ private boolean hasNetworkStackPermission() {
+ return checkCallingOrSelfPermission(NETWORK_STACK)
+ || checkCallingOrSelfPermission(PERMISSION_MAINLINE_NETWORK_STACK);
+ }
+
private boolean hasTetherPrivilegedPermission() {
- return mService.checkCallingOrSelfPermission(TETHER_PRIVILEGED) == PERMISSION_GRANTED;
+ return checkCallingOrSelfPermission(TETHER_PRIVILEGED);
+ }
+
+ private boolean checkCallingOrSelfPermission(final String permission) {
+ return mService.checkCallingOrSelfPermission(permission) == PERMISSION_GRANTED;
}
private boolean hasTetherChangePermission(final String callerPkg,
final boolean onlyAllowPrivileged) {
+ if (onlyAllowPrivileged && !hasNetworkStackPermission()) return false;
+
if (hasTetherPrivilegedPermission()) return true;
- if (onlyAllowPrivileged || mTethering.isTetherProvisioningRequired()) return false;
+ if (mTethering.isTetherProvisioningRequired()) return false;
int uid = Binder.getCallingUid();
// If callerPkg's uid is not same as Binder.getCallingUid(),
diff --git a/packages/Tethering/tests/integration/src/android/net/EthernetTetheringTest.java b/packages/Tethering/tests/integration/src/android/net/EthernetTetheringTest.java
index 2fb7e607d0af..74df11370e50 100644
--- a/packages/Tethering/tests/integration/src/android/net/EthernetTetheringTest.java
+++ b/packages/Tethering/tests/integration/src/android/net/EthernetTetheringTest.java
@@ -339,7 +339,7 @@ public class EthernetTetheringTest {
private MyTetheringEventCallback enableEthernetTethering(String iface) throws Exception {
return enableEthernetTethering(iface,
new TetheringRequest.Builder(TETHERING_ETHERNET)
- .setExemptFromEntitlementCheck(true).build());
+ .setShouldShowEntitlementUi(false).build());
}
private int getMTU(TestNetworkInterface iface) throws SocketException {
@@ -510,7 +510,7 @@ public class EthernetTetheringTest {
LinkAddress clientAddr = client == null ? null : new LinkAddress(client);
return new TetheringRequest.Builder(TETHERING_ETHERNET)
.setStaticIpv4Addresses(localAddr, clientAddr)
- .setExemptFromEntitlementCheck(true).build();
+ .setShouldShowEntitlementUi(false).build();
}
private void assertInvalidStaticIpv4Request(String iface, String local, String client)
diff --git a/packages/Tethering/tests/unit/Android.bp b/packages/Tethering/tests/unit/Android.bp
index fccc6902e365..45c7b656e28f 100644
--- a/packages/Tethering/tests/unit/Android.bp
+++ b/packages/Tethering/tests/unit/Android.bp
@@ -60,7 +60,7 @@ java_defaults {
"framework-minus-apex",
"framework-res",
"framework-tethering.impl",
- "framework-wifi-stubs-module_libs_api",
+ "framework-wifi.stubs.module_lib",
],
jni_libs: [
// For mockito extended
diff --git a/packages/Tethering/tests/unit/src/android/net/ip/IpServerTest.java b/packages/Tethering/tests/unit/src/android/net/ip/IpServerTest.java
index 0cda29a32f59..c3bc915a232d 100644
--- a/packages/Tethering/tests/unit/src/android/net/ip/IpServerTest.java
+++ b/packages/Tethering/tests/unit/src/android/net/ip/IpServerTest.java
@@ -54,12 +54,14 @@ import static org.mockito.Mockito.doThrow;
import static org.mockito.Mockito.inOrder;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.reset;
+import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.timeout;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoMoreInteractions;
import static org.mockito.Mockito.when;
+import android.app.usage.NetworkStatsManager;
import android.net.INetd;
import android.net.InetAddresses;
import android.net.InterfaceConfigurationParcel;
@@ -69,6 +71,7 @@ import android.net.LinkProperties;
import android.net.MacAddress;
import android.net.RouteInfo;
import android.net.TetherOffloadRuleParcel;
+import android.net.TetherStatsParcel;
import android.net.dhcp.DhcpServingParamsParcel;
import android.net.dhcp.IDhcpEventCallbacks;
import android.net.dhcp.IDhcpServer;
@@ -80,13 +83,17 @@ import android.net.util.InterfaceParams;
import android.net.util.InterfaceSet;
import android.net.util.PrefixUtils;
import android.net.util.SharedLog;
+import android.os.Handler;
import android.os.RemoteException;
import android.os.test.TestLooper;
import android.text.TextUtils;
+import androidx.annotation.NonNull;
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
+import com.android.networkstack.tethering.BpfCoordinator;
+import com.android.networkstack.tethering.BpfCoordinator.Ipv6ForwardingRule;
import com.android.networkstack.tethering.PrivateAddressCoordinator;
import org.junit.Before;
@@ -100,6 +107,7 @@ import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import java.net.Inet4Address;
+import java.net.Inet6Address;
import java.net.InetAddress;
import java.util.Arrays;
import java.util.List;
@@ -133,6 +141,7 @@ public class IpServerTest {
@Mock private IpNeighborMonitor mIpNeighborMonitor;
@Mock private IpServer.Dependencies mDependencies;
@Mock private PrivateAddressCoordinator mAddressCoordinator;
+ @Mock private NetworkStatsManager mStatsManager;
@Captor private ArgumentCaptor<DhcpServingParamsParcel> mDhcpParamsCaptor;
@@ -142,6 +151,7 @@ public class IpServerTest {
private IpServer mIpServer;
private InterfaceConfigurationParcel mInterfaceConfiguration;
private NeighborEventConsumer mNeighborEventConsumer;
+ private BpfCoordinator mBpfCoordinator;
private void initStateMachine(int interfaceType) throws Exception {
initStateMachine(interfaceType, false /* usingLegacyDhcp */, DEFAULT_USING_BPF_OFFLOAD);
@@ -179,7 +189,7 @@ public class IpServerTest {
neighborCaptor.capture());
mIpServer = new IpServer(
- IFACE_NAME, mLooper.getLooper(), interfaceType, mSharedLog, mNetd,
+ IFACE_NAME, mLooper.getLooper(), interfaceType, mSharedLog, mNetd, mBpfCoordinator,
mCallback, usingLegacyDhcp, usingBpfOffload, mAddressCoordinator, mDependencies);
mIpServer.start();
mNeighborEventConsumer = neighborCaptor.getValue();
@@ -215,6 +225,10 @@ public class IpServerTest {
MockitoAnnotations.initMocks(this);
when(mSharedLog.forSubComponent(anyString())).thenReturn(mSharedLog);
when(mAddressCoordinator.requestDownstreamAddress(any())).thenReturn(mTestAddress);
+
+ BpfCoordinator bc = new BpfCoordinator(new Handler(mLooper.getLooper()), mNetd,
+ mStatsManager, mSharedLog, new BpfCoordinator.Dependencies());
+ mBpfCoordinator = spy(bc);
}
@Test
@@ -222,8 +236,8 @@ public class IpServerTest {
when(mDependencies.getIpNeighborMonitor(any(), any(), any()))
.thenReturn(mIpNeighborMonitor);
mIpServer = new IpServer(IFACE_NAME, mLooper.getLooper(), TETHERING_BLUETOOTH, mSharedLog,
- mNetd, mCallback, false /* usingLegacyDhcp */, DEFAULT_USING_BPF_OFFLOAD,
- mAddressCoordinator, mDependencies);
+ mNetd, mBpfCoordinator, mCallback, false /* usingLegacyDhcp */,
+ DEFAULT_USING_BPF_OFFLOAD, mAddressCoordinator, mDependencies);
mIpServer.start();
mLooper.dispatchAll();
verify(mCallback).updateInterfaceState(
@@ -619,6 +633,10 @@ public class IpServerTest {
* (actual: "android.net.TetherOffloadRuleParcel@8c827b0" or some such), but at least it does
* work.
*
+ * TODO: consider making the error message more readable by adding a method that catching the
+ * AssertionFailedError and throwing a new assertion with more details. See
+ * NetworkMonitorTest#verifyNetworkTested.
+ *
* See ConnectivityServiceTest#assertRoutesAdded for an alternative approach which solves the
* TooManyActualInvocations problem described above by forcing the caller of the custom assert
* method to specify all expected invocations in one call. This is useful when the stable
@@ -658,6 +676,27 @@ public class IpServerTest {
return argThat(new TetherOffloadRuleParcelMatcher(upstreamIfindex, dst, dstMac));
}
+ private static Ipv6ForwardingRule makeForwardingRule(
+ int upstreamIfindex, @NonNull InetAddress dst, @NonNull MacAddress dstMac) {
+ return new Ipv6ForwardingRule(upstreamIfindex, TEST_IFACE_PARAMS.index,
+ (Inet6Address) dst, TEST_IFACE_PARAMS.macAddr, dstMac);
+ }
+
+ private TetherStatsParcel buildEmptyTetherStatsParcel(int ifIndex) {
+ TetherStatsParcel parcel = new TetherStatsParcel();
+ parcel.ifIndex = ifIndex;
+ return parcel;
+ }
+
+ private void resetNetdAndBpfCoordinator() throws Exception {
+ reset(mNetd, mBpfCoordinator);
+ when(mNetd.tetherOffloadGetStats()).thenReturn(new TetherStatsParcel[0]);
+ when(mNetd.tetherOffloadGetAndClearStats(UPSTREAM_IFINDEX))
+ .thenReturn(buildEmptyTetherStatsParcel(UPSTREAM_IFINDEX));
+ when(mNetd.tetherOffloadGetAndClearStats(UPSTREAM_IFINDEX2))
+ .thenReturn(buildEmptyTetherStatsParcel(UPSTREAM_IFINDEX2));
+ }
+
@Test
public void addRemoveipv6ForwardingRules() throws Exception {
initTetheredStateMachine(TETHERING_WIFI, UPSTREAM_IFACE, false /* usingLegacyDhcp */,
@@ -675,75 +714,100 @@ public class IpServerTest {
final MacAddress macA = MacAddress.fromString("00:00:00:00:00:0a");
final MacAddress macB = MacAddress.fromString("11:22:33:00:00:0b");
- reset(mNetd);
+ resetNetdAndBpfCoordinator();
+ verifyNoMoreInteractions(mBpfCoordinator, mNetd);
+
+ // TODO: Perhaps verify the interaction of tetherOffloadSetInterfaceQuota and
+ // tetherOffloadGetAndClearStats in netd while the rules are changed.
// Events on other interfaces are ignored.
recvNewNeigh(notMyIfindex, neighA, NUD_REACHABLE, macA);
- verifyNoMoreInteractions(mNetd);
+ verifyNoMoreInteractions(mBpfCoordinator, mNetd);
// Events on this interface are received and sent to netd.
recvNewNeigh(myIfindex, neighA, NUD_REACHABLE, macA);
+ verify(mBpfCoordinator).tetherOffloadRuleAdd(
+ mIpServer, makeForwardingRule(UPSTREAM_IFINDEX, neighA, macA));
verify(mNetd).tetherOffloadRuleAdd(matches(UPSTREAM_IFINDEX, neighA, macA));
- reset(mNetd);
+ resetNetdAndBpfCoordinator();
recvNewNeigh(myIfindex, neighB, NUD_REACHABLE, macB);
+ verify(mBpfCoordinator).tetherOffloadRuleAdd(
+ mIpServer, makeForwardingRule(UPSTREAM_IFINDEX, neighB, macB));
verify(mNetd).tetherOffloadRuleAdd(matches(UPSTREAM_IFINDEX, neighB, macB));
- reset(mNetd);
+ resetNetdAndBpfCoordinator();
// Link-local and multicast neighbors are ignored.
recvNewNeigh(myIfindex, neighLL, NUD_REACHABLE, macA);
- verifyNoMoreInteractions(mNetd);
+ verifyNoMoreInteractions(mBpfCoordinator, mNetd);
recvNewNeigh(myIfindex, neighMC, NUD_REACHABLE, macA);
- verifyNoMoreInteractions(mNetd);
+ verifyNoMoreInteractions(mBpfCoordinator, mNetd);
// A neighbor that is no longer valid causes the rule to be removed.
// NUD_FAILED events do not have a MAC address.
recvNewNeigh(myIfindex, neighA, NUD_FAILED, null);
+ verify(mBpfCoordinator).tetherOffloadRuleRemove(
+ mIpServer, makeForwardingRule(UPSTREAM_IFINDEX, neighA, macNull));
verify(mNetd).tetherOffloadRuleRemove(matches(UPSTREAM_IFINDEX, neighA, macNull));
- reset(mNetd);
+ resetNetdAndBpfCoordinator();
// A neighbor that is deleted causes the rule to be removed.
recvDelNeigh(myIfindex, neighB, NUD_STALE, macB);
+ verify(mBpfCoordinator).tetherOffloadRuleRemove(
+ mIpServer, makeForwardingRule(UPSTREAM_IFINDEX, neighB, macNull));
verify(mNetd).tetherOffloadRuleRemove(matches(UPSTREAM_IFINDEX, neighB, macNull));
- reset(mNetd);
+ resetNetdAndBpfCoordinator();
- // Upstream changes result in deleting and re-adding the rules.
+ // Upstream changes result in updating the rules.
recvNewNeigh(myIfindex, neighA, NUD_REACHABLE, macA);
recvNewNeigh(myIfindex, neighB, NUD_REACHABLE, macB);
- reset(mNetd);
+ resetNetdAndBpfCoordinator();
InOrder inOrder = inOrder(mNetd);
LinkProperties lp = new LinkProperties();
lp.setInterfaceName(UPSTREAM_IFACE2);
dispatchTetherConnectionChanged(UPSTREAM_IFACE2, lp, -1);
- inOrder.verify(mNetd).tetherOffloadRuleAdd(matches(UPSTREAM_IFINDEX2, neighA, macA));
+ verify(mBpfCoordinator).tetherOffloadRuleUpdate(mIpServer, UPSTREAM_IFINDEX2);
inOrder.verify(mNetd).tetherOffloadRuleRemove(matches(UPSTREAM_IFINDEX, neighA, macA));
- inOrder.verify(mNetd).tetherOffloadRuleAdd(matches(UPSTREAM_IFINDEX2, neighB, macB));
+ inOrder.verify(mNetd).tetherOffloadRuleAdd(matches(UPSTREAM_IFINDEX2, neighA, macA));
inOrder.verify(mNetd).tetherOffloadRuleRemove(matches(UPSTREAM_IFINDEX, neighB, macB));
- reset(mNetd);
+ inOrder.verify(mNetd).tetherOffloadRuleAdd(matches(UPSTREAM_IFINDEX2, neighB, macB));
+ resetNetdAndBpfCoordinator();
// When the upstream is lost, rules are removed.
dispatchTetherConnectionChanged(null, null, 0);
+ // Clear function is called two times by:
+ // - processMessage CMD_TETHER_CONNECTION_CHANGED for the upstream is lost.
+ // - processMessage CMD_IPV6_TETHER_UPDATE for the IPv6 upstream is lost.
+ // See dispatchTetherConnectionChanged.
+ verify(mBpfCoordinator, times(2)).tetherOffloadRuleClear(mIpServer);
verify(mNetd).tetherOffloadRuleRemove(matches(UPSTREAM_IFINDEX2, neighA, macA));
verify(mNetd).tetherOffloadRuleRemove(matches(UPSTREAM_IFINDEX2, neighB, macB));
- reset(mNetd);
+ resetNetdAndBpfCoordinator();
// If the upstream is IPv4-only, no rules are added.
dispatchTetherConnectionChanged(UPSTREAM_IFACE);
- reset(mNetd);
+ resetNetdAndBpfCoordinator();
recvNewNeigh(myIfindex, neighA, NUD_REACHABLE, macA);
- verifyNoMoreInteractions(mNetd);
+ // Clear function is called by #updateIpv6ForwardingRules for the IPv6 upstream is lost.
+ verify(mBpfCoordinator).tetherOffloadRuleClear(mIpServer);
+ verifyNoMoreInteractions(mBpfCoordinator, mNetd);
// Rules can be added again once upstream IPv6 connectivity is available.
lp.setInterfaceName(UPSTREAM_IFACE);
dispatchTetherConnectionChanged(UPSTREAM_IFACE, lp, -1);
recvNewNeigh(myIfindex, neighB, NUD_REACHABLE, macB);
+ verify(mBpfCoordinator).tetherOffloadRuleAdd(
+ mIpServer, makeForwardingRule(UPSTREAM_IFINDEX, neighB, macB));
verify(mNetd).tetherOffloadRuleAdd(matches(UPSTREAM_IFINDEX, neighB, macB));
+ verify(mBpfCoordinator, never()).tetherOffloadRuleAdd(
+ mIpServer, makeForwardingRule(UPSTREAM_IFINDEX, neighA, macA));
verify(mNetd, never()).tetherOffloadRuleAdd(matches(UPSTREAM_IFINDEX, neighA, macA));
// If upstream IPv6 connectivity is lost, rules are removed.
- reset(mNetd);
+ resetNetdAndBpfCoordinator();
dispatchTetherConnectionChanged(UPSTREAM_IFACE, null, 0);
+ verify(mBpfCoordinator).tetherOffloadRuleClear(mIpServer);
verify(mNetd).tetherOffloadRuleRemove(matches(UPSTREAM_IFINDEX, neighB, macB));
// When the interface goes down, rules are removed.
@@ -751,15 +815,20 @@ public class IpServerTest {
dispatchTetherConnectionChanged(UPSTREAM_IFACE, lp, -1);
recvNewNeigh(myIfindex, neighA, NUD_REACHABLE, macA);
recvNewNeigh(myIfindex, neighB, NUD_REACHABLE, macB);
+ verify(mBpfCoordinator).tetherOffloadRuleAdd(
+ mIpServer, makeForwardingRule(UPSTREAM_IFINDEX, neighA, macA));
verify(mNetd).tetherOffloadRuleAdd(matches(UPSTREAM_IFINDEX, neighA, macA));
+ verify(mBpfCoordinator).tetherOffloadRuleAdd(
+ mIpServer, makeForwardingRule(UPSTREAM_IFINDEX, neighB, macB));
verify(mNetd).tetherOffloadRuleAdd(matches(UPSTREAM_IFINDEX, neighB, macB));
- reset(mNetd);
+ resetNetdAndBpfCoordinator();
mIpServer.stop();
mLooper.dispatchAll();
+ verify(mBpfCoordinator).tetherOffloadRuleClear(mIpServer);
verify(mNetd).tetherOffloadRuleRemove(matches(UPSTREAM_IFINDEX, neighA, macA));
verify(mNetd).tetherOffloadRuleRemove(matches(UPSTREAM_IFINDEX, neighB, macB));
- reset(mNetd);
+ resetNetdAndBpfCoordinator();
}
@Test
@@ -769,35 +838,46 @@ public class IpServerTest {
final MacAddress macA = MacAddress.fromString("00:00:00:00:00:0a");
final MacAddress macNull = MacAddress.fromString("00:00:00:00:00:00");
- reset(mNetd);
-
// Expect that rules can be only added/removed when the BPF offload config is enabled.
- // Note that the usingBpfOffload false case is not a realistic test case. Because IP
+ // Note that the BPF offload disabled case is not a realistic test case. Because IP
// neighbor monitor doesn't start if BPF offload is disabled, there should have no
// neighbor event listening. This is used for testing the protection check just in case.
- // TODO: Perhaps remove this test once we don't need this check anymore.
- for (boolean usingBpfOffload : new boolean[]{true, false}) {
- initTetheredStateMachine(TETHERING_WIFI, UPSTREAM_IFACE, false /* usingLegacyDhcp */,
- usingBpfOffload);
-
- // A neighbor is added.
- recvNewNeigh(myIfindex, neigh, NUD_REACHABLE, macA);
- if (usingBpfOffload) {
- verify(mNetd).tetherOffloadRuleAdd(matches(UPSTREAM_IFINDEX, neigh, macA));
- } else {
- verify(mNetd, never()).tetherOffloadRuleAdd(any());
- }
- reset(mNetd);
-
- // A neighbor is deleted.
- recvDelNeigh(myIfindex, neigh, NUD_STALE, macA);
- if (usingBpfOffload) {
- verify(mNetd).tetherOffloadRuleRemove(matches(UPSTREAM_IFINDEX, neigh, macNull));
- } else {
- verify(mNetd, never()).tetherOffloadRuleRemove(any());
- }
- reset(mNetd);
- }
+ // TODO: Perhaps remove the BPF offload disabled case test once this check isn't needed
+ // anymore.
+
+ // [1] Enable BPF offload.
+ // A neighbor that is added or deleted causes the rule to be added or removed.
+ initTetheredStateMachine(TETHERING_WIFI, UPSTREAM_IFACE, false /* usingLegacyDhcp */,
+ true /* usingBpfOffload */);
+ resetNetdAndBpfCoordinator();
+
+ recvNewNeigh(myIfindex, neigh, NUD_REACHABLE, macA);
+ verify(mBpfCoordinator).tetherOffloadRuleAdd(
+ mIpServer, makeForwardingRule(UPSTREAM_IFINDEX, neigh, macA));
+ verify(mNetd).tetherOffloadRuleAdd(matches(UPSTREAM_IFINDEX, neigh, macA));
+ resetNetdAndBpfCoordinator();
+
+ recvDelNeigh(myIfindex, neigh, NUD_STALE, macA);
+ verify(mBpfCoordinator).tetherOffloadRuleRemove(
+ mIpServer, makeForwardingRule(UPSTREAM_IFINDEX, neigh, macNull));
+ verify(mNetd).tetherOffloadRuleRemove(matches(UPSTREAM_IFINDEX, neigh, macNull));
+ resetNetdAndBpfCoordinator();
+
+ // [2] Disable BPF offload.
+ // A neighbor that is added or deleted doesn’t cause the rule to be added or removed.
+ initTetheredStateMachine(TETHERING_WIFI, UPSTREAM_IFACE, false /* usingLegacyDhcp */,
+ false /* usingBpfOffload */);
+ resetNetdAndBpfCoordinator();
+
+ recvNewNeigh(myIfindex, neigh, NUD_REACHABLE, macA);
+ verify(mBpfCoordinator, never()).tetherOffloadRuleAdd(any(), any());
+ verify(mNetd, never()).tetherOffloadRuleAdd(any());
+ resetNetdAndBpfCoordinator();
+
+ recvDelNeigh(myIfindex, neigh, NUD_STALE, macA);
+ verify(mBpfCoordinator, never()).tetherOffloadRuleRemove(any(), any());
+ verify(mNetd, never()).tetherOffloadRuleRemove(any());
+ resetNetdAndBpfCoordinator();
}
@Test
diff --git a/packages/Tethering/tests/unit/src/com/android/networkstack/tethering/BpfCoordinatorTest.java b/packages/Tethering/tests/unit/src/com/android/networkstack/tethering/BpfCoordinatorTest.java
new file mode 100644
index 000000000000..e2d7aab4e33f
--- /dev/null
+++ b/packages/Tethering/tests/unit/src/com/android/networkstack/tethering/BpfCoordinatorTest.java
@@ -0,0 +1,246 @@
+/*
+ * 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.networkstack.tethering;
+
+import static android.net.NetworkStats.DEFAULT_NETWORK_NO;
+import static android.net.NetworkStats.METERED_NO;
+import static android.net.NetworkStats.ROAMING_NO;
+import static android.net.NetworkStats.SET_DEFAULT;
+import static android.net.NetworkStats.TAG_NONE;
+import static android.net.NetworkStats.UID_ALL;
+import static android.net.NetworkStats.UID_TETHERING;
+import static android.net.netstats.provider.NetworkStatsProvider.QUOTA_UNLIMITED;
+
+import static com.android.networkstack.tethering.BpfCoordinator
+ .DEFAULT_PERFORM_POLL_INTERVAL_MS;
+import static com.android.networkstack.tethering.BpfCoordinator.StatsType;
+import static com.android.networkstack.tethering.BpfCoordinator.StatsType.STATS_PER_IFACE;
+import static com.android.networkstack.tethering.BpfCoordinator.StatsType.STATS_PER_UID;
+
+import static junit.framework.Assert.assertNotNull;
+
+import static org.mockito.Matchers.anyString;
+import static org.mockito.Mockito.clearInvocations;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.annotation.NonNull;
+import android.app.usage.NetworkStatsManager;
+import android.net.INetd;
+import android.net.NetworkStats;
+import android.net.TetherStatsParcel;
+import android.net.util.SharedLog;
+import android.os.Handler;
+import android.os.test.TestLooper;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.testutils.TestableNetworkStatsProviderCbBinder;
+
+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;
+
+import java.util.ArrayList;
+
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class BpfCoordinatorTest {
+ @Mock private NetworkStatsManager mStatsManager;
+ @Mock private INetd mNetd;
+ // Late init since methods must be called by the thread that created this object.
+ private TestableNetworkStatsProviderCbBinder mTetherStatsProviderCb;
+ private BpfCoordinator.BpfTetherStatsProvider mTetherStatsProvider;
+ private final ArgumentCaptor<ArrayList> mStringArrayCaptor =
+ ArgumentCaptor.forClass(ArrayList.class);
+ private final TestLooper mTestLooper = new TestLooper();
+ private BpfCoordinator.Dependencies mDeps =
+ new BpfCoordinator.Dependencies() {
+ @Override
+ int getPerformPollInterval() {
+ return DEFAULT_PERFORM_POLL_INTERVAL_MS;
+ }
+ };
+
+ @Before public void setUp() {
+ MockitoAnnotations.initMocks(this);
+ }
+
+ private void waitForIdle() {
+ mTestLooper.dispatchAll();
+ }
+
+ private void setupFunctioningNetdInterface() throws Exception {
+ when(mNetd.tetherOffloadGetStats()).thenReturn(new TetherStatsParcel[0]);
+ }
+
+ @NonNull
+ private BpfCoordinator makeBpfCoordinator() throws Exception {
+ BpfCoordinator coordinator = new BpfCoordinator(
+ new Handler(mTestLooper.getLooper()), mNetd, mStatsManager, new SharedLog("test"),
+ mDeps);
+ final ArgumentCaptor<BpfCoordinator.BpfTetherStatsProvider>
+ tetherStatsProviderCaptor =
+ ArgumentCaptor.forClass(BpfCoordinator.BpfTetherStatsProvider.class);
+ verify(mStatsManager).registerNetworkStatsProvider(anyString(),
+ tetherStatsProviderCaptor.capture());
+ mTetherStatsProvider = tetherStatsProviderCaptor.getValue();
+ assertNotNull(mTetherStatsProvider);
+ mTetherStatsProviderCb = new TestableNetworkStatsProviderCbBinder();
+ mTetherStatsProvider.setProviderCallbackBinder(mTetherStatsProviderCb);
+ return coordinator;
+ }
+
+ @NonNull
+ private static NetworkStats.Entry buildTestEntry(@NonNull StatsType how,
+ @NonNull String iface, long rxBytes, long rxPackets, long txBytes, long txPackets) {
+ return new NetworkStats.Entry(iface, how == STATS_PER_IFACE ? UID_ALL : UID_TETHERING,
+ SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, rxBytes,
+ rxPackets, txBytes, txPackets, 0L);
+ }
+
+ @NonNull
+ private static TetherStatsParcel buildTestTetherStatsParcel(@NonNull Integer ifIndex,
+ long rxBytes, long rxPackets, long txBytes, long txPackets) {
+ final TetherStatsParcel parcel = new TetherStatsParcel();
+ parcel.ifIndex = ifIndex;
+ parcel.rxBytes = rxBytes;
+ parcel.rxPackets = rxPackets;
+ parcel.txBytes = txBytes;
+ parcel.txPackets = txPackets;
+ return parcel;
+ }
+
+ private void setTetherOffloadStatsList(TetherStatsParcel[] tetherStatsList) throws Exception {
+ when(mNetd.tetherOffloadGetStats()).thenReturn(tetherStatsList);
+ mTestLooper.moveTimeForward(DEFAULT_PERFORM_POLL_INTERVAL_MS);
+ waitForIdle();
+ }
+
+ @Test
+ public void testGetForwardedStats() throws Exception {
+ setupFunctioningNetdInterface();
+
+ final BpfCoordinator coordinator = makeBpfCoordinator();
+ coordinator.startPolling();
+
+ final String wlanIface = "wlan0";
+ final Integer wlanIfIndex = 100;
+ final String mobileIface = "rmnet_data0";
+ final Integer mobileIfIndex = 101;
+
+ // Add interface name to lookup table. In realistic case, the upstream interface name will
+ // be added by IpServer when IpServer has received with a new IPv6 upstream update event.
+ coordinator.addUpstreamNameToLookupTable(wlanIfIndex, wlanIface);
+ coordinator.addUpstreamNameToLookupTable(mobileIfIndex, mobileIface);
+
+ // [1] Both interface stats are changed.
+ // Setup the tether stats of wlan and mobile interface. Note that move forward the time of
+ // the looper to make sure the new tether stats has been updated by polling update thread.
+ setTetherOffloadStatsList(new TetherStatsParcel[] {
+ buildTestTetherStatsParcel(wlanIfIndex, 1000, 100, 2000, 200),
+ buildTestTetherStatsParcel(mobileIfIndex, 3000, 300, 4000, 400)});
+
+ final NetworkStats expectedIfaceStats = new NetworkStats(0L, 2)
+ .addEntry(buildTestEntry(STATS_PER_IFACE, wlanIface, 1000, 100, 2000, 200))
+ .addEntry(buildTestEntry(STATS_PER_IFACE, mobileIface, 3000, 300, 4000, 400));
+
+ final NetworkStats expectedUidStats = new NetworkStats(0L, 2)
+ .addEntry(buildTestEntry(STATS_PER_UID, wlanIface, 1000, 100, 2000, 200))
+ .addEntry(buildTestEntry(STATS_PER_UID, mobileIface, 3000, 300, 4000, 400));
+
+ // Force pushing stats update to verify the stats reported.
+ // TODO: Perhaps make #expectNotifyStatsUpdated to use test TetherStatsParcel object for
+ // verifying the notification.
+ mTetherStatsProvider.pushTetherStats();
+ mTetherStatsProviderCb.expectNotifyStatsUpdated(expectedIfaceStats, expectedUidStats);
+
+ // [2] Only one interface stats is changed.
+ // The tether stats of mobile interface is accumulated and The tether stats of wlan
+ // interface is the same.
+ setTetherOffloadStatsList(new TetherStatsParcel[] {
+ buildTestTetherStatsParcel(wlanIfIndex, 1000, 100, 2000, 200),
+ buildTestTetherStatsParcel(mobileIfIndex, 3010, 320, 4030, 440)});
+
+ final NetworkStats expectedIfaceStatsDiff = new NetworkStats(0L, 2)
+ .addEntry(buildTestEntry(STATS_PER_IFACE, wlanIface, 0, 0, 0, 0))
+ .addEntry(buildTestEntry(STATS_PER_IFACE, mobileIface, 10, 20, 30, 40));
+
+ final NetworkStats expectedUidStatsDiff = new NetworkStats(0L, 2)
+ .addEntry(buildTestEntry(STATS_PER_UID, wlanIface, 0, 0, 0, 0))
+ .addEntry(buildTestEntry(STATS_PER_UID, mobileIface, 10, 20, 30, 40));
+
+ // Force pushing stats update to verify that only diff of stats is reported.
+ mTetherStatsProvider.pushTetherStats();
+ mTetherStatsProviderCb.expectNotifyStatsUpdated(expectedIfaceStatsDiff,
+ expectedUidStatsDiff);
+
+ // [3] Stop coordinator.
+ // Shutdown the coordinator and clear the invocation history, especially the
+ // tetherOffloadGetStats() calls.
+ coordinator.stopPolling();
+ clearInvocations(mNetd);
+
+ // Verify the polling update thread stopped.
+ mTestLooper.moveTimeForward(DEFAULT_PERFORM_POLL_INTERVAL_MS);
+ waitForIdle();
+ verify(mNetd, never()).tetherOffloadGetStats();
+ }
+
+ @Test
+ public void testOnSetAlert() throws Exception {
+ setupFunctioningNetdInterface();
+
+ final BpfCoordinator coordinator = makeBpfCoordinator();
+ coordinator.startPolling();
+
+ final String mobileIface = "rmnet_data0";
+ final Integer mobileIfIndex = 100;
+ coordinator.addUpstreamNameToLookupTable(mobileIfIndex, mobileIface);
+
+ // Verify that set quota to 0 will immediately triggers a callback.
+ mTetherStatsProvider.onSetAlert(0);
+ waitForIdle();
+ mTetherStatsProviderCb.expectNotifyAlertReached();
+
+ // Verify that notifyAlertReached never fired if quota is not yet reached.
+ when(mNetd.tetherOffloadGetStats()).thenReturn(
+ new TetherStatsParcel[] {buildTestTetherStatsParcel(mobileIfIndex, 0, 0, 0, 0)});
+ mTetherStatsProvider.onSetAlert(100);
+ mTestLooper.moveTimeForward(DEFAULT_PERFORM_POLL_INTERVAL_MS);
+ waitForIdle();
+ mTetherStatsProviderCb.assertNoCallback();
+
+ // Verify that notifyAlertReached fired when quota is reached.
+ when(mNetd.tetherOffloadGetStats()).thenReturn(
+ new TetherStatsParcel[] {buildTestTetherStatsParcel(mobileIfIndex, 50, 0, 50, 0)});
+ mTestLooper.moveTimeForward(DEFAULT_PERFORM_POLL_INTERVAL_MS);
+ waitForIdle();
+ mTetherStatsProviderCb.expectNotifyAlertReached();
+
+ // Verify that set quota with UNLIMITED won't trigger any callback.
+ mTetherStatsProvider.onSetAlert(QUOTA_UNLIMITED);
+ mTestLooper.moveTimeForward(DEFAULT_PERFORM_POLL_INTERVAL_MS);
+ waitForIdle();
+ mTetherStatsProviderCb.assertNoCallback();
+ }
+}
diff --git a/packages/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringNotificationUpdaterTest.kt b/packages/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringNotificationUpdaterTest.kt
index 7d5471f7703d..4b6bbac051e0 100644
--- a/packages/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringNotificationUpdaterTest.kt
+++ b/packages/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringNotificationUpdaterTest.kt
@@ -19,6 +19,10 @@ package com.android.networkstack.tethering
import android.app.Notification
import android.app.NotificationManager
import android.content.Context
+import android.content.pm.ActivityInfo
+import android.content.pm.ApplicationInfo
+import android.content.pm.PackageManager
+import android.content.pm.ResolveInfo
import android.content.res.Resources
import android.net.ConnectivityManager.TETHERING_WIFI
import android.os.Handler
@@ -51,6 +55,7 @@ import org.mockito.ArgumentMatchers.anyInt
import org.mockito.ArgumentMatchers.eq
import org.mockito.Mock
import org.mockito.Mockito.doReturn
+import org.mockito.Mockito.mock
import org.mockito.Mockito.never
import org.mockito.Mockito.reset
import org.mockito.Mockito.times
@@ -351,4 +356,26 @@ class TetheringNotificationUpdaterTest {
notificationUpdater.onUpstreamCapabilitiesChanged(ROAMING_CAPABILITIES)
verifyNotificationCancelled(listOf(NO_UPSTREAM_NOTIFICATION_ID, ROAMING_NOTIFICATION_ID))
}
+
+ @Test
+ fun testGetSettingsPackageName() {
+ val defaultSettingsPackageName = "com.android.settings"
+ val testSettingsPackageName = "com.android.test.settings"
+ val pm = mock(PackageManager::class.java)
+ doReturn(null).`when`(pm).resolveActivity(any(), anyInt())
+ assertEquals(defaultSettingsPackageName,
+ TetheringNotificationUpdater.getSettingsPackageName(pm))
+
+ val resolveInfo = ResolveInfo().apply {
+ activityInfo = ActivityInfo().apply {
+ name = "test"
+ applicationInfo = ApplicationInfo().apply {
+ packageName = testSettingsPackageName
+ }
+ }
+ }
+ doReturn(resolveInfo).`when`(pm).resolveActivity(any(), anyInt())
+ assertEquals(testSettingsPackageName,
+ TetheringNotificationUpdater.getSettingsPackageName(pm))
+ }
}
diff --git a/packages/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringServiceTest.java b/packages/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringServiceTest.java
index f4a566659896..22d894bf471e 100644
--- a/packages/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringServiceTest.java
+++ b/packages/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringServiceTest.java
@@ -274,21 +274,32 @@ public final class TetheringServiceTest {
});
}
+ private void runStartTetheringAndVerifyNoPermission(final TestTetheringResult result)
+ throws Exception {
+ final TetheringRequestParcel request = new TetheringRequestParcel();
+ request.tetheringType = TETHERING_WIFI;
+ request.exemptFromEntitlementCheck = true;
+ mTetheringConnector.startTethering(request, TEST_CALLER_PKG, result);
+ result.assertResult(TETHER_ERROR_NO_CHANGE_TETHERING_PERMISSION);
+ verifyNoMoreInteractionsForTethering();
+ }
+
@Test
- public void testStartTetheringWithExemptFromEntitlementCheck() throws Exception {
+ public void testFailToBypassEntitlementWithoutNeworkStackPermission() throws Exception {
final TetheringRequestParcel request = new TetheringRequestParcel();
request.tetheringType = TETHERING_WIFI;
request.exemptFromEntitlementCheck = true;
+ runAsNoPermission((result) -> {
+ runStartTetheringAndVerifyNoPermission(result);
+ });
+
runAsTetherPrivileged((result) -> {
- runStartTethering(result, request);
- verifyNoMoreInteractionsForTethering();
+ runStartTetheringAndVerifyNoPermission(result);
});
runAsWriteSettings((result) -> {
- mTetheringConnector.startTethering(request, TEST_CALLER_PKG, result);
- result.assertResult(TETHER_ERROR_NO_CHANGE_TETHERING_PERMISSION);
- verifyNoMoreInteractionsForTethering();
+ runStartTetheringAndVerifyNoPermission(result);
});
}
diff --git a/packages/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringTest.java b/packages/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringTest.java
index bb65b18edb8a..8146a58dddcb 100644
--- a/packages/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringTest.java
+++ b/packages/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringTest.java
@@ -203,6 +203,7 @@ public class TetheringTest {
@Mock private ConnectivityManager mCm;
@Mock private EthernetManager mEm;
@Mock private TetheringNotificationUpdater mNotificationUpdater;
+ @Mock private BpfCoordinator mBpfCoordinator;
private final MockIpServerDependencies mIpServerDependencies =
spy(new MockIpServerDependencies());
@@ -337,6 +338,12 @@ public class TetheringTest {
}
@Override
+ public BpfCoordinator getBpfCoordinator(Handler handler, INetd netd,
+ SharedLog log, BpfCoordinator.Dependencies deps) {
+ return mBpfCoordinator;
+ }
+
+ @Override
public OffloadHardwareInterface getOffloadHardwareInterface(Handler h, SharedLog log) {
return mOffloadHardwareInterface;
}
diff --git a/packages/overlays/IconPackCircularLauncherOverlay/res/drawable/ic_select.xml b/packages/overlays/IconPackCircularLauncherOverlay/res/drawable/ic_select.xml
index 4e265fd9c5d5..0f375610865d 100644
--- a/packages/overlays/IconPackCircularLauncherOverlay/res/drawable/ic_select.xml
+++ b/packages/overlays/IconPackCircularLauncherOverlay/res/drawable/ic_select.xml
@@ -18,15 +18,6 @@
android:viewportWidth="24"
android:viewportHeight="24">
<path
- android:fillColor="#FF000000"
- android:pathData="M11.25,1h1.5v3h-1.5z"/>
- <path
- android:fillColor="#FF000000"
- android:pathData="M15.5983,5.3402l2.1213,-2.1213l1.0606,1.0606l-2.1213,2.1213z"/>
- <path
- android:fillColor="#FF000000"
- android:pathData="M5.2187,4.2803l1.0606,-1.0606l2.1213,2.1213l-1.0606,1.0606z"/>
- <path
- android:fillColor="#FF000000"
- android:pathData="M15.5,12.5l-1.25,0V8.12C14.25,6.95 13.3,6 12.12,6S10,6.95 10,8.12v7.9L8.03,15.5c-0.39,-0.1 -1.23,-0.36 -2.56,0.97c-0.29,0.29 -0.29,0.75 -0.01,1.05l3.79,3.98c0,0 0,0 0,0.01c1.37,1.41 3.28,1.51 4.04,1.49l2.2,0c2.12,0.06 5.25,-1.01 5.25,-5.25C20.75,13.19 17.23,12.46 15.5,12.5zM15.5,21.5l-2.25,0c-0.44,0.01 -1.93,-0.02 -2.92,-1.03l-3.27,-3.43c0.17,-0.1 0.38,-0.13 0.58,-0.08l2.91,0.78c0.47,0.12 0.94,-0.23 0.94,-0.72V8.12c0,-0.34 0.28,-0.62 0.62,-0.62s0.62,0.28 0.62,0.62v5.12c0,0.41 0.33,0.75 0.75,0.75l2.05,0c1.26,-0.03 3.7,0.37 3.7,3.75C19.25,21.14 16.78,21.53 15.5,21.5z"/>
+ android:fillColor="@android:color/white"
+ android:pathData="M18.04,13.71c-0.71,-0.77 -1.71,-1.21 -2.76,-1.21h-1.15V8.12C14.13,6.95 13.18,6 12,6S9.88,6.95 9.88,8.12v7.9l-1.44,-0.38c-1.1,-0.29 -2.28,0.02 -3.09,0.83l-0.52,0.52L10.56,23h7.92l0.54,-6.44C19.1,15.52 18.75,14.48 18.04,13.71zM17.1,21.5h-5.9l-4.16,-4.37c0.32,-0.11 0.68,-0.13 1.01,-0.04l3.33,0.89V8.12c0,-0.34 0.28,-0.62 0.62,-0.62s0.62,0.28 0.62,0.62V14h2.65c0.64,0 1.22,0.26 1.66,0.73c0.43,0.47 0.64,1.08 0.59,1.71L17.1,21.5zM2.81,8.25h0.38c0.31,0 0.56,0.26 0.56,0.56v0.38c0,0.31 -0.26,0.56 -0.56,0.56H2.81c-0.31,0 -0.56,-0.26 -0.56,-0.56V8.81C2.25,8.51 2.51,8.25 2.81,8.25zM5.81,8.25h0.38c0.31,0 0.56,0.26 0.56,0.56v0.38c0,0.31 -0.26,0.56 -0.56,0.56H5.81c-0.31,0 -0.56,-0.26 -0.56,-0.56V8.81C5.25,8.51 5.51,8.25 5.81,8.25zM17.81,8.25h0.38c0.31,0 0.56,0.26 0.56,0.56v0.38c0,0.31 -0.26,0.56 -0.56,0.56h-0.38c-0.31,0 -0.56,-0.26 -0.56,-0.56V8.81C17.25,8.51 17.5,8.25 17.81,8.25zM20.81,8.25h0.38c0.31,0 0.56,0.26 0.56,0.56v0.38c0,0.31 -0.26,0.56 -0.56,0.56h-0.38c-0.31,0 -0.56,-0.26 -0.56,-0.56V8.81C20.25,8.51 20.5,8.25 20.81,8.25zM2.81,5.25h0.38c0.31,0 0.56,0.26 0.56,0.56v0.38c0,0.31 -0.26,0.56 -0.56,0.56H2.81c-0.31,0 -0.56,-0.26 -0.56,-0.56V5.81C2.25,5.5 2.51,5.25 2.81,5.25zM20.81,5.25h0.38c0.31,0 0.56,0.26 0.56,0.56v0.38c0,0.31 -0.26,0.56 -0.56,0.56h-0.38c-0.31,0 -0.56,-0.26 -0.56,-0.56V5.81C20.25,5.5 20.5,5.25 20.81,5.25zM2.81,2.25h0.38c0.31,0 0.56,0.26 0.56,0.56v0.38c0,0.31 -0.26,0.56 -0.56,0.56H2.81c-0.31,0 -0.56,-0.26 -0.56,-0.56V2.81C2.25,2.51 2.51,2.25 2.81,2.25zM5.81,2.25h0.38c0.31,0 0.56,0.26 0.56,0.56v0.38c0,0.31 -0.26,0.56 -0.56,0.56H5.81c-0.31,0 -0.56,-0.26 -0.56,-0.56V2.81C5.25,2.51 5.51,2.25 5.81,2.25zM8.81,2.25h0.38c0.31,0 0.56,0.26 0.56,0.56v0.38c0,0.31 -0.26,0.56 -0.56,0.56H8.81c-0.31,0 -0.56,-0.26 -0.56,-0.56V2.81C8.25,2.51 8.51,2.25 8.81,2.25zM11.81,2.25h0.38c0.31,0 0.56,0.26 0.56,0.56v0.38c0,0.31 -0.26,0.56 -0.56,0.56h-0.38c-0.31,0 -0.56,-0.26 -0.56,-0.56V2.81C11.25,2.51 11.51,2.25 11.81,2.25zM14.81,2.25h0.38c0.31,0 0.56,0.26 0.56,0.56v0.38c0,0.31 -0.26,0.56 -0.56,0.56h-0.38c-0.31,0 -0.56,-0.26 -0.56,-0.56V2.81C14.25,2.51 14.51,2.25 14.81,2.25zM17.81,2.25h0.38c0.31,0 0.56,0.26 0.56,0.56v0.38c0,0.31 -0.26,0.56 -0.56,0.56h-0.38c-0.31,0 -0.56,-0.26 -0.56,-0.56V2.81C17.25,2.51 17.5,2.25 17.81,2.25zM17.81,2.25h0.38c0.31,0 0.56,0.26 0.56,0.56v0.38c0,0.31 -0.26,0.56 -0.56,0.56h-0.38c-0.31,0 -0.56,-0.26 -0.56,-0.56V2.81C17.25,2.51 17.5,2.25 17.81,2.25zM20.81,2.25h0.38c0.31,0 0.56,0.26 0.56,0.56v0.38c0,0.31 -0.26,0.56 -0.56,0.56h-0.38c-0.31,0 -0.56,-0.26 -0.56,-0.56V2.81C20.25,2.51 20.5,2.25 20.81,2.25z"/>
</vector>
diff --git a/packages/overlays/IconPackFilledLauncherOverlay/res/drawable/ic_select.xml b/packages/overlays/IconPackFilledLauncherOverlay/res/drawable/ic_select.xml
index df4525d48777..51d4a1183fb9 100644
--- a/packages/overlays/IconPackFilledLauncherOverlay/res/drawable/ic_select.xml
+++ b/packages/overlays/IconPackFilledLauncherOverlay/res/drawable/ic_select.xml
@@ -18,15 +18,6 @@
android:viewportWidth="24"
android:viewportHeight="24">
<path
- android:fillColor="#FF000000"
- android:pathData="M17.59,5.83l0.71,-0.71c0.39,-0.39 0.39,-1.02 0,-1.41l0,0c-0.39,-0.39 -1.02,-0.39 -1.41,0l-0.71,0.71c-0.39,0.39 -0.39,1.02 0,1.41C16.56,6.21 17.2,6.21 17.59,5.83z"/>
- <path
- android:fillColor="#FF000000"
- android:pathData="M12,4c0.55,0 1,-0.45 1,-1V2c0,-0.55 -0.45,-1 -1,-1s-1,0.45 -1,1v1C11,3.55 11.45,4 12,4z"/>
- <path
- android:fillColor="#FF000000"
- android:pathData="M6.42,5.83c0.39,0.39 1.02,0.39 1.41,0c0.39,-0.39 0.39,-1.02 0,-1.41L7.12,3.71c-0.39,-0.39 -1.02,-0.39 -1.41,0l0,0c-0.39,0.39 -0.39,1.02 0,1.41L6.42,5.83z"/>
- <path
- android:fillColor="#FF000000"
- android:pathData="M17.95,14.43l-3.23,-1.61c-0.42,-0.21 -0.88,-0.32 -1.34,-0.32H13v-5C13,6.67 12.33,6 11.5,6C10.67,6 10,6.67 10,7.5v9.12c0,0.32 -0.29,0.55 -0.6,0.49l-2.84,-0.6c-0.37,-0.08 -0.76,0.04 -1.03,0.31c-0.43,0.44 -0.43,1.14 0.01,1.58l3.71,3.71C9.81,22.68 10.58,23 11.37,23h4.82c1.49,0 2.76,-1.1 2.97,-2.58l0.41,-2.89C19.76,16.26 19.1,15.01 17.95,14.43z"/>
+ android:fillColor="@android:color/white"
+ android:pathData="M19.09,14.75L15,12.71c-0.28,-0.14 -0.58,-0.21 -0.89,-0.21H13.5v-5C13.5,6.67 12.83,6 12,6s-1.5,0.67 -1.5,1.5v9.74L7,16.5c-0.33,-0.07 -0.68,0.03 -0.92,0.28l-0.13,0.13c-0.39,0.39 -0.38,1.02 0,1.41l4.09,4.09c0.38,0.38 0.89,0.59 1.42,0.59h6.1c1,0 1.84,-0.73 1.98,-1.72l0.63,-4.46C20.3,15.97 19.86,15.14 19.09,14.75zM2.62,9.75h0.75c0.21,0 0.38,-0.17 0.38,-0.38V8.62c0,-0.21 -0.17,-0.38 -0.38,-0.38H2.62c-0.21,0 -0.38,0.16 -0.38,0.38v0.75C2.25,9.58 2.42,9.75 2.62,9.75zM5.62,9.75h0.75c0.21,0 0.38,-0.17 0.38,-0.38V8.62c0,-0.21 -0.17,-0.38 -0.38,-0.38H5.62c-0.21,0 -0.38,0.16 -0.38,0.38v0.75C5.25,9.58 5.41,9.75 5.62,9.75zM17.62,9.75h0.75c0.21,0 0.38,-0.17 0.38,-0.38V8.62c0,-0.21 -0.17,-0.38 -0.38,-0.38h-0.75c-0.21,0 -0.38,0.16 -0.38,0.38v0.75C17.25,9.58 17.42,9.75 17.62,9.75zM20.62,9.75h0.75c0.21,0 0.38,-0.17 0.38,-0.38V8.62c0,-0.21 -0.17,-0.38 -0.38,-0.38h-0.75c-0.21,0 -0.38,0.16 -0.38,0.38v0.75C20.25,9.58 20.42,9.75 20.62,9.75zM2.62,6.75h0.75c0.21,0 0.38,-0.16 0.38,-0.38V5.62c0,-0.21 -0.17,-0.38 -0.38,-0.38H2.62c-0.21,0 -0.38,0.17 -0.38,0.38v0.75C2.25,6.58 2.42,6.75 2.62,6.75zM20.62,6.75h0.75c0.21,0 0.38,-0.16 0.38,-0.38V5.62c0,-0.21 -0.17,-0.38 -0.38,-0.38h-0.75c-0.21,0 -0.38,0.17 -0.38,0.38v0.75C20.25,6.58 20.42,6.75 20.62,6.75zM2.62,3.75h0.75c0.21,0 0.38,-0.17 0.38,-0.38V2.62c0,-0.21 -0.17,-0.38 -0.38,-0.38H2.62c-0.21,0 -0.38,0.17 -0.38,0.38v0.75C2.25,3.58 2.42,3.75 2.62,3.75zM5.62,3.75h0.75c0.21,0 0.38,-0.17 0.38,-0.38V2.62c0,-0.21 -0.16,-0.38 -0.38,-0.38H5.62c-0.21,0 -0.38,0.17 -0.38,0.38v0.75C5.25,3.58 5.41,3.75 5.62,3.75zM8.62,3.75h0.75c0.21,0 0.38,-0.17 0.38,-0.38V2.62c0,-0.21 -0.16,-0.38 -0.38,-0.38H8.62c-0.21,0 -0.38,0.17 -0.38,0.38v0.75C8.25,3.58 8.41,3.75 8.62,3.75zM14.62,3.75h0.75c0.21,0 0.38,-0.17 0.38,-0.38V2.62c0,-0.21 -0.16,-0.38 -0.38,-0.38h-0.75c-0.21,0 -0.38,0.17 -0.38,0.38v0.75C14.25,3.58 14.41,3.75 14.62,3.75zM17.62,3.75h0.75c0.21,0 0.38,-0.17 0.38,-0.38V2.62c0,-0.21 -0.17,-0.38 -0.38,-0.38h-0.75c-0.21,0 -0.38,0.17 -0.38,0.38v0.75C17.25,3.58 17.42,3.75 17.62,3.75zM20.62,3.75h0.75c0.21,0 0.38,-0.17 0.38,-0.38V2.62c0,-0.21 -0.17,-0.38 -0.38,-0.38h-0.75c-0.21,0 -0.38,0.17 -0.38,0.38v0.75C20.25,3.58 20.42,3.75 20.62,3.75zM11.62,3.75h0.75c0.21,0 0.38,-0.17 0.38,-0.38V2.62c0,-0.21 -0.16,-0.38 -0.38,-0.38h-0.75c-0.21,0 -0.38,0.17 -0.38,0.38v0.75C11.25,3.58 11.41,3.75 11.62,3.75z"/>
</vector>
diff --git a/packages/overlays/IconPackRoundedLauncherOverlay/res/drawable/ic_select.xml b/packages/overlays/IconPackRoundedLauncherOverlay/res/drawable/ic_select.xml
index b699a4444d76..7bd92ef8687a 100644
--- a/packages/overlays/IconPackRoundedLauncherOverlay/res/drawable/ic_select.xml
+++ b/packages/overlays/IconPackRoundedLauncherOverlay/res/drawable/ic_select.xml
@@ -17,16 +17,7 @@
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
- <path
- android:fillColor="#FF000000"
- android:pathData="M16.19,12.5h-1.94V8.12C14.25,6.95 13.3,6 12.12,6S10,6.95 10,8.12v7.9l-3.22,-0.86l-1.82,1.82L10.68,23h8.6l1.57,-7.96L16.19,12.5zM18.04,21.5h-6.72l-4.27,-4.49l0.18,-0.18l4.28,1.14V8.12c0,-0.34 0.28,-0.62 0.62,-0.62s0.62,0.28 0.62,0.62V14h3.06l3.35,1.83L18.04,21.5z"/>
- <path
- android:fillColor="#FF000000"
- android:pathData="M11.25,1h1.5v3h-1.5z"/>
- <path
- android:fillColor="#FF000000"
- android:pathData="M15.5983,5.3402l2.1213,-2.1213l1.0606,1.0606l-2.1213,2.1213z"/>
- <path
- android:fillColor="#FF000000"
- android:pathData="M5.2187,4.2803l1.0606,-1.0606l2.1213,2.1213l-1.0606,1.0606z"/>
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M18.46,14.17l-4.33,-1.46V8.12C14.13,6.95 13.18,6 12,6S9.88,6.95 9.88,8.12v7.9l-2.3,-0.61c-0.57,-0.15 -1.18,0.01 -1.6,0.43c-0.64,0.64 -0.66,1.66 -0.03,2.32l3.79,3.99c0.52,0.54 1.24,0.85 1.99,0.85h5.16c1.31,0 2.44,-0.93 2.7,-2.22l0.69,-3.48C20.54,15.95 19.76,14.6 18.46,14.17zM18.81,17.01l-0.69,3.48c-0.11,0.58 -0.63,1.01 -1.23,1.01h-5.16c-0.34,0 -0.67,-0.14 -0.91,-0.39l-3.8,-3.99c-0.06,-0.06 -0.06,-0.16 0,-0.23c0.03,-0.03 0.07,-0.05 0.11,-0.05c0.01,0 0.03,0 0.04,0.01l3.24,0.86c0.22,0.06 0.46,0.01 0.65,-0.13c0.18,-0.14 0.29,-0.36 0.29,-0.59V8.12c0,-0.34 0.28,-0.62 0.62,-0.62s0.62,0.28 0.62,0.62v5.12c0,0.32 0.21,0.61 0.51,0.71l4.84,1.63C18.57,15.79 18.93,16.4 18.81,17.01zM3.38,8.25H2.62c-0.21,0 -0.38,0.16 -0.38,0.38v0.75c0,0.21 0.16,0.38 0.38,0.38h0.75c0.21,0 0.38,-0.17 0.38,-0.38V8.62C3.75,8.41 3.59,8.25 3.38,8.25zM6.38,8.25H5.62c-0.21,0 -0.38,0.16 -0.38,0.38v0.75c0,0.21 0.16,0.38 0.38,0.38h0.75c0.21,0 0.38,-0.17 0.38,-0.38V8.62C6.75,8.41 6.59,8.25 6.38,8.25zM18.38,8.25h-0.75c-0.21,0 -0.38,0.16 -0.38,0.38v0.75c0,0.21 0.16,0.38 0.38,0.38h0.75c0.21,0 0.38,-0.17 0.38,-0.38V8.62C18.75,8.41 18.59,8.25 18.38,8.25zM21.38,8.25h-0.75c-0.21,0 -0.38,0.16 -0.38,0.38v0.75c0,0.21 0.16,0.38 0.38,0.38h0.75c0.21,0 0.38,-0.17 0.38,-0.38V8.62C21.75,8.41 21.59,8.25 21.38,8.25zM3.38,5.25H2.62c-0.21,0 -0.38,0.16 -0.38,0.38v0.75c0,0.21 0.16,0.38 0.38,0.38h0.75c0.21,0 0.38,-0.17 0.38,-0.38V5.62C3.75,5.41 3.59,5.25 3.38,5.25zM21.38,5.25h-0.75c-0.21,0 -0.38,0.16 -0.38,0.38v0.75c0,0.21 0.16,0.38 0.38,0.38h0.75c0.21,0 0.38,-0.17 0.38,-0.38V5.62C21.75,5.41 21.59,5.25 21.38,5.25zM3.38,2.25H2.62c-0.21,0 -0.38,0.17 -0.38,0.38v0.75c0,0.21 0.16,0.38 0.38,0.38h0.75c0.21,0 0.38,-0.17 0.38,-0.38V2.62C3.75,2.42 3.59,2.25 3.38,2.25zM6.38,2.25H5.62c-0.21,0 -0.38,0.17 -0.38,0.38v0.75c0,0.21 0.16,0.38 0.38,0.38h0.75c0.21,0 0.38,-0.17 0.38,-0.38V2.62C6.75,2.42 6.59,2.25 6.38,2.25zM9.38,2.25H8.62c-0.21,0 -0.38,0.17 -0.38,0.38v0.75c0,0.21 0.16,0.38 0.38,0.38h0.75c0.21,0 0.38,-0.17 0.38,-0.38V2.62C9.75,2.42 9.59,2.25 9.38,2.25zM12.38,2.25h-0.75c-0.21,0 -0.38,0.17 -0.38,0.38v0.75c0,0.21 0.16,0.38 0.38,0.38h0.75c0.21,0 0.38,-0.17 0.38,-0.38V2.62C12.75,2.42 12.59,2.25 12.38,2.25zM15.38,2.25h-0.75c-0.21,0 -0.38,0.17 -0.38,0.38v0.75c0,0.21 0.16,0.38 0.38,0.38h0.75c0.21,0 0.38,-0.17 0.38,-0.38V2.62C15.75,2.42 15.59,2.25 15.38,2.25zM18.38,2.25h-0.75c-0.21,0 -0.38,0.17 -0.38,0.38v0.75c0,0.21 0.16,0.38 0.38,0.38h0.75c0.21,0 0.38,-0.17 0.38,-0.38V2.62C18.75,2.42 18.59,2.25 18.38,2.25zM18.38,2.25h-0.75c-0.21,0 -0.38,0.17 -0.38,0.38v0.75c0,0.21 0.16,0.38 0.38,0.38h0.75c0.21,0 0.38,-0.17 0.38,-0.38V2.62C18.75,2.42 18.59,2.25 18.38,2.25zM21.38,2.25h-0.75c-0.21,0 -0.38,0.17 -0.38,0.38v0.75c0,0.21 0.16,0.38 0.38,0.38h0.75c0.21,0 0.38,-0.17 0.38,-0.38V2.62C21.75,2.42 21.59,2.25 21.38,2.25z" />
</vector>
diff --git a/samples/demo/haptic-assessment/Android.bp b/samples/demo/haptic-assessment/Android.bp
new file mode 100644
index 000000000000..1c006091a755
--- /dev/null
+++ b/samples/demo/haptic-assessment/Android.bp
@@ -0,0 +1,34 @@
+//
+// Copyright (C) 2020 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+android_app {
+ name: "HapticAssessment",
+ manifest: "AndroidManifest.xml",
+ sdk_version: "current",
+ min_sdk_version: "29",
+ srcs: [
+ "src/**/*.java",
+ "src/**/*.kt",
+ ],
+ static_libs: [
+ "androidx.appcompat_appcompat",
+ "androidx-constraintlayout_constraintlayout",
+ ],
+ resource_dirs: [
+ "res",
+ ],
+ dxflags: ["--multi-dex"],
+} \ No newline at end of file
diff --git a/samples/demo/haptic-assessment/AndroidManifest.xml b/samples/demo/haptic-assessment/AndroidManifest.xml
new file mode 100644
index 000000000000..251646eb975e
--- /dev/null
+++ b/samples/demo/haptic-assessment/AndroidManifest.xml
@@ -0,0 +1,38 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ 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.
+ -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.example.android.hapticassessment">
+
+ <uses-sdk android:minSdkVersion="29" android:targetSdkVersion="30"/>
+
+ <uses-permission android:name="android.permission.VIBRATE" />
+
+ <application
+ android:icon="@mipmap/ic_launcher"
+ android:label="@string/app_name"
+ android:roundIcon="@mipmap/ic_launcher_round"
+ android:theme="@style/AppTheme">
+ <activity android:name=".MainActivity">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.LAUNCHER" />
+ </intent-filter>
+ </activity>
+ </application>
+
+</manifest> \ No newline at end of file
diff --git a/samples/demo/haptic-assessment/README.txt b/samples/demo/haptic-assessment/README.txt
new file mode 100644
index 000000000000..8b84cd8c6807
--- /dev/null
+++ b/samples/demo/haptic-assessment/README.txt
@@ -0,0 +1,13 @@
+README
+======
+
+This haptic assessment sample app allows the user to play with three different
+types of VibrationEffects:
+
+1) Predefined click effect with default strength.
+
+2) One shot vibration with 20ms duration at max amplitude.
+
+3) Waveform vibration with 500ms duration at half amplitude, then 500ms duration
+ at max amplitude. This will pass if the device supports vibration amplitude
+ control, and visibly fail otherwise.
diff --git a/samples/demo/haptic-assessment/res/drawable-v24/ic_launcher_foreground.xml b/samples/demo/haptic-assessment/res/drawable-v24/ic_launcher_foreground.xml
new file mode 100644
index 000000000000..134813eb4d68
--- /dev/null
+++ b/samples/demo/haptic-assessment/res/drawable-v24/ic_launcher_foreground.xml
@@ -0,0 +1,46 @@
+<!--
+ ~ 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.
+ -->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:aapt="http://schemas.android.com/aapt"
+ android:width="108dp"
+ android:height="108dp"
+ android:viewportWidth="108"
+ android:viewportHeight="108">
+ <path android:pathData="M31,63.928c0,0 6.4,-11 12.1,-13.1c7.2,-2.6 26,-1.4 26,-1.4l38.1,38.1L107,108.928l-32,-1L31,63.928z">
+ <aapt:attr name="android:fillColor">
+ <gradient
+ android:endX="85.84757"
+ android:endY="92.4963"
+ android:startX="42.9492"
+ android:startY="49.59793"
+ android:type="linear">
+ <item
+ android:color="#44000000"
+ android:offset="0.0" />
+ <item
+ android:color="#00000000"
+ android:offset="1.0" />
+ </gradient>
+ </aapt:attr>
+ </path>
+ <path
+ android:fillColor="#FFFFFF"
+ android:fillType="nonZero"
+ android:pathData="M65.3,45.828l3.8,-6.6c0.2,-0.4 0.1,-0.9 -0.3,-1.1c-0.4,-0.2 -0.9,-0.1 -1.1,0.3l-3.9,6.7c-6.3,-2.8 -13.4,-2.8 -19.7,0l-3.9,-6.7c-0.2,-0.4 -0.7,-0.5 -1.1,-0.3C38.8,38.328 38.7,38.828 38.9,39.228l3.8,6.6C36.2,49.428 31.7,56.028 31,63.928h46C76.3,56.028 71.8,49.428 65.3,45.828zM43.4,57.328c-0.8,0 -1.5,-0.5 -1.8,-1.2c-0.3,-0.7 -0.1,-1.5 0.4,-2.1c0.5,-0.5 1.4,-0.7 2.1,-0.4c0.7,0.3 1.2,1 1.2,1.8C45.3,56.528 44.5,57.328 43.4,57.328L43.4,57.328zM64.6,57.328c-0.8,0 -1.5,-0.5 -1.8,-1.2s-0.1,-1.5 0.4,-2.1c0.5,-0.5 1.4,-0.7 2.1,-0.4c0.7,0.3 1.2,1 1.2,1.8C66.5,56.528 65.6,57.328 64.6,57.328L64.6,57.328z"
+ android:strokeWidth="1"
+ android:strokeColor="#00000000" />
+</vector> \ No newline at end of file
diff --git a/samples/demo/haptic-assessment/res/drawable/bluebar.png b/samples/demo/haptic-assessment/res/drawable/bluebar.png
new file mode 100644
index 000000000000..ae163df4295a
--- /dev/null
+++ b/samples/demo/haptic-assessment/res/drawable/bluebar.png
Binary files differ
diff --git a/samples/demo/haptic-assessment/res/drawable/cross_60x60.gif b/samples/demo/haptic-assessment/res/drawable/cross_60x60.gif
new file mode 100644
index 000000000000..cf3561757e38
--- /dev/null
+++ b/samples/demo/haptic-assessment/res/drawable/cross_60x60.gif
Binary files differ
diff --git a/samples/demo/haptic-assessment/res/drawable/ic_launcher_background.xml b/samples/demo/haptic-assessment/res/drawable/ic_launcher_background.xml
new file mode 100644
index 000000000000..5634f725f245
--- /dev/null
+++ b/samples/demo/haptic-assessment/res/drawable/ic_launcher_background.xml
@@ -0,0 +1,185 @@
+<!--
+ ~ 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.
+ -->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="108dp"
+ android:height="108dp"
+ android:viewportWidth="108"
+ android:viewportHeight="108">
+ <path
+ android:fillColor="#3DDC84"
+ android:pathData="M0,0h108v108h-108z" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M9,0L9,108"
+ android:strokeWidth="0.8"
+ android:strokeColor="#33FFFFFF" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M19,0L19,108"
+ android:strokeWidth="0.8"
+ android:strokeColor="#33FFFFFF" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M29,0L29,108"
+ android:strokeWidth="0.8"
+ android:strokeColor="#33FFFFFF" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M39,0L39,108"
+ android:strokeWidth="0.8"
+ android:strokeColor="#33FFFFFF" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M49,0L49,108"
+ android:strokeWidth="0.8"
+ android:strokeColor="#33FFFFFF" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M59,0L59,108"
+ android:strokeWidth="0.8"
+ android:strokeColor="#33FFFFFF" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M69,0L69,108"
+ android:strokeWidth="0.8"
+ android:strokeColor="#33FFFFFF" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M79,0L79,108"
+ android:strokeWidth="0.8"
+ android:strokeColor="#33FFFFFF" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M89,0L89,108"
+ android:strokeWidth="0.8"
+ android:strokeColor="#33FFFFFF" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M99,0L99,108"
+ android:strokeWidth="0.8"
+ android:strokeColor="#33FFFFFF" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M0,9L108,9"
+ android:strokeWidth="0.8"
+ android:strokeColor="#33FFFFFF" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M0,19L108,19"
+ android:strokeWidth="0.8"
+ android:strokeColor="#33FFFFFF" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M0,29L108,29"
+ android:strokeWidth="0.8"
+ android:strokeColor="#33FFFFFF" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M0,39L108,39"
+ android:strokeWidth="0.8"
+ android:strokeColor="#33FFFFFF" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M0,49L108,49"
+ android:strokeWidth="0.8"
+ android:strokeColor="#33FFFFFF" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M0,59L108,59"
+ android:strokeWidth="0.8"
+ android:strokeColor="#33FFFFFF" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M0,69L108,69"
+ android:strokeWidth="0.8"
+ android:strokeColor="#33FFFFFF" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M0,79L108,79"
+ android:strokeWidth="0.8"
+ android:strokeColor="#33FFFFFF" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M0,89L108,89"
+ android:strokeWidth="0.8"
+ android:strokeColor="#33FFFFFF" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M0,99L108,99"
+ android:strokeWidth="0.8"
+ android:strokeColor="#33FFFFFF" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M19,29L89,29"
+ android:strokeWidth="0.8"
+ android:strokeColor="#33FFFFFF" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M19,39L89,39"
+ android:strokeWidth="0.8"
+ android:strokeColor="#33FFFFFF" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M19,49L89,49"
+ android:strokeWidth="0.8"
+ android:strokeColor="#33FFFFFF" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M19,59L89,59"
+ android:strokeWidth="0.8"
+ android:strokeColor="#33FFFFFF" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M19,69L89,69"
+ android:strokeWidth="0.8"
+ android:strokeColor="#33FFFFFF" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M19,79L89,79"
+ android:strokeWidth="0.8"
+ android:strokeColor="#33FFFFFF" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M29,19L29,89"
+ android:strokeWidth="0.8"
+ android:strokeColor="#33FFFFFF" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M39,19L39,89"
+ android:strokeWidth="0.8"
+ android:strokeColor="#33FFFFFF" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M49,19L49,89"
+ android:strokeWidth="0.8"
+ android:strokeColor="#33FFFFFF" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M59,19L59,89"
+ android:strokeWidth="0.8"
+ android:strokeColor="#33FFFFFF" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M69,19L69,89"
+ android:strokeWidth="0.8"
+ android:strokeColor="#33FFFFFF" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M79,19L79,89"
+ android:strokeWidth="0.8"
+ android:strokeColor="#33FFFFFF" />
+</vector>
diff --git a/samples/demo/haptic-assessment/res/layout/activity_main.xml b/samples/demo/haptic-assessment/res/layout/activity_main.xml
new file mode 100644
index 000000000000..47d45a60a6a4
--- /dev/null
+++ b/samples/demo/haptic-assessment/res/layout/activity_main.xml
@@ -0,0 +1,93 @@
+<!--
+ ~ 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.
+ -->
+
+<androidx.constraintlayout.widget.ConstraintLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:app="http://schemas.android.com/apk/res-auto"
+ xmlns:tools="http://schemas.android.com/tools"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ tools:context=".MainActivity">
+
+ <Button
+ android:id="@+id/click_effect_button"
+ android:layout_width="@dimen/button_width"
+ android:layout_height="@dimen/button_height"
+ android:layout_marginHorizontal="@dimen/button_horizontal_margin"
+ android:layout_marginTop="@dimen/button_vertical_margin"
+ android:text="@string/click_effect_button"
+ app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintTop_toTopOf="parent"/>
+
+ <Button
+ android:id="@+id/oneshot_effect_button"
+ android:layout_width="@dimen/button_width"
+ android:layout_height="@dimen/button_height"
+ android:layout_marginHorizontal="@dimen/button_horizontal_margin"
+ android:layout_marginTop="@dimen/button_vertical_margin"
+ android:text="@string/oneshot_effect_button"
+ app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintTop_toBottomOf="@+id/click_effect_button"/>
+
+ <Button
+ android:id="@+id/waveform_effect_button"
+ android:layout_width="@dimen/button_width"
+ android:layout_height="@dimen/button_height"
+ android:layout_marginHorizontal="@dimen/button_horizontal_margin"
+ android:layout_marginTop="@dimen/button_vertical_margin"
+ android:text="@string/waveform_effect_button"
+ app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintTop_toBottomOf="@+id/oneshot_effect_button"/>
+
+ <View
+ android:id="@+id/divider"
+ android:layout_width="363dp"
+ android:layout_height="1dp"
+ android:layout_marginHorizontal="@dimen/button_horizontal_margin"
+ android:layout_marginTop="10dp"
+ android:background="?android:attr/listDivider"
+ app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintHorizontal_bias="0.5"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintTop_toBottomOf="@+id/waveform_effect_button"/>
+
+ <androidx.constraintlayout.widget.ConstraintLayout
+ android:layout_width="363dp"
+ android:layout_height="0dp"
+ app:layout_constraintBottom_toBottomOf="parent"
+ app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintHorizontal_bias="0.5"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintTop_toBottomOf="@+id/divider">
+
+ <ImageView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:adjustViewBounds="true"
+ android:scaleType="fitXY"
+ app:layout_constraintBottom_toBottomOf="parent"
+ app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintHorizontal_bias="0.5"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintTop_toTopOf="parent"
+ app:srcCompat="@drawable/bluebar"/>
+
+ </androidx.constraintlayout.widget.ConstraintLayout>
+
+</androidx.constraintlayout.widget.ConstraintLayout> \ No newline at end of file
diff --git a/samples/demo/haptic-assessment/res/mipmap-anydpi-v26/ic_launcher.xml b/samples/demo/haptic-assessment/res/mipmap-anydpi-v26/ic_launcher.xml
new file mode 100644
index 000000000000..47606a49580f
--- /dev/null
+++ b/samples/demo/haptic-assessment/res/mipmap-anydpi-v26/ic_launcher.xml
@@ -0,0 +1,20 @@
+<!--
+ ~ 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.
+ -->
+
+<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
+ <background android:drawable="@drawable/ic_launcher_background" />
+ <foreground android:drawable="@drawable/ic_launcher_foreground" />
+</adaptive-icon> \ No newline at end of file
diff --git a/samples/demo/haptic-assessment/res/mipmap-anydpi-v26/ic_launcher_round.xml b/samples/demo/haptic-assessment/res/mipmap-anydpi-v26/ic_launcher_round.xml
new file mode 100644
index 000000000000..47606a49580f
--- /dev/null
+++ b/samples/demo/haptic-assessment/res/mipmap-anydpi-v26/ic_launcher_round.xml
@@ -0,0 +1,20 @@
+<!--
+ ~ 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.
+ -->
+
+<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
+ <background android:drawable="@drawable/ic_launcher_background" />
+ <foreground android:drawable="@drawable/ic_launcher_foreground" />
+</adaptive-icon> \ No newline at end of file
diff --git a/samples/demo/haptic-assessment/res/mipmap-hdpi/ic_launcher.png b/samples/demo/haptic-assessment/res/mipmap-hdpi/ic_launcher.png
new file mode 100644
index 000000000000..a571e60098c9
--- /dev/null
+++ b/samples/demo/haptic-assessment/res/mipmap-hdpi/ic_launcher.png
Binary files differ
diff --git a/samples/demo/haptic-assessment/res/mipmap-hdpi/ic_launcher_round.png b/samples/demo/haptic-assessment/res/mipmap-hdpi/ic_launcher_round.png
new file mode 100644
index 000000000000..61da551c5594
--- /dev/null
+++ b/samples/demo/haptic-assessment/res/mipmap-hdpi/ic_launcher_round.png
Binary files differ
diff --git a/samples/demo/haptic-assessment/res/mipmap-mdpi/ic_launcher.png b/samples/demo/haptic-assessment/res/mipmap-mdpi/ic_launcher.png
new file mode 100644
index 000000000000..c41dd2853190
--- /dev/null
+++ b/samples/demo/haptic-assessment/res/mipmap-mdpi/ic_launcher.png
Binary files differ
diff --git a/samples/demo/haptic-assessment/res/mipmap-mdpi/ic_launcher_round.png b/samples/demo/haptic-assessment/res/mipmap-mdpi/ic_launcher_round.png
new file mode 100644
index 000000000000..db5080a75273
--- /dev/null
+++ b/samples/demo/haptic-assessment/res/mipmap-mdpi/ic_launcher_round.png
Binary files differ
diff --git a/samples/demo/haptic-assessment/res/mipmap-xhdpi/ic_launcher.png b/samples/demo/haptic-assessment/res/mipmap-xhdpi/ic_launcher.png
new file mode 100644
index 000000000000..6dba46dab192
--- /dev/null
+++ b/samples/demo/haptic-assessment/res/mipmap-xhdpi/ic_launcher.png
Binary files differ
diff --git a/samples/demo/haptic-assessment/res/mipmap-xhdpi/ic_launcher_round.png b/samples/demo/haptic-assessment/res/mipmap-xhdpi/ic_launcher_round.png
new file mode 100644
index 000000000000..da31a871c8dc
--- /dev/null
+++ b/samples/demo/haptic-assessment/res/mipmap-xhdpi/ic_launcher_round.png
Binary files differ
diff --git a/samples/demo/haptic-assessment/res/mipmap-xxhdpi/ic_launcher.png b/samples/demo/haptic-assessment/res/mipmap-xxhdpi/ic_launcher.png
new file mode 100644
index 000000000000..15ac681720f3
--- /dev/null
+++ b/samples/demo/haptic-assessment/res/mipmap-xxhdpi/ic_launcher.png
Binary files differ
diff --git a/samples/demo/haptic-assessment/res/mipmap-xxhdpi/ic_launcher_round.png b/samples/demo/haptic-assessment/res/mipmap-xxhdpi/ic_launcher_round.png
new file mode 100644
index 000000000000..b216f2d313cc
--- /dev/null
+++ b/samples/demo/haptic-assessment/res/mipmap-xxhdpi/ic_launcher_round.png
Binary files differ
diff --git a/samples/demo/haptic-assessment/res/mipmap-xxxhdpi/ic_launcher.png b/samples/demo/haptic-assessment/res/mipmap-xxxhdpi/ic_launcher.png
new file mode 100644
index 000000000000..f25a41974472
--- /dev/null
+++ b/samples/demo/haptic-assessment/res/mipmap-xxxhdpi/ic_launcher.png
Binary files differ
diff --git a/samples/demo/haptic-assessment/res/mipmap-xxxhdpi/ic_launcher_round.png b/samples/demo/haptic-assessment/res/mipmap-xxxhdpi/ic_launcher_round.png
new file mode 100644
index 000000000000..e96783ccce84
--- /dev/null
+++ b/samples/demo/haptic-assessment/res/mipmap-xxxhdpi/ic_launcher_round.png
Binary files differ
diff --git a/samples/demo/haptic-assessment/res/values/colors.xml b/samples/demo/haptic-assessment/res/values/colors.xml
new file mode 100644
index 000000000000..2883b95397a2
--- /dev/null
+++ b/samples/demo/haptic-assessment/res/values/colors.xml
@@ -0,0 +1,21 @@
+<!--
+ ~ 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.
+ -->
+
+<resources>
+ <color name="colorPrimary">#009688</color>
+ <color name="colorPrimaryDark">#673AB7</color>
+ <color name="colorAccent">#03DAC5</color>
+</resources>
diff --git a/samples/demo/haptic-assessment/res/values/dimen.xml b/samples/demo/haptic-assessment/res/values/dimen.xml
new file mode 100644
index 000000000000..f9090ed39568
--- /dev/null
+++ b/samples/demo/haptic-assessment/res/values/dimen.xml
@@ -0,0 +1,25 @@
+<!--
+ ~ 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.
+ -->
+
+<resources>
+ <dimen name="activity_horizontal_margin">16dp</dimen>
+ <dimen name="activity_vertical_margin">16dp</dimen>
+ <dimen name="button_width">350dp</dimen>
+ <dimen name="button_height">60dp</dimen>
+ <dimen name="button_horizontal_margin">32dp</dimen>
+ <dimen name="button_vertical_margin">5dp</dimen>
+ <dimen name="fab_margin">16dp</dimen>
+</resources>
diff --git a/samples/demo/haptic-assessment/res/values/strings.xml b/samples/demo/haptic-assessment/res/values/strings.xml
new file mode 100644
index 000000000000..a22d8dbe0580
--- /dev/null
+++ b/samples/demo/haptic-assessment/res/values/strings.xml
@@ -0,0 +1,24 @@
+<!--
+ ~ 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.
+ -->
+
+<resources>
+ <string name="app_name">Haptic Hardware Assessment 2020</string>
+ <string name="click_effect_button">Effect 1</string>
+ <string name="oneshot_effect_button">Effect 2</string>
+ <string name="waveform_effect_button">Effect 3</string>
+ <string name="button_3_pass">Effect 3: PASS</string>
+ <string name="button_3_fail">Effect 3: FAIL</string>
+</resources>
diff --git a/samples/demo/haptic-assessment/res/values/styles.xml b/samples/demo/haptic-assessment/res/values/styles.xml
new file mode 100644
index 000000000000..1abcab1d2dc9
--- /dev/null
+++ b/samples/demo/haptic-assessment/res/values/styles.xml
@@ -0,0 +1,28 @@
+<!--
+ ~ 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.
+ -->
+
+<resources>
+ <style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
+ <item name="android:buttonStyle">@style/AppButton</item>
+ <item name="colorPrimary">@color/colorPrimary</item>
+ <item name="colorPrimaryDark">@color/colorPrimaryDark</item>
+ <item name="colorAccent">@color/colorAccent</item>
+ </style>
+
+ <style name="AppButton" parent="@android:style/Widget.Button">
+ <item name="android:textSize">18sp</item>
+ </style>
+</resources>
diff --git a/samples/demo/haptic-assessment/src/com/example/android/hapticassessment/MainActivity.kt b/samples/demo/haptic-assessment/src/com/example/android/hapticassessment/MainActivity.kt
new file mode 100644
index 000000000000..d198b51b935c
--- /dev/null
+++ b/samples/demo/haptic-assessment/src/com/example/android/hapticassessment/MainActivity.kt
@@ -0,0 +1,71 @@
+/*
+ * 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.example.android.hapticassessment
+
+import android.graphics.Color
+import android.os.Bundle
+import android.os.VibrationEffect
+import android.os.VibrationEffect.EFFECT_CLICK
+import android.os.Vibrator
+import android.view.View
+import android.widget.Button
+
+import androidx.appcompat.app.AppCompatActivity
+
+/** App main screen. */
+class MainActivity : AppCompatActivity() {
+
+ companion object {
+
+ private const val ONE_SHOT_TIMING = 20L
+ private const val ONE_SHOT_AMPLITUDE = 255
+
+ private val WAVEFORM_TIMINGS = longArrayOf(500, 500)
+ private val WAVEFORM_AMPLITUDES = intArrayOf(128, 255)
+ }
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ setContentView(R.layout.activity_main)
+
+ val vibrator = getSystemService(Vibrator::class.java)
+
+ findViewById<Button>(R.id.click_effect_button).setOnClickListener {
+ vibrator.vibrate(VibrationEffect.createPredefined(EFFECT_CLICK))
+ }
+
+ findViewById<Button>(R.id.oneshot_effect_button).setOnClickListener {
+ vibrator.vibrate(VibrationEffect.createOneShot(ONE_SHOT_TIMING, ONE_SHOT_AMPLITUDE))
+ }
+
+ findViewById<Button>(R.id.waveform_effect_button).setOnClickListener { view: View ->
+ vibrator.vibrate(
+ VibrationEffect.createWaveform(WAVEFORM_TIMINGS, WAVEFORM_AMPLITUDES, -1))
+
+ val button = view as Button
+ if (vibrator.hasAmplitudeControl()) {
+ button.text = getString(R.string.button_3_pass)
+ button.setBackgroundColor(Color.GREEN)
+ button.setTextColor(Color.BLACK)
+ } else {
+ button.text = getString(R.string.button_3_fail)
+ button.setBackgroundColor(Color.RED)
+ button.setTextColor(Color.WHITE)
+ }
+ }
+ }
+}
diff --git a/services/Android.bp b/services/Android.bp
index 882085a7d0ba..00676e332656 100644
--- a/services/Android.bp
+++ b/services/Android.bp
@@ -87,7 +87,7 @@ java_library {
libs: [
"android.hidl.manager-V1.0-java",
- "framework-tethering-stubs-module_libs_api",
+ "framework-tethering.stubs.module_lib",
],
// Uncomment to enable output of certain warnings (deprecated, unchecked)
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityWindowManager.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityWindowManager.java
index 468e93a8f683..d15c60b9501d 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityWindowManager.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityWindowManager.java
@@ -725,7 +725,8 @@ public class AccessibilityWindowManager {
case WindowManager.LayoutParams.TYPE_SYSTEM_ERROR:
case WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY:
case WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY:
- case WindowManager.LayoutParams.TYPE_SCREENSHOT: {
+ case WindowManager.LayoutParams.TYPE_SCREENSHOT:
+ case WindowManager.LayoutParams.TYPE_TRUSTED_APPLICATION_OVERLAY: {
return AccessibilityWindowInfo.TYPE_SYSTEM;
}
diff --git a/services/autofill/java/com/android/server/autofill/AutofillInlineSessionController.java b/services/autofill/java/com/android/server/autofill/AutofillInlineSessionController.java
index e2330ca6ffe9..0ec8654f2a20 100644
--- a/services/autofill/java/com/android/server/autofill/AutofillInlineSessionController.java
+++ b/services/autofill/java/com/android/server/autofill/AutofillInlineSessionController.java
@@ -75,9 +75,7 @@ final class AutofillInlineSessionController {
@NonNull Consumer<InlineSuggestionsRequest> requestConsumer, @NonNull Bundle uiExtras) {
// TODO(b/151123764): rename the method to better reflect what it does.
if (mSession != null) {
- // Send an empty response to IME and destroy the existing session.
- mSession.onInlineSuggestionsResponseLocked(
- InlineFillUi.emptyUi(mSession.getAutofillIdLocked()));
+ // Destroy the existing session.
mSession.destroySessionLocked();
mInlineFillUi = null;
}
diff --git a/services/autofill/java/com/android/server/autofill/AutofillInlineSuggestionsRequestSession.java b/services/autofill/java/com/android/server/autofill/AutofillInlineSuggestionsRequestSession.java
index 687b75a8b949..48895ad42e99 100644
--- a/services/autofill/java/com/android/server/autofill/AutofillInlineSuggestionsRequestSession.java
+++ b/services/autofill/java/com/android/server/autofill/AutofillInlineSuggestionsRequestSession.java
@@ -40,7 +40,6 @@ import com.android.server.autofill.ui.InlineFillUi;
import com.android.server.inputmethod.InputMethodManagerInternal;
import java.lang.ref.WeakReference;
-import java.util.Collections;
import java.util.Optional;
import java.util.function.Consumer;
@@ -94,7 +93,7 @@ final class AutofillInlineSuggestionsRequestSession {
@Nullable
private InlineFillUi mInlineFillUi;
@GuardedBy("mLock")
- private boolean mPreviousResponseIsNotEmpty;
+ private Boolean mPreviousResponseIsNotEmpty = null;
@GuardedBy("mLock")
private boolean mDestroyed = false;
@@ -209,21 +208,12 @@ final class AutofillInlineSuggestionsRequestSession {
if (mDestroyed || mResponseCallback == null) {
return;
}
- if (!mImeInputStarted && mPreviousResponseIsNotEmpty) {
- // 1. if previous response is not empty, and IME is just disconnected from the view,
- // then send empty response to make sure existing responses don't stick around.
- // Although the inline suggestions should disappear when IME hides which removes them
- // from the view hierarchy, but we still send an empty response to indicate that the
- // previous suggestions are invalid now.
- if (sVerbose) Slog.v(TAG, "Send empty inline response");
- updateResponseToImeUncheckLocked(new InlineSuggestionsResponse(Collections.EMPTY_LIST));
- mPreviousResponseIsNotEmpty = false;
- } else if (mImeInputViewStarted && mInlineFillUi != null && match(mAutofillId,
+ if (mImeInputViewStarted && mInlineFillUi != null && match(mAutofillId,
mImeCurrentFieldId)) {
- // 2. if IME is visible, and response is not null, send the response
+ // if IME is visible, and response is not null, send the response
InlineSuggestionsResponse response = mInlineFillUi.getInlineSuggestionsResponse();
boolean isEmptyResponse = response.getInlineSuggestions().isEmpty();
- if (isEmptyResponse && !mPreviousResponseIsNotEmpty) {
+ if (isEmptyResponse && Boolean.FALSE.equals(mPreviousResponseIsNotEmpty)) {
// No-op if both the previous response and current response are empty.
return;
}
diff --git a/services/autofill/java/com/android/server/autofill/AutofillManagerService.java b/services/autofill/java/com/android/server/autofill/AutofillManagerService.java
index 42e859f9d713..089861bee479 100644
--- a/services/autofill/java/com/android/server/autofill/AutofillManagerService.java
+++ b/services/autofill/java/com/android/server/autofill/AutofillManagerService.java
@@ -192,7 +192,7 @@ public final class AutofillManagerService
public AutofillManagerService(Context context) {
super(context,
new SecureSettingsServiceNameResolver(context, Settings.Secure.AUTOFILL_SERVICE),
- UserManager.DISALLOW_AUTOFILL);
+ UserManager.DISALLOW_AUTOFILL, PACKAGE_UPDATE_POLICY_REFRESH_EAGER);
mUi = new AutoFillUI(ActivityThread.currentActivityThread().getSystemUiContext());
mAm = LocalServices.getService(ActivityManagerInternal.class);
diff --git a/services/autofill/java/com/android/server/autofill/RemoteAugmentedAutofillService.java b/services/autofill/java/com/android/server/autofill/RemoteAugmentedAutofillService.java
index 851e4cc0bfd1..a7d0061cc043 100644
--- a/services/autofill/java/com/android/server/autofill/RemoteAugmentedAutofillService.java
+++ b/services/autofill/java/com/android/server/autofill/RemoteAugmentedAutofillService.java
@@ -245,6 +245,11 @@ final class RemoteAugmentedAutofillService
if (inlineSuggestionsData == null || inlineSuggestionsData.isEmpty()
|| inlineSuggestionsCallback == null || request == null
|| remoteRenderService == null) {
+ // If it was an inline request and the response doesn't have any inline suggestions,
+ // we will send an empty response to IME.
+ if (inlineSuggestionsCallback != null && request != null) {
+ inlineSuggestionsCallback.apply(InlineFillUi.emptyUi(focusedId));
+ }
return;
}
mCallbacks.setLastResponse(sessionId);
diff --git a/services/autofill/java/com/android/server/autofill/Session.java b/services/autofill/java/com/android/server/autofill/Session.java
index ffdb9c83c805..a9a0ab69f633 100644
--- a/services/autofill/java/com/android/server/autofill/Session.java
+++ b/services/autofill/java/com/android/server/autofill/Session.java
@@ -2715,7 +2715,9 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
final ViewState currentView = mViewStates.get(mCurrentViewId);
currentView.maybeCallOnFillReady(flags);
}
- } else if (viewState.id.equals(this.mCurrentViewId)
+ }
+
+ if (viewState.id.equals(this.mCurrentViewId)
&& (viewState.getState() & ViewState.STATE_INLINE_SHOWN) != 0) {
if ((viewState.getState() & ViewState.STATE_INLINE_DISABLED) != 0) {
mInlineSessionController.disableFilterMatching(viewState.id);
@@ -3852,6 +3854,7 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
for (int i = 0; i < responseCount; i++) {
if (mResponses.keyAt(i) > lastResponseId) {
lastResponseIdx = i;
+ lastResponseId = mResponses.keyAt(i);
}
}
}
diff --git a/services/core/Android.bp b/services/core/Android.bp
index a95a0c2eaf28..65e98ac8e684 100644
--- a/services/core/Android.bp
+++ b/services/core/Android.bp
@@ -99,8 +99,8 @@ java_library_static {
"android.hardware.vibrator-java",
"android.net.ipsec.ike.stubs.module_lib",
"app-compat-annotations",
- "framework-tethering-stubs-module_libs_api",
- "service-permission-stubs",
+ "framework-tethering.stubs.module_lib",
+ "service-permission.stubs.system_server",
],
required: [
diff --git a/services/core/java/android/content/pm/PackageManagerInternal.java b/services/core/java/android/content/pm/PackageManagerInternal.java
index 81de29c4ee4d..b241bd16d3ee 100644
--- a/services/core/java/android/content/pm/PackageManagerInternal.java
+++ b/services/core/java/android/content/pm/PackageManagerInternal.java
@@ -988,4 +988,14 @@ public abstract class PackageManagerInternal {
* Unblocks uninstall for all packages for the user.
*/
public abstract void clearBlockUninstallForUser(@UserIdInt int userId);
+
+ /**
+ * Unsuspends all packages suspended by the given package for the user.
+ */
+ public abstract void unsuspendForSuspendingPackage(String suspendingPackage, int userId);
+
+ /**
+ * Returns {@code true} if the package is suspending any packages for the user.
+ */
+ public abstract boolean isSuspendingAnyPackages(String suspendingPackage, int userId);
}
diff --git a/services/core/java/com/android/server/AppStateTracker.java b/services/core/java/com/android/server/AppStateTracker.java
index b765d81d42b7..74f79e0d40f5 100644
--- a/services/core/java/com/android/server/AppStateTracker.java
+++ b/services/core/java/com/android/server/AppStateTracker.java
@@ -1120,7 +1120,8 @@ public class AppStateTracker {
return false;
}
final int userId = UserHandle.getUserId(uid);
- if (mExemptedPackages.contains(userId, packageName)) {
+ if (mAppStandbyInternal.isAppIdleEnabled() && !mAppStandbyInternal.isInParole()
+ && mExemptedPackages.contains(userId, packageName)) {
return false;
}
return mForceAllAppsStandby;
diff --git a/services/core/java/com/android/server/BluetoothManagerService.java b/services/core/java/com/android/server/BluetoothManagerService.java
index 3c0d880916ee..0d4efed25da3 100644
--- a/services/core/java/com/android/server/BluetoothManagerService.java
+++ b/services/core/java/com/android/server/BluetoothManagerService.java
@@ -954,7 +954,8 @@ class BluetoothManagerService extends IBluetoothManager.Stub {
}
/**
- * Call IBluetooth.onLeServiceUp() to continue if Bluetooth should be on.
+ * Call IBluetooth.onLeServiceUp() to continue if Bluetooth should be on,
+ * call IBluetooth.onBrEdrDown() to disable if Bluetooth should be off.
*/
private void continueFromBleOnState() {
if (DBG) {
@@ -966,11 +967,10 @@ class BluetoothManagerService extends IBluetoothManager.Stub {
Slog.e(TAG, "onBluetoothServiceUp: mBluetooth is null!");
return;
}
- if (!mEnableExternal && !isBleAppPresent() && isAirplaneModeOn()) {
- // Airplane mode is turned on while enabling BLE only mode, disable
- // BLE now.
- disableBleScanMode();
- sendBrEdrDownCallback();
+ if (!mEnableExternal && !isBleAppPresent()) {
+ Slog.i(TAG, "Bluetooth was disabled while enabling BLE, disable BLE now");
+ mEnable = false;
+ mBluetooth.onBrEdrDown();
return;
}
if (isBluetoothPersistedStateOnBluetooth() || !isBleAppPresent()) {
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index 1634f6e62897..0ab571854c72 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -1374,10 +1374,9 @@ public class ConnectivityService extends IConnectivityManager.Stub
if (nri == null || net == null || !LOGD_BLOCKED_NETWORKINFO) {
return;
}
- String action = blocked ? "BLOCKED" : "UNBLOCKED";
- log(String.format("Blocked status changed to %s for %d(%d) on netId %d", blocked,
- nri.mUid, nri.request.requestId, net.netId));
- mNetworkInfoBlockingLogs.log(action + " " + nri.mUid);
+ final String action = blocked ? "BLOCKED" : "UNBLOCKED";
+ mNetworkInfoBlockingLogs.log(String.format(
+ "%s %d(%d) on netId %d", action, nri.mUid, nri.request.requestId, net.netId));
}
/**
diff --git a/services/core/java/com/android/server/PackageWatchdog.java b/services/core/java/com/android/server/PackageWatchdog.java
index e77458cc955a..fd7abfa65c86 100644
--- a/services/core/java/com/android/server/PackageWatchdog.java
+++ b/services/core/java/com/android/server/PackageWatchdog.java
@@ -239,7 +239,10 @@ public class PackageWatchdog {
mIsPackagesReady = true;
mHealthCheckController.setCallbacks(packageName -> onHealthCheckPassed(packageName),
packages -> onSupportedPackages(packages),
- () -> syncRequestsAsync());
+ () -> {
+ syncRequestsAsync();
+ mSyncRequired = true;
+ });
setPropertyChangedListenerLocked();
updateConfigs();
registerConnectivityModuleHealthListener();
@@ -255,7 +258,6 @@ public class PackageWatchdog {
*/
public void registerHealthObserver(PackageHealthObserver observer) {
synchronized (mLock) {
- mSyncRequired = true;
ObserverInternal internalObserver = mAllObservers.get(observer.getName());
if (internalObserver != null) {
internalObserver.registeredObserver = observer;
@@ -642,7 +644,8 @@ public class PackageWatchdog {
synchronized (mLock) {
if (mIsPackagesReady) {
Set<String> packages = getPackagesPendingHealthChecksLocked();
- if (!packages.equals(mRequestedHealthCheckPackages) || mSyncRequired) {
+ if (mSyncRequired || !packages.equals(mRequestedHealthCheckPackages)
+ || packages.isEmpty()) {
syncRequired = true;
mRequestedHealthCheckPackages = packages;
}
diff --git a/services/core/java/com/android/server/StorageManagerService.java b/services/core/java/com/android/server/StorageManagerService.java
index b5aec8e401eb..1ce3dfe9f3a0 100644
--- a/services/core/java/com/android/server/StorageManagerService.java
+++ b/services/core/java/com/android/server/StorageManagerService.java
@@ -157,7 +157,6 @@ import com.android.internal.util.IndentingPrintWriter;
import com.android.internal.util.Preconditions;
import com.android.internal.widget.LockPatternUtils;
import com.android.server.pm.Installer;
-import com.android.server.pm.parsing.pkg.AndroidPackage;
import com.android.server.storage.AppFuseBridge;
import com.android.server.storage.StorageSessionController;
import com.android.server.storage.StorageSessionController.ExternalStorageServiceException;
@@ -3343,15 +3342,23 @@ class StorageManagerService extends IStorageManager.Stub
public void fixupAppDir(String path) {
final Matcher matcher = KNOWN_APP_DIR_PATHS.matcher(path);
if (matcher.matches()) {
- AndroidPackage pkg = mPmInternal.getPackage(matcher.group(3));
- if (pkg != null) {
+ if (matcher.group(2) == null) {
+ Log.e(TAG, "Asked to fixup an app dir without a userId: " + path);
+ return;
+ }
+ try {
+ int userId = Integer.parseInt(matcher.group(2));
+ String packageName = matcher.group(3);
+ int uid = mContext.getPackageManager().getPackageUidAsUser(packageName, userId);
try {
- mVold.fixupAppDir(path + "/", pkg.getUid());
+ mVold.fixupAppDir(path + "/", uid);
} catch (RemoteException | ServiceSpecificException e) {
- Log.e(TAG, "Failed to fixup app dir for " + pkg.getPackageName(), e);
+ Log.e(TAG, "Failed to fixup app dir for " + packageName, e);
}
- } else {
- Log.e(TAG, "Can't find package belonging to " + path);
+ } catch (NumberFormatException e) {
+ Log.e(TAG, "Invalid userId in path: " + path, e);
+ } catch (PackageManager.NameNotFoundException e) {
+ Log.e(TAG, "Couldn't find package to fixup app dir " + path, e);
}
} else {
Log.e(TAG, "Path " + path + " is not a valid application-specific directory");
@@ -4657,9 +4664,8 @@ class StorageManagerService extends IStorageManager.Stub
private void killAppForOpChange(int code, int uid, String packageName) {
final IActivityManager am = ActivityManager.getService();
try {
- am.killApplication(packageName,
- UserHandle.getAppId(uid),
- UserHandle.USER_ALL, AppOpsManager.opToName(code) + " changed.");
+ am.killUid(UserHandle.getAppId(uid), UserHandle.USER_ALL,
+ AppOpsManager.opToName(code) + " changed.");
} catch (RemoteException e) {
}
}
@@ -4681,7 +4687,12 @@ class StorageManagerService extends IStorageManager.Stub
// results in a bad UX, especially since the gid only gives access
// to unreliable volumes, USB OTGs that are rarely mounted. The app
// will get the external_storage gid on next organic restart.
- killAppForOpChange(code, uid, packageName);
+ if (packageName != null) {
+ killAppForOpChange(code, uid, packageName);
+ } else {
+ // TODO(b/158283222) this can happen, figure out if we need
+ // to kill in this case as well.
+ }
}
return;
case OP_LEGACY_STORAGE:
diff --git a/services/core/java/com/android/server/SystemServiceManager.java b/services/core/java/com/android/server/SystemServiceManager.java
index 197a2cef0a62..74bb7d7e90f1 100644
--- a/services/core/java/com/android/server/SystemServiceManager.java
+++ b/services/core/java/com/android/server/SystemServiceManager.java
@@ -198,12 +198,12 @@ public class SystemServiceManager {
Slog.i(TAG, "Starting phase " + mCurrentPhase);
try {
- t.traceBegin("OnBootPhase " + phase);
+ t.traceBegin("OnBootPhase_" + phase);
final int serviceLen = mServices.size();
for (int i = 0; i < serviceLen; i++) {
final SystemService service = mServices.get(i);
long time = SystemClock.elapsedRealtime();
- t.traceBegin("OnBootPhase " + service.getClass().getName());
+ t.traceBegin("OnBootPhase_" + phase + "_" + service.getClass().getName());
try {
service.onBootPhase(mCurrentPhase);
} catch (Exception ex) {
@@ -332,7 +332,7 @@ public class SystemServiceManager {
}
continue;
}
- t.traceBegin("ssm.on" + onWhat + "User-" + curUserId + " " + serviceName);
+ t.traceBegin("ssm.on" + onWhat + "User-" + curUserId + "_" + serviceName);
long time = SystemClock.elapsedRealtime();
try {
switch (onWhat) {
diff --git a/services/core/java/com/android/server/VibratorService.java b/services/core/java/com/android/server/VibratorService.java
index e066d99147ba..a153d4191a5c 100644
--- a/services/core/java/com/android/server/VibratorService.java
+++ b/services/core/java/com/android/server/VibratorService.java
@@ -1894,6 +1894,8 @@ public class VibratorService extends IVibratorService.Stub
return runWaveform();
} else if ("prebaked".equals(cmd)) {
return runPrebaked();
+ } else if ("capabilities".equals(cmd)) {
+ return runCapabilities();
} else if ("cancel".equals(cmd)) {
cancelVibrate(mToken);
return 0;
@@ -2016,10 +2018,15 @@ public class VibratorService extends IVibratorService.Stub
Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "runPrebaked");
try {
CommonOptions commonOptions = new CommonOptions();
+ boolean shouldFallback = false;
String opt;
while ((opt = getNextOption()) != null) {
- commonOptions.check(opt);
+ if ("-b".equals(opt)) {
+ shouldFallback = true;
+ } else {
+ commonOptions.check(opt);
+ }
}
if (checkDoNotDisturb(commonOptions)) {
@@ -2033,8 +2040,7 @@ public class VibratorService extends IVibratorService.Stub
description = "Shell command";
}
- VibrationEffect effect =
- VibrationEffect.get(id, false);
+ VibrationEffect effect = VibrationEffect.get(id, shouldFallback);
VibrationAttributes attrs = createVibrationAttributes(commonOptions);
vibrate(Binder.getCallingUid(), description, effect, attrs, "Shell Command",
mToken);
@@ -2044,12 +2050,39 @@ public class VibratorService extends IVibratorService.Stub
}
}
+ private int runCapabilities() {
+ Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "runCapabilities");
+ try (PrintWriter pw = getOutPrintWriter();) {
+ pw.println("Vibrator capabilities:");
+ if (hasCapability(IVibrator.CAP_ALWAYS_ON_CONTROL)) {
+ pw.println(" Always on effects");
+ }
+ if (hasCapability(IVibrator.CAP_COMPOSE_EFFECTS)) {
+ pw.println(" Compose effects");
+ }
+ if (mSupportsAmplitudeControl || hasCapability(IVibrator.CAP_AMPLITUDE_CONTROL)) {
+ pw.println(" Amplitude control");
+ }
+ if (mSupportsExternalControl || hasCapability(IVibrator.CAP_EXTERNAL_CONTROL)) {
+ pw.println(" External control");
+ }
+ if (hasCapability(IVibrator.CAP_EXTERNAL_AMPLITUDE_CONTROL)) {
+ pw.println(" External amplitude control");
+ }
+ pw.println("");
+ return 0;
+ } finally {
+ Trace.traceEnd(Trace.TRACE_TAG_VIBRATOR);
+ }
+ }
+
private VibrationAttributes createVibrationAttributes(CommonOptions commonOptions) {
final int flags = commonOptions.force
? VibrationAttributes.FLAG_BYPASS_INTERRUPTION_POLICY
: 0;
return new VibrationAttributes.Builder()
- .setUsage(VibrationAttributes.USAGE_UNKNOWN)
+ // Used to apply Settings.System.HAPTIC_FEEDBACK_INTENSITY to scale effects.
+ .setUsage(VibrationAttributes.USAGE_TOUCH)
.replaceFlags(flags)
.build();
}
@@ -2062,19 +2095,26 @@ public class VibratorService extends IVibratorService.Stub
pw.println(" Prints this help text.");
pw.println("");
pw.println(" vibrate duration [description]");
- pw.println(" Vibrates for duration milliseconds; ignored when device is on DND ");
- pw.println(" (Do Not Disturb) mode.");
+ pw.println(" Vibrates for duration milliseconds; ignored when device is on ");
+ pw.println(" DND (Do Not Disturb) mode; touch feedback strength user setting ");
+ pw.println(" will be used to scale amplitude.");
pw.println(" waveform [-d description] [-r index] [-a] duration [amplitude] ...");
- pw.println(" Vibrates for durations and amplitudes in list;");
- pw.println(" ignored when device is on DND (Do Not Disturb) mode.");
+ pw.println(" Vibrates for durations and amplitudes in list; ignored when ");
+ pw.println(" device is on DND (Do Not Disturb) mode; touch feedback strength ");
+ pw.println(" user setting will be used to scale amplitude.");
pw.println(" If -r is provided, the waveform loops back to the specified");
pw.println(" index (e.g. 0 loops from the beginning)");
pw.println(" If -a is provided, the command accepts duration-amplitude pairs;");
pw.println(" otherwise, it accepts durations only and alternates off/on");
pw.println(" Duration is in milliseconds; amplitude is a scale of 1-255.");
- pw.println(" prebaked effect-id [description]");
+ pw.println(" prebaked [-b] effect-id [description]");
pw.println(" Vibrates with prebaked effect; ignored when device is on DND ");
- pw.println(" (Do Not Disturb) mode.");
+ pw.println(" (Do Not Disturb) mode; touch feedback strength user setting ");
+ pw.println(" will be used to scale amplitude.");
+ pw.println(" If -b is provided, the prebaked fallback effect will be played if");
+ pw.println(" the device doesn't support the given effect-id.");
+ pw.println(" capabilities");
+ pw.println(" Prints capabilities of this device.");
pw.println(" cancel");
pw.println(" Cancels any active vibration");
pw.println("Common Options:");
diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java
index c5c3cafa8813..a7bf98280af8 100644
--- a/services/core/java/com/android/server/am/ActiveServices.java
+++ b/services/core/java/com/android/server/am/ActiveServices.java
@@ -4918,52 +4918,6 @@ public final class ActiveServices {
if (isDeviceOwner) {
return true;
}
-
- r.mInfoDenyWhileInUsePermissionInFgs =
- "Background FGS start while-in-use permission restriction [callingPackage: "
- + callingPackage
- + "; callingUid: " + callingUid
- + "; intent: " + intent
- + "]";
return false;
}
-
- // TODO: remove this toast after feature development is done
- void showWhileInUseDebugToastLocked(int uid, int op, int mode) {
- final UidRecord uidRec = mAm.mProcessList.getUidRecordLocked(uid);
- if (uidRec == null) {
- return;
- }
-
- for (int i = uidRec.procRecords.size() - 1; i >= 0; i--) {
- ProcessRecord pr = uidRec.procRecords.valueAt(i);
- if (pr.uid != uid) {
- continue;
- }
- for (int j = pr.numberOfRunningServices() - 1; j >= 0; j--) {
- ServiceRecord r = pr.getRunningServiceAt(j);
- if (!r.isForeground) {
- continue;
- }
- if (mode == DEBUG_FGS_ALLOW_WHILE_IN_USE) {
- if (!r.mAllowWhileInUsePermissionInFgs
- && r.mInfoDenyWhileInUsePermissionInFgs != null) {
- final String msg = r.mInfoDenyWhileInUsePermissionInFgs
- + " affected while-in-use permission:"
- + AppOpsManager.opToPublicName(op);
- Slog.wtf(TAG, msg);
- }
- } else if (mode == DEBUG_FGS_ENFORCE_TYPE) {
- final String msg =
- "FGS Missing foregroundServiceType in manifest file [callingPackage: "
- + r.mRecentCallingPackage
- + "; intent:" + r.intent.getIntent()
- + "] affected while-in-use permission:"
- + AppOpsManager.opToPublicName(op)
- + "; targetSdkVersion:" + r.appInfo.targetSdkVersion;
- Slog.wtf(TAG, msg);
- }
- }
- }
- }
}
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index caaa8371af53..026f147e955c 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -28,6 +28,7 @@ import static android.app.ActivityManager.INSTR_FLAG_DISABLE_TEST_API_CHECKS;
import static android.app.ActivityManager.INSTR_FLAG_MOUNT_EXTERNAL_STORAGE_FULL;
import static android.app.ActivityManager.PROCESS_STATE_LAST_ACTIVITY;
import static android.app.ActivityManager.PROCESS_STATE_NONEXISTENT;
+import static android.app.ActivityManager.PROCESS_STATE_TOP;
import static android.app.ActivityManagerInternal.ALLOW_FULL_ONLY;
import static android.app.ActivityManagerInternal.ALLOW_NON_FULL;
import static android.app.AppOpsManager.OP_NONE;
@@ -299,7 +300,6 @@ import android.util.PrintWriterPrinter;
import android.util.Slog;
import android.util.SparseArray;
import android.util.SparseIntArray;
-import android.util.SparseLongArray;
import android.util.TimeUtils;
import android.util.proto.ProtoOutputStream;
import android.util.proto.ProtoUtils;
@@ -421,7 +421,6 @@ public class ActivityManagerService extends IActivityManager.Stub
* Priority we boost main thread and RT of top app to.
*/
public static final int TOP_APP_PRIORITY_BOOST = -10;
-
private static final String SYSTEM_PROPERTY_DEVICE_PROVISIONED =
"persist.sys.device_provisioned";
@@ -823,45 +822,7 @@ public class ActivityManagerService extends IActivityManager.Stub
}
}
- /**
- * While starting activity, WindowManager posts a runnable to DisplayThread to updateOomAdj.
- * The latency of the thread switch could cause client app failure when the app is checking
- * {@link #isUidActive} before updateOomAdj is done.
- *
- * Use PendingStartActivityUids to save uid after WindowManager start activity and before
- * updateOomAdj is done.
- *
- * <p>NOTE: This object is protected by its own lock, NOT the global activity manager lock!
- */
- final PendingStartActivityUids mPendingStartActivityUidsLocked = new PendingStartActivityUids();
- final class PendingStartActivityUids {
- // Key is uid, value is SystemClock.elapsedRealtime() when the key is added.
- private final SparseLongArray mPendingUids = new SparseLongArray();
-
- void add(int uid) {
- if (mPendingUids.indexOfKey(uid) < 0) {
- mPendingUids.put(uid, SystemClock.elapsedRealtime());
- }
- }
-
- void delete(int uid) {
- if (mPendingUids.indexOfKey(uid) >= 0) {
- long delay = SystemClock.elapsedRealtime() - mPendingUids.get(uid);
- if (delay >= 1000) {
- Slog.wtf(TAG,
- "PendingStartActivityUids startActivity to updateOomAdj delay:"
- + delay + "ms,"
- + " uid:" + uid
- + " packageName:" + Settings.getPackageNameForUid(mContext, uid));
- }
- mPendingUids.delete(uid);
- }
- }
-
- boolean isPendingTopUid(int uid) {
- return mPendingUids.indexOfKey(uid) >= 0;
- }
- }
+ private final PendingStartActivityUids mPendingStartActivityUids;
/**
* Puts the process record in the map.
@@ -2585,6 +2546,7 @@ public class ActivityManagerService extends IActivityManager.Stub
mFactoryTest = FACTORY_TEST_OFF;
mUgmInternal = LocalServices.getService(UriGrantsManagerInternal.class);
mInternal = new LocalService();
+ mPendingStartActivityUids = new PendingStartActivityUids(mContext);
}
// Note: This method is invoked on the main thread but may need to attach various
@@ -2742,6 +2704,7 @@ public class ActivityManagerService extends IActivityManager.Stub
}
mInternal = new LocalService();
+ mPendingStartActivityUids = new PendingStartActivityUids(mContext);
}
public void setSystemServiceManager(SystemServiceManager mgr) {
@@ -6093,9 +6056,18 @@ public class ActivityManagerService extends IActivityManager.Stub
synchronized (mPidsSelfLocked) {
for (int i = 0; i < pids.length; i++) {
ProcessRecord pr = mPidsSelfLocked.get(pids[i]);
- states[i] = (pr == null) ? PROCESS_STATE_NONEXISTENT : pr.getCurProcState();
- if (scores != null) {
- scores[i] = (pr == null) ? ProcessList.INVALID_ADJ : pr.curAdj;
+ if (pr != null) {
+ final boolean isPendingTop =
+ mPendingStartActivityUids.isPendingTopPid(pr.uid, pids[i]);
+ states[i] = isPendingTop ? PROCESS_STATE_TOP : pr.getCurProcState();
+ if (scores != null) {
+ scores[i] = isPendingTop ? ProcessList.FOREGROUND_APP_ADJ : pr.curAdj;
+ }
+ } else {
+ states[i] = PROCESS_STATE_NONEXISTENT;
+ if (scores != null) {
+ scores[i] = ProcessList.INVALID_ADJ;
+ }
}
}
}
@@ -8839,15 +8811,7 @@ public class ActivityManagerService extends IActivityManager.Stub
return true;
}
}
-
- if (mInternal.isPendingTopUid(uid)) {
- Slog.wtf(TAG, "PendingStartActivityUids isUidActive false but"
- + " isPendingTopUid true, uid:" + uid
- + " callingPackage:" + callingPackage);
- return true;
- } else {
- return false;
- }
+ return mInternal.isPendingTopUid(uid);
}
boolean isUidActiveLocked(int uid) {
@@ -19707,15 +19671,6 @@ public class ActivityManagerService extends IActivityManager.Stub
return false;
}
- // TODO: remove this toast after feature development is done
- @Override
- public void showWhileInUseDebugToast(int uid, int op, int mode) {
- synchronized (ActivityManagerService.this) {
- ActivityManagerService.this.mServices.showWhileInUseDebugToastLocked(
- uid, op, mode);
- }
- }
-
@Override
public void setDeviceOwnerUid(int uid) {
synchronized (ActivityManagerService.this) {
@@ -19731,22 +19686,18 @@ public class ActivityManagerService extends IActivityManager.Stub
}
@Override
- public void updatePendingTopUid(int uid, boolean pending) {
- synchronized (mPendingStartActivityUidsLocked) {
- if (pending) {
- mPendingStartActivityUidsLocked.add(uid);
- } else {
- mPendingStartActivityUidsLocked.delete(uid);
- }
- }
+ public void addPendingTopUid(int uid, int pid) {
+ mPendingStartActivityUids.add(uid, pid);
+ }
+ @Override
+ public void deletePendingTopUid(int uid) {
+ mPendingStartActivityUids.delete(uid);
}
@Override
public boolean isPendingTopUid(int uid) {
- synchronized (mPendingStartActivityUidsLocked) {
- return mPendingStartActivityUidsLocked.isPendingTopUid(uid);
- }
+ return mPendingStartActivityUids.isPendingTopUid(uid);
}
}
diff --git a/services/core/java/com/android/server/am/OomAdjuster.java b/services/core/java/com/android/server/am/OomAdjuster.java
index 14c5b2cb12b2..da5f48962130 100644
--- a/services/core/java/com/android/server/am/OomAdjuster.java
+++ b/services/core/java/com/android/server/am/OomAdjuster.java
@@ -951,7 +951,7 @@ public final class OomAdjuster {
mService.mServices.foregroundServiceProcStateChangedLocked(uidRec);
}
}
- mService.mInternal.updatePendingTopUid(uidRec.uid, false);
+ mService.mInternal.deletePendingTopUid(uidRec.uid);
}
if (mLocalPowerManager != null) {
mLocalPowerManager.finishUidChanges();
@@ -1508,16 +1508,7 @@ public final class OomAdjuster {
capabilityFromFGS |=
(fgsType & FOREGROUND_SERVICE_TYPE_LOCATION)
!= 0 ? PROCESS_CAPABILITY_FOREGROUND_LOCATION : 0;
- } else {
- //The FGS has the location capability, but due to FGS BG start restriction it
- //lost the capability, use temp location capability to mark this case.
- //TODO: remove this block when development is done.
- capabilityFromFGS |=
- (fgsType & FOREGROUND_SERVICE_TYPE_LOCATION) != 0
- ? ActivityManager.DEBUG_PROCESS_CAPABILITY_FOREGROUND_LOCATION
- : 0;
- }
- if (s.mAllowWhileInUsePermissionInFgs) {
+
boolean enabled = false;
try {
enabled = mPlatformCompat.isChangeEnabled(
@@ -1527,23 +1518,13 @@ public final class OomAdjuster {
if (enabled) {
capabilityFromFGS |=
(fgsType & FOREGROUND_SERVICE_TYPE_CAMERA)
- != 0 ? PROCESS_CAPABILITY_FOREGROUND_CAMERA
- : ActivityManager.DEBUG_PROCESS_CAPABILITY_FOREGROUND_CAMERA;
+ != 0 ? PROCESS_CAPABILITY_FOREGROUND_CAMERA : 0;
capabilityFromFGS |=
(fgsType & FOREGROUND_SERVICE_TYPE_MICROPHONE)
- != 0 ? PROCESS_CAPABILITY_FOREGROUND_MICROPHONE
- : ActivityManager.DEBUG_PROCESS_CAPABILITY_FOREGROUND_MICROPHONE;
+ != 0 ? PROCESS_CAPABILITY_FOREGROUND_MICROPHONE : 0;
} else {
- // Remove fgsType check and assign PROCESS_CAPABILITY_FOREGROUND_CAMERA
- // and MICROPHONE when finish debugging.
- capabilityFromFGS |=
- (fgsType & FOREGROUND_SERVICE_TYPE_CAMERA)
- != 0 ? PROCESS_CAPABILITY_FOREGROUND_CAMERA
- : ActivityManager.DEBUG_PROCESS_CAPABILITY_FOREGROUND_CAMERA_Q;
- capabilityFromFGS |=
- (fgsType & FOREGROUND_SERVICE_TYPE_MICROPHONE)
- != 0 ? PROCESS_CAPABILITY_FOREGROUND_MICROPHONE
- : ActivityManager.DEBUG_PROCESS_CAPABILITY_FOREGROUND_MICROPHONE_Q;
+ capabilityFromFGS |= PROCESS_CAPABILITY_FOREGROUND_CAMERA
+ | PROCESS_CAPABILITY_FOREGROUND_MICROPHONE;
}
}
}
diff --git a/services/core/java/com/android/server/am/PendingStartActivityUids.java b/services/core/java/com/android/server/am/PendingStartActivityUids.java
new file mode 100644
index 000000000000..6bf9d4e5c3f0
--- /dev/null
+++ b/services/core/java/com/android/server/am/PendingStartActivityUids.java
@@ -0,0 +1,78 @@
+/*
+ * 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.server.am;
+
+import android.content.Context;
+import android.os.SystemClock;
+import android.util.Pair;
+import android.util.Slog;
+import android.util.SparseArray;
+
+/**
+ * While starting activity, WindowManager posts a runnable to DisplayThread to updateOomAdj.
+ * The latency of the thread switch could cause client app failure when the app is checking
+ * {@link ActivityManagerService#isUidActive} before updateOomAdj is done.
+ *
+ * Use PendingStartActivityUids to save uid after WindowManager start activity and before
+ * updateOomAdj is done.
+ *
+ * <p>NOTE: This object is protected by its own lock, NOT the global activity manager lock!
+ */
+final class PendingStartActivityUids {
+ static final String TAG = ActivityManagerService.TAG;
+
+ // Key is uid, value is Pair of pid and SystemClock.elapsedRealtime() when the
+ // uid is added.
+ private final SparseArray<Pair<Integer, Long>> mPendingUids = new SparseArray();
+ private Context mContext;
+
+ PendingStartActivityUids(Context context) {
+ mContext = context;
+ }
+
+ synchronized void add(int uid, int pid) {
+ if (mPendingUids.get(uid) == null) {
+ mPendingUids.put(uid, new Pair<>(pid, SystemClock.elapsedRealtime()));
+ }
+ }
+
+ synchronized void delete(int uid) {
+ final Pair<Integer, Long> pendingPid = mPendingUids.get(uid);
+ if (pendingPid != null) {
+ final long delay = SystemClock.elapsedRealtime() - pendingPid.second;
+ if (delay >= 1000 /*ms*/) {
+ Slog.i(TAG,
+ "PendingStartActivityUids startActivity to updateOomAdj delay:"
+ + delay + "ms," + " uid:" + uid);
+ }
+ mPendingUids.delete(uid);
+ }
+ }
+
+ synchronized boolean isPendingTopPid(int uid, int pid) {
+ final Pair<Integer, Long> pendingPid = mPendingUids.get(uid);
+ if (pendingPid != null) {
+ return pendingPid.first == pid;
+ } else {
+ return false;
+ }
+ }
+
+ synchronized boolean isPendingTopUid(int uid) {
+ return mPendingUids.get(uid) != null;
+ }
+} \ No newline at end of file
diff --git a/services/core/java/com/android/server/am/ProcessList.java b/services/core/java/com/android/server/am/ProcessList.java
index 9f2a77c05d2b..2e628642dac5 100644
--- a/services/core/java/com/android/server/am/ProcessList.java
+++ b/services/core/java/com/android/server/am/ProcessList.java
@@ -2214,11 +2214,11 @@ public final class ProcessList {
app.setHasForegroundActivities(true);
}
- final Map<String, Pair<String, Long>> pkgDataInfoMap;
- final Map<String, Pair<String, Long>> whitelistedAppDataInfoMap;
+ Map<String, Pair<String, Long>> pkgDataInfoMap;
+ Map<String, Pair<String, Long>> whitelistedAppDataInfoMap;
boolean bindMountAppStorageDirs = false;
boolean bindMountAppsData = mAppDataIsolationEnabled
- && UserHandle.isApp(app.uid)
+ && (UserHandle.isApp(app.uid) || UserHandle.isIsolated(app.uid))
&& mPlatformCompat.isChangeEnabled(APP_DATA_DIRECTORY_ISOLATION, app.info);
// Get all packages belongs to the same shared uid. sharedPackages is empty array
@@ -2266,6 +2266,13 @@ public final class ProcessList {
}
}
+ // If it's an isolated process, it should not even mount its own app data directories,
+ // since it has no access to them anyway.
+ if (app.isolated) {
+ pkgDataInfoMap = null;
+ whitelistedAppDataInfoMap = null;
+ }
+
final Process.ProcessStartResult startResult;
if (hostingRecord.usesWebviewZygote()) {
startResult = startWebView(entryPoint,
@@ -2276,13 +2283,14 @@ public final class ProcessList {
} else if (hostingRecord.usesAppZygote()) {
final AppZygote appZygote = createAppZygoteForProcessIfNeeded(app);
+ // We can't isolate app data and storage data as parent zygote already did that.
startResult = appZygote.getProcess().start(entryPoint,
app.processName, uid, uid, gids, runtimeFlags, mountExternal,
app.info.targetSdkVersion, seInfo, requiredAbi, instructionSet,
app.info.dataDir, null, app.info.packageName,
/*zygotePolicyFlags=*/ ZYGOTE_POLICY_FLAG_EMPTY, isTopApp,
app.mDisabledCompatChanges, pkgDataInfoMap, whitelistedAppDataInfoMap,
- bindMountAppsData, bindMountAppStorageDirs,
+ false, false,
new String[]{PROC_START_SEQ_IDENT + app.startSeq});
} else {
startResult = Process.start(entryPoint,
diff --git a/services/core/java/com/android/server/am/ServiceRecord.java b/services/core/java/com/android/server/am/ServiceRecord.java
index 4670d58ca63b..9c96e6e02566 100644
--- a/services/core/java/com/android/server/am/ServiceRecord.java
+++ b/services/core/java/com/android/server/am/ServiceRecord.java
@@ -138,10 +138,7 @@ final class ServiceRecord extends Binder implements ComponentName.WithComponentN
// allow while-in-use permissions in foreground service or not.
// while-in-use permissions in FGS started from background might be restricted.
boolean mAllowWhileInUsePermissionInFgs;
- // information string what/why service is denied while-in-use permissions when
- // foreground service is started from background.
- // TODO: remove this field after feature development is done
- String mInfoDenyWhileInUsePermissionInFgs;
+
// the most recent package that start/bind this service.
String mRecentCallingPackage;
diff --git a/services/core/java/com/android/server/am/UserController.java b/services/core/java/com/android/server/am/UserController.java
index ea7059894f38..f2c4e4428af2 100644
--- a/services/core/java/com/android/server/am/UserController.java
+++ b/services/core/java/com/android/server/am/UserController.java
@@ -2515,7 +2515,7 @@ class UserController implements Handler.Callback {
showUserSwitchDialog(fromToUserPair);
break;
case CLEAR_USER_JOURNEY_SESSION_MSG:
- clearSessionId(msg.arg1);
+ logAndClearSessionId(msg.arg1);
break;
}
return false;
@@ -2630,6 +2630,21 @@ class UserController implements Handler.Callback {
}
/**
+ * Log a final event of the {@link UserJourneySession} and clear it.
+ */
+ private void logAndClearSessionId(@UserIdInt int userId) {
+ synchronized (mUserIdToUserJourneyMap) {
+ final UserJourneySession userJourneySession = mUserIdToUserJourneyMap.get(userId);
+ if (userJourneySession != null) {
+ FrameworkStatsLog.write(FrameworkStatsLog.USER_LIFECYCLE_EVENT_OCCURRED,
+ userJourneySession.mSessionId, userId, USER_LIFECYCLE_EVENT_UNKNOWN,
+ USER_LIFECYCLE_EVENT_STATE_NONE);
+ }
+ clearSessionId(userId);
+ }
+ }
+
+ /**
* Helper class to store user journey and session id.
*
* <p> User journey tracks a chain of user lifecycle events occurring during different user
diff --git a/services/core/java/com/android/server/appop/AppOpsService.java b/services/core/java/com/android/server/appop/AppOpsService.java
index a33ad7dc0ea1..73c98da6aa56 100644
--- a/services/core/java/com/android/server/appop/AppOpsService.java
+++ b/services/core/java/com/android/server/appop/AppOpsService.java
@@ -66,11 +66,6 @@ import static android.content.Intent.EXTRA_REPLACING;
import static android.content.pm.PermissionInfo.PROTECTION_DANGEROUS;
import static android.content.pm.PermissionInfo.PROTECTION_FLAG_APPOP;
-import static android.app.ActivityManager.DEBUG_PROCESS_CAPABILITY_FOREGROUND_CAMERA;
-import static android.app.ActivityManager.DEBUG_PROCESS_CAPABILITY_FOREGROUND_CAMERA_Q;
-import static android.app.ActivityManager.DEBUG_PROCESS_CAPABILITY_FOREGROUND_LOCATION;
-import static android.app.ActivityManager.DEBUG_PROCESS_CAPABILITY_FOREGROUND_MICROPHONE;
-import static android.app.ActivityManager.DEBUG_PROCESS_CAPABILITY_FOREGROUND_MICROPHONE_Q;
import static com.android.server.appop.AppOpsService.ModeCallback.ALL_OPS;
import static java.lang.Long.max;
@@ -249,7 +244,7 @@ public class AppOpsService extends IAppOpsService.Stub {
OP_CAMERA,
};
- private static final int MAX_UNFORWARED_OPS = 10;
+ private static final int MAX_UNFORWARDED_OPS = 10;
private static final int MAX_UNUSED_POOLED_OBJECTS = 3;
private static final int RARELY_USED_PACKAGES_INITIALIZATION_DELAY_MILLIS = 300000;
@@ -322,7 +317,7 @@ public class AppOpsService extends IAppOpsService.Stub {
@VisibleForTesting
final SparseArray<UidState> mUidStates = new SparseArray<>();
- final HistoricalRegistry mHistoricalRegistry = new HistoricalRegistry(this);
+ volatile @NonNull HistoricalRegistry mHistoricalRegistry = new HistoricalRegistry(this);
long mLastRealtime;
@@ -520,9 +515,6 @@ public class AppOpsService extends IAppOpsService.Stub {
public SparseBooleanArray foregroundOps;
public boolean hasForegroundWatchers;
- public long lastTimeShowDebugToast;
- public long lastTimePendingTopUid;
-
public UidState(int uid) {
this.uid = uid;
}
@@ -545,7 +537,6 @@ public class AppOpsService extends IAppOpsService.Stub {
return MODE_ALLOWED;
} else if (mActivityManagerInternal != null
&& mActivityManagerInternal.isPendingTopUid(uid)) {
- maybeLogPendingTopUid(op, mode);
return MODE_ALLOWED;
} else if (state <= UID_STATE_TOP) {
// process is in TOP.
@@ -559,44 +550,19 @@ public class AppOpsService extends IAppOpsService.Stub {
case AppOpsManager.OP_MONITOR_HIGH_POWER_LOCATION:
if ((capability & PROCESS_CAPABILITY_FOREGROUND_LOCATION) != 0) {
return MODE_ALLOWED;
- } else if ((capability
- & DEBUG_PROCESS_CAPABILITY_FOREGROUND_LOCATION) != 0) {
- // The FGS has the location capability, but due to FGS BG start
- // restriction it lost the capability, use temp location capability
- // to mark this case.
- maybeShowWhileInUseDebugToast(op, DEBUG_FGS_ALLOW_WHILE_IN_USE);
- return MODE_IGNORED;
} else {
return MODE_IGNORED;
}
case OP_CAMERA:
if ((capability & PROCESS_CAPABILITY_FOREGROUND_CAMERA) != 0) {
return MODE_ALLOWED;
- } else if ((capability & DEBUG_PROCESS_CAPABILITY_FOREGROUND_CAMERA_Q)
- != 0) {
- maybeShowWhileInUseDebugToast(op, DEBUG_FGS_ENFORCE_TYPE);
- return MODE_ALLOWED;
- } else if ((capability & DEBUG_PROCESS_CAPABILITY_FOREGROUND_CAMERA)
- != 0) {
- maybeShowWhileInUseDebugToast(op, DEBUG_FGS_ENFORCE_TYPE);
- return MODE_IGNORED;
} else {
- maybeShowWhileInUseDebugToast(op, DEBUG_FGS_ALLOW_WHILE_IN_USE);
return MODE_IGNORED;
}
case OP_RECORD_AUDIO:
if ((capability & PROCESS_CAPABILITY_FOREGROUND_MICROPHONE) != 0) {
return MODE_ALLOWED;
- } else if ((capability
- & DEBUG_PROCESS_CAPABILITY_FOREGROUND_MICROPHONE_Q) != 0) {
- maybeShowWhileInUseDebugToast(op, DEBUG_FGS_ENFORCE_TYPE);
- return MODE_ALLOWED;
- } else if ((capability
- & DEBUG_PROCESS_CAPABILITY_FOREGROUND_MICROPHONE) != 0) {
- maybeShowWhileInUseDebugToast(op, DEBUG_FGS_ENFORCE_TYPE);
- return MODE_IGNORED;
} else {
- maybeShowWhileInUseDebugToast(op, DEBUG_FGS_ALLOW_WHILE_IN_USE);
return MODE_IGNORED;
}
default:
@@ -611,38 +577,19 @@ public class AppOpsService extends IAppOpsService.Stub {
case OP_CAMERA:
if (mActivityManagerInternal != null
&& mActivityManagerInternal.isPendingTopUid(uid)) {
- maybeLogPendingTopUid(op, mode);
return MODE_ALLOWED;
} else if ((capability & PROCESS_CAPABILITY_FOREGROUND_CAMERA) != 0) {
return MODE_ALLOWED;
- } else if ((capability
- & DEBUG_PROCESS_CAPABILITY_FOREGROUND_CAMERA_Q) != 0) {
- maybeShowWhileInUseDebugToast(op, DEBUG_FGS_ENFORCE_TYPE);
- return MODE_ALLOWED;
- } else if ((capability & DEBUG_PROCESS_CAPABILITY_FOREGROUND_CAMERA) != 0) {
- maybeShowWhileInUseDebugToast(op, DEBUG_FGS_ENFORCE_TYPE);
- return MODE_IGNORED;
} else {
- maybeShowWhileInUseDebugToast(op, DEBUG_FGS_ALLOW_WHILE_IN_USE);
return MODE_IGNORED;
}
case OP_RECORD_AUDIO:
if (mActivityManagerInternal != null
&& mActivityManagerInternal.isPendingTopUid(uid)) {
- maybeLogPendingTopUid(op, mode);
return MODE_ALLOWED;
} else if ((capability & PROCESS_CAPABILITY_FOREGROUND_MICROPHONE) != 0) {
return MODE_ALLOWED;
- } else if ((capability & DEBUG_PROCESS_CAPABILITY_FOREGROUND_MICROPHONE_Q)
- != 0) {
- maybeShowWhileInUseDebugToast(op, DEBUG_FGS_ENFORCE_TYPE);
- return MODE_ALLOWED;
- } else if ((capability & DEBUG_PROCESS_CAPABILITY_FOREGROUND_MICROPHONE)
- != 0) {
- maybeShowWhileInUseDebugToast(op, DEBUG_FGS_ENFORCE_TYPE);
- return MODE_IGNORED;
} else {
- maybeShowWhileInUseDebugToast(op, DEBUG_FGS_ALLOW_WHILE_IN_USE);
return MODE_IGNORED;
}
default:
@@ -696,40 +643,6 @@ public class AppOpsService extends IAppOpsService.Stub {
}
foregroundOps = which;
}
-
- // TODO: remove this toast after feature development is done
- // For DEBUG_FGS_ALLOW_WHILE_IN_USE, if the procstate is foreground service and while-in-use
- // permission is denied, show a toast message and generate a WTF log so we know
- // how many apps are impacted by the new background started foreground service while-in-use
- // permission restriction.
- // For DEBUG_FGS_ENFORCE_TYPE, The process has a foreground service that does not have
- // camera/microphone foregroundServiceType in manifest file, and the process is asking
- // AppOps for camera/microphone ops, show a toast message and generate a WTF log.
- void maybeShowWhileInUseDebugToast(int op, int mode) {
- if (mode == DEBUG_FGS_ALLOW_WHILE_IN_USE && state != UID_STATE_FOREGROUND_SERVICE) {
- return;
- }
- final long now = System.currentTimeMillis();
- if (lastTimeShowDebugToast == 0 || now - lastTimeShowDebugToast > 600000) {
- lastTimeShowDebugToast = now;
- mHandler.sendMessage(PooledLambda.obtainMessage(
- ActivityManagerInternal::showWhileInUseDebugToast,
- mActivityManagerInternal, uid, op, mode));
- }
- }
-
-
- void maybeLogPendingTopUid(int op, int mode) {
- final long now = System.currentTimeMillis();
- if (lastTimePendingTopUid == 0 || now - lastTimePendingTopUid > 300000) {
- lastTimePendingTopUid = now;
- Slog.wtf(TAG, "PendingStartActivityUids evalMode, isPendingTopUid true, uid:"
- + uid
- + " packageName:" + Settings.getPackageNameForUid(mContext, uid)
- + " op:" + op
- + " mode:" + mode);
- }
- }
}
final static class Ops extends SparseArray<Op> {
@@ -1776,8 +1689,7 @@ public class AppOpsService extends IAppOpsService.Stub {
mHandler.postDelayed(new Runnable() {
@Override
public void run() {
- List<String> packageNames = getPackageNamesForSampling();
- resamplePackageAndAppOpLocked(packageNames);
+ List<String> packageNames = getPackageListAndResample();
initializeRarelyUsedPackagesList(new ArraySet<>(packageNames));
}
}, RARELY_USED_PACKAGES_INITIALIZATION_DELAY_MILLIS);
@@ -1978,6 +1890,8 @@ public class AppOpsService extends IAppOpsService.Stub {
if (AppOpsManager.NOTE_OP_COLLECTION_ENABLED && mWriteNoteOpsScheduled) {
writeNoteOps();
}
+
+ mHistoricalRegistry.shutdown();
}
private ArrayList<AppOpsManager.OpEntry> collectOps(Ops pkgOps, int[] ops) {
@@ -3372,7 +3286,7 @@ public class AppOpsService extends IAppOpsService.Stub {
}
unforwardedOps.add(asyncNotedOp);
- if (unforwardedOps.size() > MAX_UNFORWARED_OPS) {
+ if (unforwardedOps.size() > MAX_UNFORWARDED_OPS) {
unforwardedOps.remove(0);
}
}
@@ -5881,6 +5795,25 @@ public class AppOpsService extends IAppOpsService.Stub {
mHistoricalRegistry.clearHistory();
}
+ @Override
+ public void rebootHistory(long offlineDurationMillis) {
+ mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_APPOPS,
+ "rebootHistory");
+
+ Preconditions.checkArgument(offlineDurationMillis >= 0);
+
+ // Must not hold the appops lock
+ mHistoricalRegistry.shutdown();
+
+ if (offlineDurationMillis > 0) {
+ SystemClock.sleep(offlineDurationMillis);
+ }
+
+ mHistoricalRegistry = new HistoricalRegistry(mHistoricalRegistry);
+ mHistoricalRegistry.systemReady(mContext.getContentResolver());
+ mHistoricalRegistry.persistPendingHistory();
+ }
+
/**
* Report runtime access to AppOp together with message (including stack trace)
*
@@ -5967,11 +5900,13 @@ public class AppOpsService extends IAppOpsService.Stub {
mContext.enforcePermission(android.Manifest.permission.GET_APP_OPS_STATS,
Binder.getCallingPid(), Binder.getCallingUid(), null);
RuntimeAppOpAccessMessage result;
- List<String> packageNames = getPackageNamesForSampling();
synchronized (this) {
result = mCollectedRuntimePermissionMessage;
- resamplePackageAndAppOpLocked(packageNames);
+ mCollectedRuntimePermissionMessage = null;
}
+ mHandler.sendMessage(PooledLambda.obtainMessage(
+ AppOpsService::getPackageListAndResample,
+ this));
return result;
}
@@ -5995,6 +5930,15 @@ public class AppOpsService extends IAppOpsService.Stub {
}
}
+ /** Obtains package list and resamples package and appop to watch. */
+ private List<String> getPackageListAndResample() {
+ List<String> packageNames = getPackageNamesForSampling();
+ synchronized (this) {
+ resamplePackageAndAppOpLocked(packageNames);
+ }
+ return packageNames;
+ }
+
/** Resamples package and appop to watch from the list provided. */
private void resamplePackageAndAppOpLocked(@NonNull List<String> packageNames) {
if (!packageNames.isEmpty()) {
@@ -6010,7 +5954,6 @@ public class AppOpsService extends IAppOpsService.Stub {
mSampledAppOpCode = ThreadLocalRandom.current().nextInt(_NUM_OP);
mAcceptableLeftDistance = _NUM_OP;
mSampledPackage = packageName;
- mCollectedRuntimePermissionMessage = null;
}
/**
@@ -6022,7 +5965,7 @@ public class AppOpsService extends IAppOpsService.Stub {
List<String> runtimeAppOpsList = getRuntimeAppOpsList();
AppOpsManager.HistoricalOpsRequest histOpsRequest =
new AppOpsManager.HistoricalOpsRequest.Builder(
- Instant.now().minus(7, ChronoUnit.DAYS).toEpochMilli(),
+ Math.max(Instant.now().minus(7, ChronoUnit.DAYS).toEpochMilli(), 0),
Long.MAX_VALUE).setOpNames(runtimeAppOpsList).setFlags(
OP_FLAG_SELF | OP_FLAG_TRUSTED_PROXIED).build();
appOps.getHistoricalOps(histOpsRequest, AsyncTask.THREAD_POOL_EXECUTOR,
diff --git a/services/core/java/com/android/server/appop/HistoricalRegistry.java b/services/core/java/com/android/server/appop/HistoricalRegistry.java
index ed4506902f0a..3d22a156b91c 100644
--- a/services/core/java/com/android/server/appop/HistoricalRegistry.java
+++ b/services/core/java/com/android/server/appop/HistoricalRegistry.java
@@ -199,6 +199,13 @@ final class HistoricalRegistry {
mInMemoryLock = lock;
}
+ HistoricalRegistry(@NonNull HistoricalRegistry other) {
+ this(other.mInMemoryLock);
+ mMode = other.mMode;
+ mBaseSnapshotInterval = other.mBaseSnapshotInterval;
+ mIntervalCompressionMultiplier = other.mIntervalCompressionMultiplier;
+ }
+
void systemReady(@NonNull ContentResolver resolver) {
final Uri uri = Settings.Global.getUriFor(Settings.Global.APPOP_HISTORY_PARAMETERS);
resolver.registerContentObserver(uri, false, new ContentObserver(
@@ -223,9 +230,16 @@ final class HistoricalRegistry {
// When starting always adjust history to now.
final long lastPersistTimeMills =
mPersistence.getLastPersistTimeMillisDLocked();
+
if (lastPersistTimeMills > 0) {
- mPendingHistoryOffsetMillis =
- System.currentTimeMillis() - lastPersistTimeMills;
+ mPendingHistoryOffsetMillis = System.currentTimeMillis()
+ - lastPersistTimeMills;
+
+ if (DEBUG) {
+ Slog.i(LOG_TAG, "Time since last write: "
+ + TimeUtils.formatDuration(mPendingHistoryOffsetMillis)
+ + " by which to push history on next write");
+ }
}
}
}
@@ -597,6 +611,9 @@ final class HistoricalRegistry {
return;
}
clearHistoryOnDiskDLocked();
+ mNextPersistDueTimeMillis = 0;
+ mPendingHistoryOffsetMillis = 0;
+ mCurrentHistoricalOps = null;
}
}
}
@@ -650,7 +667,15 @@ final class HistoricalRegistry {
return mCurrentHistoricalOps;
}
- private void persistPendingHistory() {
+ void shutdown() {
+ synchronized (mInMemoryLock) {
+ if (mMode != AppOpsManager.HISTORICAL_MODE_DISABLED) {
+ persistPendingHistory();
+ }
+ }
+ }
+
+ void persistPendingHistory() {
final List<HistoricalOps> pendingWrites;
synchronized (mOnDiskLock) {
synchronized (mInMemoryLock) {
@@ -844,13 +869,7 @@ final class HistoricalRegistry {
if (shortestFile == null) {
return 0;
}
- final String shortestNameNoExtension = shortestFile.getName()
- .replace(HISTORY_FILE_SUFFIX, "");
- try {
- return Long.parseLong(shortestNameNoExtension);
- } catch (NumberFormatException e) {
- return 0;
- }
+ return shortestFile.lastModified();
}
sHistoricalAppOpsDir.finishRead();
} catch (Throwable e) {
diff --git a/services/core/java/com/android/server/audio/AudioDeviceBroker.java b/services/core/java/com/android/server/audio/AudioDeviceBroker.java
index 5c6b481a60bd..45f95fd3f663 100644
--- a/services/core/java/com/android/server/audio/AudioDeviceBroker.java
+++ b/services/core/java/com/android/server/audio/AudioDeviceBroker.java
@@ -38,6 +38,7 @@ import android.os.Message;
import android.os.PowerManager;
import android.os.RemoteException;
import android.os.SystemClock;
+import android.text.TextUtils;
import android.util.Log;
import android.util.PrintWriterPrinter;
@@ -329,11 +330,13 @@ import java.util.concurrent.atomic.AtomicBoolean;
final BtDeviceConnectionInfo info = new BtDeviceConnectionInfo(device, state, profile,
suppressNoisyIntent, a2dpVolume);
+ final String name = TextUtils.emptyIfNull(device.getName());
new MediaMetrics.Item(MediaMetrics.Name.AUDIO_DEVICE + MediaMetrics.SEPARATOR
+ "postBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent")
.set(MediaMetrics.Property.STATE, state == BluetoothProfile.STATE_CONNECTED
? MediaMetrics.Value.CONNECTED : MediaMetrics.Value.DISCONNECTED)
.set(MediaMetrics.Property.INDEX, a2dpVolume)
+ .set(MediaMetrics.Property.NAME, name)
.record();
// operations of removing and posting messages related to A2DP device state change must be
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index 5427dd2328a6..6d45abaf0234 100755
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -1893,7 +1893,7 @@ public class AudioService extends IAudioService.Stub
Binder.getCallingUid(), true, keyEventMode);
break;
case KeyEvent.KEYCODE_VOLUME_MUTE:
- if (event.getRepeatCount() == 0) {
+ if (event.getAction() == KeyEvent.ACTION_DOWN && event.getRepeatCount() == 0) {
adjustSuggestedStreamVolume(AudioManager.ADJUST_TOGGLE_MUTE,
AudioManager.USE_DEFAULT_STREAM_TYPE, flags, callingPackage, caller,
Binder.getCallingUid(), true, VOL_ADJUST_NORMAL);
@@ -1908,31 +1908,11 @@ public class AudioService extends IAudioService.Stub
/** @see AudioManager#adjustVolume(int, int) */
public void adjustSuggestedStreamVolume(int direction, int suggestedStreamType, int flags,
String callingPackage, String caller) {
- final IAudioPolicyCallback extVolCtlr;
- synchronized (mExtVolumeControllerLock) {
- extVolCtlr = mExtVolumeController;
- }
- new MediaMetrics.Item(mMetricsId + "adjustSuggestedStreamVolume")
- .setUid(Binder.getCallingUid())
- .set(MediaMetrics.Property.CALLING_PACKAGE, callingPackage)
- .set(MediaMetrics.Property.CLIENT_NAME, caller)
- .set(MediaMetrics.Property.DIRECTION, direction > 0
- ? MediaMetrics.Value.UP : MediaMetrics.Value.DOWN)
- .set(MediaMetrics.Property.EXTERNAL, extVolCtlr != null
- ? MediaMetrics.Value.YES : MediaMetrics.Value.NO)
- .set(MediaMetrics.Property.FLAGS, flags)
- .record();
- if (extVolCtlr != null) {
- sendMsg(mAudioHandler, MSG_NOTIFY_VOL_EVENT, SENDMSG_QUEUE,
- direction, 0 /*ignored*/,
- extVolCtlr, 0 /*delay*/);
- } else {
- final boolean hasModifyAudioSettings =
- mContext.checkCallingPermission(Manifest.permission.MODIFY_AUDIO_SETTINGS)
- == PackageManager.PERMISSION_GRANTED;
- adjustSuggestedStreamVolume(direction, suggestedStreamType, flags, callingPackage,
- caller, Binder.getCallingUid(), hasModifyAudioSettings, VOL_ADJUST_NORMAL);
- }
+ boolean hasModifyAudioSettings =
+ mContext.checkCallingPermission(Manifest.permission.MODIFY_AUDIO_SETTINGS)
+ == PackageManager.PERMISSION_GRANTED;
+ adjustSuggestedStreamVolume(direction, suggestedStreamType, flags, callingPackage,
+ caller, Binder.getCallingUid(), hasModifyAudioSettings, VOL_ADJUST_NORMAL);
}
private void adjustSuggestedStreamVolume(int direction, int suggestedStreamType, int flags,
@@ -1947,6 +1927,24 @@ public class AudioService extends IAudioService.Stub
direction/*val1*/, flags/*val2*/, new StringBuilder(callingPackage)
.append("/").append(caller).append(" uid:").append(uid).toString()));
}
+
+ boolean hasExternalVolumeController = notifyExternalVolumeController(direction);
+
+ new MediaMetrics.Item(mMetricsId + "adjustSuggestedStreamVolume")
+ .setUid(Binder.getCallingUid())
+ .set(MediaMetrics.Property.CALLING_PACKAGE, callingPackage)
+ .set(MediaMetrics.Property.CLIENT_NAME, caller)
+ .set(MediaMetrics.Property.DIRECTION, direction > 0
+ ? MediaMetrics.Value.UP : MediaMetrics.Value.DOWN)
+ .set(MediaMetrics.Property.EXTERNAL, hasExternalVolumeController
+ ? MediaMetrics.Value.YES : MediaMetrics.Value.NO)
+ .set(MediaMetrics.Property.FLAGS, flags)
+ .record();
+
+ if (hasExternalVolumeController) {
+ return;
+ }
+
final int streamType;
synchronized (mForceControlStreamLock) {
// Request lock in case mVolumeControlStream is changed by other thread.
@@ -1995,6 +1993,21 @@ public class AudioService extends IAudioService.Stub
hasModifyAudioSettings, keyEventMode);
}
+ private boolean notifyExternalVolumeController(int direction) {
+ final IAudioPolicyCallback externalVolumeController;
+ synchronized (mExtVolumeControllerLock) {
+ externalVolumeController = mExtVolumeController;
+ }
+ if (externalVolumeController == null) {
+ return false;
+ }
+
+ sendMsg(mAudioHandler, MSG_NOTIFY_VOL_EVENT, SENDMSG_QUEUE,
+ direction, 0 /*ignored*/,
+ externalVolumeController, 0 /*delay*/);
+ return true;
+ }
+
/** @see AudioManager#adjustStreamVolume(int, int, int)
* Part of service interface, check permissions here */
public void adjustStreamVolume(int streamType, int direction, int flags,
@@ -2142,7 +2155,8 @@ public class AudioService extends IAudioService.Stub
}
int oldIndex = mStreamStates[streamType].getIndex(device);
- if (adjustVolume && (direction != AudioManager.ADJUST_SAME)) {
+ if (adjustVolume
+ && (direction != AudioManager.ADJUST_SAME) && (keyEventMode != VOL_ADJUST_END)) {
mAudioHandler.removeMessages(MSG_UNMUTE_STREAM);
if (isMuteAdjust) {
@@ -2225,6 +2239,11 @@ public class AudioService extends IAudioService.Stub
if (streamTypeAlias == AudioSystem.STREAM_MUSIC) {
setSystemAudioVolume(oldIndex, newIndex, getStreamMaxVolume(streamType), flags);
}
+ }
+
+ final int newIndex = mStreamStates[streamType].getIndex(device);
+
+ if (adjustVolume) {
synchronized (mHdmiClientLock) {
if (mHdmiManager != null) {
// mHdmiCecSink true => mHdmiPlaybackClient != null
@@ -2277,8 +2296,7 @@ public class AudioService extends IAudioService.Stub
}
}
}
- int index = mStreamStates[streamType].getIndex(device);
- sendVolumeUpdate(streamType, oldIndex, index, flags, device);
+ sendVolumeUpdate(streamType, oldIndex, newIndex, flags, device);
}
// Called after a delay when volume down is pressed while muted
@@ -7370,6 +7388,7 @@ public class AudioService extends IAudioService.Stub
pw.print(" mIsSingleVolume="); pw.println(mIsSingleVolume);
pw.print(" mUseFixedVolume="); pw.println(mUseFixedVolume);
pw.print(" mFixedVolumeDevices="); pw.println(dumpDeviceTypes(mFixedVolumeDevices));
+ pw.print(" mExtVolumeController="); pw.println(mExtVolumeController);
pw.print(" mHdmiCecSink="); pw.println(mHdmiCecSink);
pw.print(" mHdmiAudioSystemClient="); pw.println(mHdmiAudioSystemClient);
pw.print(" mHdmiPlaybackClient="); pw.println(mHdmiPlaybackClient);
diff --git a/services/core/java/com/android/server/display/BrightnessMappingStrategy.java b/services/core/java/com/android/server/display/BrightnessMappingStrategy.java
index 787f7f398fcb..6f12155c5ec6 100644
--- a/services/core/java/com/android/server/display/BrightnessMappingStrategy.java
+++ b/services/core/java/com/android/server/display/BrightnessMappingStrategy.java
@@ -28,6 +28,7 @@ import android.util.Pair;
import android.util.Slog;
import android.util.Spline;
+import com.android.internal.BrightnessSynchronizer;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.Preconditions;
import com.android.server.display.utils.Plog;
@@ -348,9 +349,9 @@ public abstract class BrightnessMappingStrategy {
// Normalize entire brightness range to 0 - 1.
protected static float normalizeAbsoluteBrightness(int brightness) {
- brightness = MathUtils.constrain(brightness,
- PowerManager.BRIGHTNESS_OFF, PowerManager.BRIGHTNESS_ON);
- return (float) brightness / PowerManager.BRIGHTNESS_ON;
+ return BrightnessSynchronizer.brightnessIntToFloat(brightness,
+ PowerManager.BRIGHTNESS_OFF + 1, PowerManager.BRIGHTNESS_ON,
+ PowerManager.BRIGHTNESS_MIN, PowerManager.BRIGHTNESS_MAX);
}
private Pair<float[], float[]> insertControlPoint(
diff --git a/services/core/java/com/android/server/hdmi/Constants.java b/services/core/java/com/android/server/hdmi/Constants.java
index ac3a65310d31..13b6c7c3ea46 100644
--- a/services/core/java/com/android/server/hdmi/Constants.java
+++ b/services/core/java/com/android/server/hdmi/Constants.java
@@ -483,6 +483,39 @@ final class Constants {
static final String PROPERTY_STRIP_AUDIO_TV_NO_SYSTEM_AUDIO =
"persist.sys.hdmi.property_strip_audio_tv_no_system_audio";
+ /**
+ * Determines playback device action upon receiving routing control messages.
+ * <ul>
+ * <li><b>none</b> No action taken.
+ * <li><b>wake_up_only</b> PowerManager.wakeUp() is called.
+ * <li><b>wake_up_and_send_active_source</b> Same as above and
+ * additionally <Active Source> is sent.
+ * </ul>
+ */
+ static final String PLAYBACK_DEVICE_ACTION_ON_ROUTING_CONTROL =
+ "ro.hdmi.cec.source.playback_device_action_on_routing_control";
+
+ static final String PLAYBACK_DEVICE_ACTION_ON_ROUTING_CONTROL_NONE = "none";
+ static final String PLAYBACK_DEVICE_ACTION_ON_ROUTING_CONTROL_WAKE_UP_ONLY = "wake_up_only";
+ static final String PLAYBACK_DEVICE_ACTION_ON_ROUTING_CONTROL_WAKE_UP_AND_SEND_ACTIVE_SOURCE =
+ "wake_up_and_send_active_source";
+
+ /**
+ * Property to decide the device behaviour when <Active Source> is lost.
+ *
+ * <p>This property applies to playback devices.
+ * <p>Possible values are:
+ * <ul>
+ * <li><b>none</b> No power state change (default).
+ * <li><b>standby_now</b> PowerManager.goToSleep() is called.
+ * </ul>
+ */
+ static final String POWER_STATE_CHANGE_ON_ACTIVE_SOURCE_LOST =
+ "ro.hdmi.cec.source.power_state_change_on_active_source_lost";
+
+ static final String POWER_STATE_CHANGE_ON_ACTIVE_SOURCE_LOST_NONE = "none";
+ static final String POWER_STATE_CHANGE_ON_ACTIVE_SOURCE_LOST_STANDBY_NOW = "standby_now";
+
static final int RECORDING_TYPE_DIGITAL_RF = 1;
static final int RECORDING_TYPE_ANALOGUE_RF = 2;
static final int RECORDING_TYPE_EXTERNAL_PHYSICAL_ADDRESS = 3;
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDevicePlayback.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDevicePlayback.java
index d6993b2b38e9..ef2781082a24 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDevicePlayback.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDevicePlayback.java
@@ -63,6 +63,14 @@ public class HdmiCecLocalDevicePlayback extends HdmiCecLocalDeviceSource {
// TODO(amyjojo): adding system constants for input ports to TIF mapping.
private int mLocalActivePath = 0;
+ // Determines what action should be taken upon receiving Routing Control messages.
+ @VisibleForTesting
+ protected String mPlaybackDeviceActionOnRoutingControl;
+
+ // Behaviour of the device when <Active Source> is lost in favor of another device.
+ @VisibleForTesting
+ protected String mPowerStateChangeOnActiveSourceLost;
+
HdmiCecLocalDevicePlayback(HdmiControlService service) {
super(service, HdmiDeviceInfo.DEVICE_PLAYBACK);
@@ -71,6 +79,14 @@ public class HdmiCecLocalDevicePlayback extends HdmiCecLocalDeviceSource {
// The option is false by default. Update settings db as well to have the right
// initial setting on UI.
mService.writeBooleanSetting(Global.HDMI_CONTROL_AUTO_DEVICE_OFF_ENABLED, mAutoTvOff);
+
+ mPlaybackDeviceActionOnRoutingControl = SystemProperties.get(
+ Constants.PLAYBACK_DEVICE_ACTION_ON_ROUTING_CONTROL,
+ Constants.PLAYBACK_DEVICE_ACTION_ON_ROUTING_CONTROL_NONE);
+
+ mPowerStateChangeOnActiveSourceLost = SystemProperties.get(
+ Constants.POWER_STATE_CHANGE_ON_ACTIVE_SOURCE_LOST,
+ Constants.POWER_STATE_CHANGE_ON_ACTIVE_SOURCE_LOST_NONE);
}
@Override
@@ -232,6 +248,28 @@ public class HdmiCecLocalDevicePlayback extends HdmiCecLocalDeviceSource {
return !getWakeLock().isHeld();
}
+ @Override
+ @ServiceThreadOnly
+ protected boolean handleActiveSource(HdmiCecMessage message) {
+ super.handleActiveSource(message);
+ if (mIsActiveSource) {
+ return true;
+ }
+ switch (mPowerStateChangeOnActiveSourceLost) {
+ case Constants.POWER_STATE_CHANGE_ON_ACTIVE_SOURCE_LOST_STANDBY_NOW:
+ mService.standby();
+ return true;
+ case Constants.POWER_STATE_CHANGE_ON_ACTIVE_SOURCE_LOST_NONE:
+ return true;
+ default:
+ Slog.w(TAG, "Invalid property '"
+ + Constants.POWER_STATE_CHANGE_ON_ACTIVE_SOURCE_LOST
+ + "' value: "
+ + mPowerStateChangeOnActiveSourceLost);
+ return true;
+ }
+ }
+
@ServiceThreadOnly
protected boolean handleUserControlPressed(HdmiCecMessage message) {
assertRunOnServiceThread();
@@ -323,6 +361,47 @@ public class HdmiCecLocalDevicePlayback extends HdmiCecLocalDeviceSource {
}
@Override
+ @ServiceThreadOnly
+ protected boolean handleRoutingChange(HdmiCecMessage message) {
+ assertRunOnServiceThread();
+ int physicalAddress = HdmiUtils.twoBytesToInt(message.getParams(), 2);
+ handleRoutingChangeAndInformation(physicalAddress, message);
+ return true;
+ }
+
+ @Override
+ @ServiceThreadOnly
+ protected boolean handleRoutingInformation(HdmiCecMessage message) {
+ assertRunOnServiceThread();
+ int physicalAddress = HdmiUtils.twoBytesToInt(message.getParams());
+ handleRoutingChangeAndInformation(physicalAddress, message);
+ return true;
+ }
+
+ @Override
+ protected void handleRoutingChangeAndInformation(int physicalAddress, HdmiCecMessage message) {
+ if (physicalAddress != mService.getPhysicalAddress()) {
+ return; // Do nothing.
+ }
+ switch (mPlaybackDeviceActionOnRoutingControl) {
+ case Constants.PLAYBACK_DEVICE_ACTION_ON_ROUTING_CONTROL_WAKE_UP_AND_SEND_ACTIVE_SOURCE:
+ setAndBroadcastActiveSource(message, physicalAddress);
+ break;
+ case Constants.PLAYBACK_DEVICE_ACTION_ON_ROUTING_CONTROL_WAKE_UP_ONLY:
+ mService.wakeUp();
+ break;
+ case Constants.PLAYBACK_DEVICE_ACTION_ON_ROUTING_CONTROL_NONE:
+ break;
+ default:
+ Slog.w(TAG, "Invalid property '"
+ + Constants.PLAYBACK_DEVICE_ACTION_ON_ROUTING_CONTROL
+ + "' value: "
+ + mPlaybackDeviceActionOnRoutingControl);
+ break;
+ }
+ }
+
+ @Override
protected int findKeyReceiverAddress() {
return Constants.ADDR_TV;
}
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceSource.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceSource.java
index df6b40dbbcb8..470a25bbae6c 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceSource.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceSource.java
@@ -199,7 +199,8 @@ abstract class HdmiCecLocalDeviceSource extends HdmiCecLocalDevice {
// do nothing
}
- // Source device with Switch functionality should implement this method.
+ // Only source devices that react to routing control messages should implement
+ // this method (e.g. a TV with built in switch).
// TODO(): decide which type will handle the routing when multi device type is supported
protected void handleRoutingChangeAndInformation(int physicalAddress, HdmiCecMessage message) {
// do nothing
diff --git a/services/core/java/com/android/server/hdmi/HdmiControlService.java b/services/core/java/com/android/server/hdmi/HdmiControlService.java
index 9de95abafdda..b9669c74a6df 100644
--- a/services/core/java/com/android/server/hdmi/HdmiControlService.java
+++ b/services/core/java/com/android/server/hdmi/HdmiControlService.java
@@ -40,6 +40,7 @@ import android.hardware.hdmi.HdmiControlManager;
import android.hardware.hdmi.HdmiDeviceInfo;
import android.hardware.hdmi.HdmiHotplugEvent;
import android.hardware.hdmi.HdmiPortInfo;
+import android.hardware.hdmi.IHdmiCecVolumeControlFeatureListener;
import android.hardware.hdmi.IHdmiControlCallback;
import android.hardware.hdmi.IHdmiControlService;
import android.hardware.hdmi.IHdmiControlStatusChangeListener;
@@ -63,6 +64,7 @@ import android.os.HandlerThread;
import android.os.IBinder;
import android.os.Looper;
import android.os.PowerManager;
+import android.os.RemoteCallbackList;
import android.os.RemoteException;
import android.os.SystemClock;
import android.os.SystemProperties;
@@ -268,6 +270,11 @@ public class HdmiControlService extends SystemService {
private final ArrayList<HdmiControlStatusChangeListenerRecord>
mHdmiControlStatusChangeListenerRecords = new ArrayList<>();
+ // List of records for HDMI control volume control status change listener for death monitoring.
+ @GuardedBy("mLock")
+ private final RemoteCallbackList<IHdmiCecVolumeControlFeatureListener>
+ mHdmiCecVolumeControlFeatureListenerRecords = new RemoteCallbackList<>();
+
// List of records for hotplug event listener to handle the the caller killed in action.
@GuardedBy("mLock")
private final ArrayList<HotplugEventListenerRecord> mHotplugEventListenerRecords =
@@ -1814,6 +1821,21 @@ public class HdmiControlService extends SystemService {
}
@Override
+ public void addHdmiCecVolumeControlFeatureListener(
+ final IHdmiCecVolumeControlFeatureListener listener) {
+ enforceAccessPermission();
+ HdmiControlService.this.addHdmiCecVolumeControlFeatureListener(listener);
+ }
+
+ @Override
+ public void removeHdmiCecVolumeControlFeatureListener(
+ final IHdmiCecVolumeControlFeatureListener listener) {
+ enforceAccessPermission();
+ HdmiControlService.this.removeHdmiControlVolumeControlStatusChangeListener(listener);
+ }
+
+
+ @Override
public void addHotplugEventListener(final IHdmiHotplugEventListener listener) {
enforceAccessPermission();
HdmiControlService.this.addHotplugEventListener(listener);
@@ -2409,6 +2431,33 @@ public class HdmiControlService extends SystemService {
}
}
+ @VisibleForTesting
+ void addHdmiCecVolumeControlFeatureListener(
+ final IHdmiCecVolumeControlFeatureListener listener) {
+ mHdmiCecVolumeControlFeatureListenerRecords.register(listener);
+
+ runOnServiceThread(new Runnable() {
+ @Override
+ public void run() {
+ // Return the current status of mHdmiCecVolumeControlEnabled;
+ synchronized (mLock) {
+ try {
+ listener.onHdmiCecVolumeControlFeature(mHdmiCecVolumeControlEnabled);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Failed to report HdmiControlVolumeControlStatusChange: "
+ + mHdmiCecVolumeControlEnabled, e);
+ }
+ }
+ }
+ });
+ }
+
+ @VisibleForTesting
+ void removeHdmiControlVolumeControlStatusChangeListener(
+ final IHdmiCecVolumeControlFeatureListener listener) {
+ mHdmiCecVolumeControlFeatureListenerRecords.unregister(listener);
+ }
+
private void addHotplugEventListener(final IHdmiHotplugEventListener listener) {
final HotplugEventListenerRecord record = new HotplugEventListenerRecord(listener);
try {
@@ -2682,6 +2731,19 @@ public class HdmiControlService extends SystemService {
}
}
+ private void announceHdmiCecVolumeControlFeatureChange(boolean isEnabled) {
+ assertRunOnServiceThread();
+ mHdmiCecVolumeControlFeatureListenerRecords.broadcast(listener -> {
+ try {
+ listener.onHdmiCecVolumeControlFeature(isEnabled);
+ } catch (RemoteException e) {
+ Slog.e(TAG,
+ "Failed to report HdmiControlVolumeControlStatusChange: "
+ + isEnabled);
+ }
+ });
+ }
+
public HdmiCecLocalDeviceTv tv() {
return (HdmiCecLocalDeviceTv) mCecController.getLocalDevice(HdmiDeviceInfo.DEVICE_TV);
}
@@ -3026,6 +3088,7 @@ public class HdmiControlService extends SystemService {
isHdmiCecVolumeControlEnabled);
}
}
+ announceHdmiCecVolumeControlFeatureChange(isHdmiCecVolumeControlEnabled);
}
boolean isHdmiCecVolumeControlEnabled() {
diff --git a/services/core/java/com/android/server/hdmi/SystemAudioStatusAction.java b/services/core/java/com/android/server/hdmi/SystemAudioStatusAction.java
index 13f0f4ae4a92..5d913d12b79f 100644
--- a/services/core/java/com/android/server/hdmi/SystemAudioStatusAction.java
+++ b/services/core/java/com/android/server/hdmi/SystemAudioStatusAction.java
@@ -64,12 +64,6 @@ final class SystemAudioStatusAction extends HdmiCecFeatureAction {
}
private void handleSendGiveAudioStatusFailure() {
- // Inform to all application that the audio status (volume, mute) of
- // the audio amplifier is unknown.
- tv().setAudioStatus(false, Constants.UNKNOWN_VOLUME);
-
- sendUserControlPressedAndReleased(mAvrAddress,
- HdmiCecKeycode.getMuteKey(!tv().isSystemAudioActivated()));
// Still return SUCCESS to callback.
finishWithCallback(HdmiControlManager.RESULT_SUCCESS);
diff --git a/services/core/java/com/android/server/location/LocationManagerService.java b/services/core/java/com/android/server/location/LocationManagerService.java
index ccbe96f30e04..bfcbe465a271 100644
--- a/services/core/java/com/android/server/location/LocationManagerService.java
+++ b/services/core/java/com/android/server/location/LocationManagerService.java
@@ -28,6 +28,9 @@ import static android.os.PowerManager.locationPowerSaveModeToString;
import static com.android.server.location.CallerIdentity.PERMISSION_COARSE;
import static com.android.server.location.CallerIdentity.PERMISSION_FINE;
+import static com.android.server.location.UserInfoHelper.UserListener.CURRENT_USER_CHANGED;
+import static com.android.server.location.UserInfoHelper.UserListener.USER_STARTED;
+import static com.android.server.location.UserInfoHelper.UserListener.USER_STOPPED;
import static java.util.concurrent.TimeUnit.NANOSECONDS;
@@ -64,6 +67,7 @@ import android.location.LocationProvider;
import android.location.LocationRequest;
import android.location.LocationTime;
import android.os.Binder;
+import android.os.Build;
import android.os.Bundle;
import android.os.CancellationSignal;
import android.os.Handler;
@@ -101,7 +105,7 @@ import com.android.server.location.AbstractLocationProvider.State;
import com.android.server.location.CallerIdentity.PermissionLevel;
import com.android.server.location.LocationRequestStatistics.PackageProviderKey;
import com.android.server.location.LocationRequestStatistics.PackageStatistics;
-import com.android.server.location.UserInfoHelper.UserListener;
+import com.android.server.location.UserInfoHelper.UserListener.UserChange;
import com.android.server.location.gnss.GnssManagerService;
import com.android.server.pm.permission.PermissionManagerServiceInternal;
@@ -132,11 +136,13 @@ public class LocationManagerService extends ILocationManager.Stub {
*/
public static class Lifecycle extends SystemService {
+ private final UserInfoHelper mUserInfoHelper;
private final LocationManagerService mService;
public Lifecycle(Context context) {
super(context);
- mService = new LocationManagerService(context);
+ mUserInfoHelper = new SystemUserInfoHelper(context);
+ mService = new LocationManagerService(context, mUserInfoHelper);
}
@Override
@@ -161,6 +167,29 @@ public class LocationManagerService extends ILocationManager.Stub {
mService.onSystemThirdPartyAppsCanStart();
}
}
+
+ @Override
+ public void onUserStarting(TargetUser user) {
+ mUserInfoHelper.dispatchOnUserStarted(user.getUserIdentifier());
+ }
+
+ @Override
+ public void onUserSwitching(TargetUser from, TargetUser to) {
+ mUserInfoHelper.dispatchOnCurrentUserChanged(from.getUserIdentifier(),
+ to.getUserIdentifier());
+ }
+
+ @Override
+ public void onUserStopped(TargetUser user) {
+ mUserInfoHelper.dispatchOnUserStopped(user.getUserIdentifier());
+ }
+
+ private static class SystemUserInfoHelper extends UserInfoHelper {
+
+ SystemUserInfoHelper(Context context) {
+ super(context);
+ }
+ }
}
public static final String TAG = "LocationManagerService";
@@ -202,7 +231,7 @@ public class LocationManagerService extends ILocationManager.Stub {
private final AppForegroundHelper mAppForegroundHelper;
private final LocationUsageLogger mLocationUsageLogger;
- @Nullable private GnssManagerService mGnssManagerService = null;
+ @Nullable private volatile GnssManagerService mGnssManagerService = null;
private final PassiveLocationProviderManager mPassiveManager;
@@ -232,7 +261,7 @@ public class LocationManagerService extends ILocationManager.Stub {
@PowerManager.LocationPowerSaveMode
private int mBatterySaverMode;
- private LocationManagerService(Context context) {
+ private LocationManagerService(Context context, UserInfoHelper userInfoHelper) {
mContext = context.createAttributionContext(ATTRIBUTION_TAG);
mHandler = FgThread.getHandler();
mLocalService = new LocalService();
@@ -240,7 +269,7 @@ public class LocationManagerService extends ILocationManager.Stub {
LocalServices.addService(LocationManagerInternal.class, mLocalService);
mAppOpsHelper = new AppOpsHelper(mContext);
- mUserInfoHelper = new UserInfoHelper(mContext);
+ mUserInfoHelper = userInfoHelper;
mSettingsHelper = new SettingsHelper(mContext, mHandler);
mAppForegroundHelper = new AppForegroundHelper(mContext);
mLocationUsageLogger = new LocationUsageLogger();
@@ -342,7 +371,7 @@ public class LocationManagerService extends ILocationManager.Stub {
// initialize the current users. we would get the user started notifications for these
// users eventually anyways, but this takes care of it as early as possible.
for (int userId: mUserInfoHelper.getCurrentUserIds()) {
- onUserChanged(userId, UserListener.USER_STARTED);
+ onUserChanged(userId, USER_STARTED);
}
}
}
@@ -352,6 +381,10 @@ public class LocationManagerService extends ILocationManager.Stub {
// prepare providers
initializeProvidersLocked();
}
+
+ // initialize gnss last because it has no awareness of boot phases and blindly assumes that
+ // all other location providers are loaded at initialization
+ initializeGnss();
}
private void onAppOpChanged(String packageName) {
@@ -573,16 +606,19 @@ public class LocationManagerService extends ILocationManager.Stub {
}
manager.setMockProvider(new MockProvider(properties));
}
+ }
- // initialize gnss last because it has no awareness of boot phases and blindly assumes that
- // all other location providers are loaded at initialization
+ private void initializeGnss() {
+ // Do not hold mLock when calling GnssManagerService#isGnssSupported() which calls into HAL.
if (GnssManagerService.isGnssSupported()) {
mGnssManagerService = new GnssManagerService(mContext, mAppOpsHelper, mSettingsHelper,
mAppForegroundHelper, mLocationUsageLogger);
mGnssManagerService.onSystemReady();
LocationProviderManager gnssManager = new LocationProviderManager(GPS_PROVIDER);
- mProviderManagers.add(gnssManager);
+ synchronized (mLock) {
+ mProviderManagers.add(gnssManager);
+ }
gnssManager.setRealProvider(mGnssManagerService.getGnssLocationProvider());
// bind to geofence proxy
@@ -596,32 +632,23 @@ public class LocationManagerService extends ILocationManager.Stub {
}
}
- private void onUserChanged(@UserIdInt int userId, @UserListener.UserChange int change) {
+ private void onUserChanged(@UserIdInt int userId, @UserChange int change) {
switch (change) {
- case UserListener.USER_SWITCHED:
- if (D) {
- Log.d(TAG, "user " + userId + " current status changed");
- }
+ case CURRENT_USER_CHANGED:
synchronized (mLock) {
for (LocationProviderManager manager : mProviderManagers) {
manager.onEnabledChangedLocked(userId);
}
}
break;
- case UserListener.USER_STARTED:
- if (D) {
- Log.d(TAG, "user " + userId + " started");
- }
+ case USER_STARTED:
synchronized (mLock) {
for (LocationProviderManager manager : mProviderManagers) {
manager.onUserStarted(userId);
}
}
break;
- case UserListener.USER_STOPPED:
- if (D) {
- Log.d(TAG, "user " + userId + " stopped");
- }
+ case USER_STOPPED:
synchronized (mLock) {
for (LocationProviderManager manager : mProviderManagers) {
manager.onUserStopped(userId);
@@ -957,10 +984,22 @@ public class LocationManagerService extends ILocationManager.Stub {
pw.increaseIndent();
// for now we only dump for the parent user
- int userId = mUserInfoHelper.getCurrentUserIds()[0];
- pw.println("last location=" + mLastLocation.get(userId));
- pw.println("last coarse location=" + mLastCoarseLocation.get(userId));
- pw.println("enabled=" + isEnabled(userId));
+ int[] userIds = mUserInfoHelper.getCurrentUserIds();
+ if (userIds.length == 1) {
+ int userId = userIds[0];
+ pw.println("last location=" + mLastLocation.get(userId));
+ pw.println("last coarse location=" + mLastCoarseLocation.get(userId));
+ pw.println("enabled=" + isEnabled(userId));
+ } else {
+ for (int userId : userIds) {
+ pw.println("user " + userId + ":");
+ pw.increaseIndent();
+ pw.println("last location=" + mLastLocation.get(userId));
+ pw.println("last coarse location=" + mLastCoarseLocation.get(userId));
+ pw.println("enabled=" + isEnabled(userId));
+ pw.decreaseIndent();
+ }
+ }
}
mProvider.dump(fd, pw, args);
@@ -1666,6 +1705,9 @@ public class LocationManagerService extends ILocationManager.Stub {
* Note: must be constructed with lock held.
*/
private UpdateRecord(String provider, LocationRequest request, Receiver receiver) {
+ if (Build.IS_DEBUGGABLE) {
+ Preconditions.checkState(Thread.holdsLock(mLock));
+ }
mExpirationRealtimeMs = request.getExpirationRealtimeMs(SystemClock.elapsedRealtime());
mProvider = provider;
mRealRequest = request;
@@ -1703,6 +1745,10 @@ public class LocationManagerService extends ILocationManager.Stub {
* Method to be called when a record will no longer be used.
*/
private void disposeLocked(boolean removeReceiver) {
+ if (Build.IS_DEBUGGABLE) {
+ Preconditions.checkState(Thread.holdsLock(mLock));
+ }
+
CallerIdentity identity = mReceiver.mCallerIdentity;
mRequestStatistics.stopRequesting(identity.packageName, identity.featureId, mProvider);
diff --git a/services/core/java/com/android/server/location/UserInfoHelper.java b/services/core/java/com/android/server/location/UserInfoHelper.java
index a3dcc40bdf2d..53bff8eacb4c 100644
--- a/services/core/java/com/android/server/location/UserInfoHelper.java
+++ b/services/core/java/com/android/server/location/UserInfoHelper.java
@@ -20,48 +20,48 @@ import static android.os.UserManager.DISALLOW_SHARE_LOCATION;
import static com.android.server.location.LocationManagerService.D;
import static com.android.server.location.LocationManagerService.TAG;
+import static com.android.server.location.UserInfoHelper.UserListener.CURRENT_USER_CHANGED;
+import static com.android.server.location.UserInfoHelper.UserListener.USER_STARTED;
+import static com.android.server.location.UserInfoHelper.UserListener.USER_STOPPED;
+import android.annotation.CallSuper;
import android.annotation.IntDef;
import android.annotation.Nullable;
import android.annotation.UserIdInt;
-import android.app.ActivityManager;
-import android.content.BroadcastReceiver;
+import android.app.ActivityManagerInternal;
import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
import android.os.Binder;
-import android.os.Build;
import android.os.UserHandle;
import android.os.UserManager;
import android.util.Log;
import com.android.internal.annotations.GuardedBy;
-import com.android.internal.util.ArrayUtils;
import com.android.internal.util.Preconditions;
-import com.android.server.FgThread;
+import com.android.server.LocalServices;
import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.Arrays;
+import java.util.Objects;
import java.util.concurrent.CopyOnWriteArrayList;
/**
* Provides accessors and listeners for all user info.
*/
-public class UserInfoHelper {
+public abstract class UserInfoHelper {
/**
* Listener for current user changes.
*/
public interface UserListener {
- int USER_SWITCHED = 1;
+ int CURRENT_USER_CHANGED = 1;
int USER_STARTED = 2;
int USER_STOPPED = 3;
- @IntDef({USER_SWITCHED, USER_STARTED, USER_STOPPED})
+ @IntDef({CURRENT_USER_CHANGED, USER_STARTED, USER_STOPPED})
@Retention(RetentionPolicy.SOURCE)
@interface UserChange {}
@@ -75,143 +75,101 @@ public class UserInfoHelper {
private final CopyOnWriteArrayList<UserListener> mListeners;
@GuardedBy("this")
- @Nullable private UserManager mUserManager;
-
- @UserIdInt private volatile int mCurrentUserId;
-
+ @Nullable private ActivityManagerInternal mActivityManagerInternal;
@GuardedBy("this")
- @UserIdInt private int mCachedParentUserId;
- @GuardedBy("this")
- private int[] mCachedProfileUserIds;
+ @Nullable private UserManager mUserManager;
public UserInfoHelper(Context context) {
mContext = context;
mListeners = new CopyOnWriteArrayList<>();
-
- mCurrentUserId = UserHandle.USER_NULL;
- mCachedParentUserId = UserHandle.USER_NULL;
- mCachedProfileUserIds = new int[]{UserHandle.USER_NULL};
}
/** Called when system is ready. */
+ @CallSuper
public synchronized void onSystemReady() {
- if (mUserManager != null) {
+ if (mActivityManagerInternal != null) {
return;
}
+ mActivityManagerInternal = Objects.requireNonNull(
+ LocalServices.getService(ActivityManagerInternal.class));
mUserManager = mContext.getSystemService(UserManager.class);
-
- IntentFilter intentFilter = new IntentFilter();
- intentFilter.addAction(Intent.ACTION_USER_SWITCHED);
- intentFilter.addAction(Intent.ACTION_USER_STARTED);
- intentFilter.addAction(Intent.ACTION_USER_STOPPED);
- intentFilter.addAction(Intent.ACTION_MANAGED_PROFILE_ADDED);
- intentFilter.addAction(Intent.ACTION_MANAGED_PROFILE_REMOVED);
-
- mContext.registerReceiverAsUser(new BroadcastReceiver() {
- @Override
- public void onReceive(Context context, Intent intent) {
- String action = intent.getAction();
- if (action == null) {
- return;
- }
- int userId;
- switch (action) {
- case Intent.ACTION_USER_SWITCHED:
- userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, UserHandle.USER_NULL);
- if (userId != UserHandle.USER_NULL) {
- onCurrentUserChanged(userId);
- }
- break;
- case Intent.ACTION_USER_STARTED:
- userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, UserHandle.USER_NULL);
- if (userId != UserHandle.USER_NULL) {
- onUserStarted(userId);
- }
- break;
- case Intent.ACTION_USER_STOPPED:
- userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, UserHandle.USER_NULL);
- if (userId != UserHandle.USER_NULL) {
- onUserStopped(userId);
- }
- break;
- case Intent.ACTION_MANAGED_PROFILE_ADDED:
- case Intent.ACTION_MANAGED_PROFILE_REMOVED:
- onUserProfilesChanged();
- break;
- }
- }
- }, UserHandle.ALL, intentFilter, null, FgThread.getHandler());
-
- mCurrentUserId = ActivityManager.getCurrentUser();
}
/**
* Adds a listener for user changed events. Callbacks occur on an unspecified thread.
*/
- public void addListener(UserListener listener) {
+ public final void addListener(UserListener listener) {
mListeners.add(listener);
}
/**
* Removes a listener for user changed events.
*/
- public void removeListener(UserListener listener) {
+ public final void removeListener(UserListener listener) {
mListeners.remove(listener);
}
- private void onCurrentUserChanged(@UserIdInt int newUserId) {
- if (newUserId == mCurrentUserId) {
- return;
- }
-
+ protected void dispatchOnUserStarted(@UserIdInt int userId) {
if (D) {
- Log.d(TAG, "current user switched from u" + mCurrentUserId + " to u" + newUserId);
+ Log.d(TAG, "u" + userId + " started");
}
- int oldUserId = mCurrentUserId;
- mCurrentUserId = newUserId;
-
- onUserChanged(oldUserId, UserListener.USER_SWITCHED);
- onUserChanged(newUserId, UserListener.USER_SWITCHED);
+ for (UserListener listener : mListeners) {
+ listener.onUserChanged(userId, USER_STARTED);
+ }
}
- private void onUserStarted(@UserIdInt int userId) {
+ protected void dispatchOnUserStopped(@UserIdInt int userId) {
if (D) {
- Log.d(TAG, "u" + userId + " started");
+ Log.d(TAG, "u" + userId + " stopped");
}
- onUserChanged(userId, UserListener.USER_STARTED);
+ for (UserListener listener : mListeners) {
+ listener.onUserChanged(userId, USER_STOPPED);
+ }
}
- private void onUserStopped(@UserIdInt int userId) {
+ protected void dispatchOnCurrentUserChanged(@UserIdInt int fromUserId,
+ @UserIdInt int toUserId) {
+ int[] fromUserIds = getProfileIds(fromUserId);
+ int[] toUserIds = getProfileIds(toUserId);
if (D) {
- Log.d(TAG, "u" + userId + " stopped");
+ Log.d(TAG, "current user changed from u" + Arrays.toString(fromUserIds) + " to u"
+ + Arrays.toString(toUserIds));
}
- onUserChanged(userId, UserListener.USER_STOPPED);
- }
-
- private void onUserChanged(@UserIdInt int userId, @UserListener.UserChange int change) {
for (UserListener listener : mListeners) {
- listener.onUserChanged(userId, change);
+ for (int userId : fromUserIds) {
+ listener.onUserChanged(userId, CURRENT_USER_CHANGED);
+ }
}
- }
- private synchronized void onUserProfilesChanged() {
- // this intent is only sent to the current user
- if (mCachedParentUserId == mCurrentUserId) {
- mCachedParentUserId = UserHandle.USER_NULL;
- mCachedProfileUserIds = new int[]{UserHandle.USER_NULL};
+ for (UserListener listener : mListeners) {
+ for (int userId : toUserIds) {
+ listener.onUserChanged(userId, CURRENT_USER_CHANGED);
+ }
}
}
/**
* Returns an array of current user ids. This will always include the current user, and will
- * also include any profiles of the current user.
+ * also include any profiles of the current user. The caller must never mutate the returned
+ * array.
*/
public int[] getCurrentUserIds() {
- return getProfileUserIdsForParentUser(mCurrentUserId);
+ synchronized (this) {
+ if (mActivityManagerInternal == null) {
+ return new int[] {};
+ }
+ }
+
+ long identity = Binder.clearCallingIdentity();
+ try {
+ return mActivityManagerInternal.getCurrentProfileIds();
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
}
/**
@@ -219,54 +177,47 @@ public class UserInfoHelper {
* user.
*/
public boolean isCurrentUserId(@UserIdInt int userId) {
- int currentUserId = mCurrentUserId;
- return userId == currentUserId || ArrayUtils.contains(
- getProfileUserIdsForParentUser(currentUserId), userId);
- }
+ synchronized (this) {
+ if (mActivityManagerInternal == null) {
+ return false;
+ }
+ }
- @GuardedBy("this")
- private synchronized int[] getProfileUserIdsForParentUser(@UserIdInt int parentUserId) {
- if (parentUserId != mCachedParentUserId) {
- long identity = Binder.clearCallingIdentity();
- try {
- Preconditions.checkState(mUserManager != null);
-
- // more expensive check - check that argument really is a parent user id
- if (Build.IS_DEBUGGABLE) {
- Preconditions.checkArgument(
- mUserManager.getProfileParent(parentUserId) == null);
- }
+ long identity = Binder.clearCallingIdentity();
+ try {
+ return mActivityManagerInternal.isCurrentProfile(userId);
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
+ }
- mCachedParentUserId = parentUserId;
- mCachedProfileUserIds = mUserManager.getProfileIdsWithDisabled(parentUserId);
- } finally {
- Binder.restoreCallingIdentity(identity);
- }
+ private int[] getProfileIds(@UserIdInt int userId) {
+ synchronized (this) {
+ Preconditions.checkState(mUserManager != null);
}
- return mCachedProfileUserIds;
+ long identity = Binder.clearCallingIdentity();
+ try {
+ return mUserManager.getEnabledProfileIds(userId);
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
}
/**
* Dump info for debugging.
*/
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
- boolean systemRunning;
- synchronized (this) {
- systemRunning = mUserManager != null;
- }
-
- if (systemRunning) {
- int[] currentUserIds = getProfileUserIdsForParentUser(mCurrentUserId);
- pw.println("current users: " + Arrays.toString(currentUserIds));
- for (int userId : currentUserIds) {
- if (mUserManager.hasUserRestrictionForUser(DISALLOW_SHARE_LOCATION,
+ int[] currentUserProfiles = getCurrentUserIds();
+ pw.println("current users: " + Arrays.toString(currentUserProfiles));
+ UserManager userManager = mContext.getSystemService(UserManager.class);
+ if (userManager != null) {
+ for (int userId : currentUserProfiles) {
+ if (userManager.hasUserRestrictionForUser(DISALLOW_SHARE_LOCATION,
UserHandle.of(userId))) {
pw.println(" u" + userId + " restricted");
}
}
- } else {
- pw.println("current user: " + mCurrentUserId);
}
}
}
diff --git a/services/core/java/com/android/server/locksettings/ManagedProfilePasswordCache.java b/services/core/java/com/android/server/locksettings/ManagedProfilePasswordCache.java
index d38ee678c7aa..7950fcf7234c 100644
--- a/services/core/java/com/android/server/locksettings/ManagedProfilePasswordCache.java
+++ b/services/core/java/com/android/server/locksettings/ManagedProfilePasswordCache.java
@@ -104,8 +104,6 @@ public class ManagedProfilePasswordCache {
// Generate auth-bound key to user 0 (since we the caller is user 0)
.setUserAuthenticationRequired(true)
.setUserAuthenticationValidityDurationSeconds(CACHE_TIMEOUT_SECONDS)
- // Only accessible after user 0's keyguard is unlocked
- .setUnlockedDeviceRequired(true)
.build());
key = generator.generateKey();
} catch (GeneralSecurityException e) {
@@ -171,10 +169,14 @@ public class ManagedProfilePasswordCache {
public void removePassword(int userId) {
synchronized (mEncryptedPasswords) {
String keyName = getEncryptionKeyName(userId);
+ String legacyKeyName = getLegacyEncryptionKeyName(userId);
try {
if (mKeyStore.containsAlias(keyName)) {
mKeyStore.deleteEntry(keyName);
}
+ if (mKeyStore.containsAlias(legacyKeyName)) {
+ mKeyStore.deleteEntry(legacyKeyName);
+ }
} catch (KeyStoreException e) {
Slog.d(TAG, "Cannot delete key", e);
}
@@ -186,6 +188,14 @@ public class ManagedProfilePasswordCache {
}
private static String getEncryptionKeyName(int userId) {
+ return "com.android.server.locksettings.unified_profile_cache_v2_" + userId;
+ }
+
+ /**
+ * Returns the legacy keystore key name when setUnlockedDeviceRequired() was set explicitly.
+ * Only existed during Android 11 internal testing period.
+ */
+ private static String getLegacyEncryptionKeyName(int userId) {
return "com.android.server.locksettings.unified_profile_cache_" + userId;
}
}
diff --git a/services/core/java/com/android/server/media/MediaKeyDispatcher.java b/services/core/java/com/android/server/media/MediaKeyDispatcher.java
index 3a29622556cc..176ec3f003ea 100644
--- a/services/core/java/com/android/server/media/MediaKeyDispatcher.java
+++ b/services/core/java/com/android/server/media/MediaKeyDispatcher.java
@@ -19,6 +19,7 @@ package com.android.server.media;
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.app.PendingIntent;
import android.media.session.ISessionManager;
import android.media.session.MediaSession;
import android.os.Binder;
@@ -76,6 +77,9 @@ public abstract class MediaKeyDispatcher {
/**
* Implement this to customize the logic for which MediaSession should consume which key event.
*
+ * Note: This session will have greater priority over the {@link PendingIntent} returned from
+ * {@link #getMediaButtonReceiver(KeyEvent, int, boolean)}.
+ *
* @param keyEvent a non-null KeyEvent whose key code is one of the supported media buttons.
* @param uid the uid value retrieved by calling {@link Binder#getCallingUid()} from
* {@link ISessionManager#dispatchMediaKeyEvent(String, boolean, KeyEvent, boolean)}
@@ -84,7 +88,27 @@ public abstract class MediaKeyDispatcher {
* @return a {@link MediaSession.Token} instance that should consume the given key event.
*/
@Nullable
- MediaSession.Token getSessionForKeyEvent(@NonNull KeyEvent keyEvent, int uid,
+ MediaSession.Token getMediaSession(@NonNull KeyEvent keyEvent, int uid,
+ boolean asSystemService) {
+ return null;
+ }
+
+ /**
+ * Implement this to customize the logic for which MediaButtonReceiver should consume a
+ * dispatched key event.
+ *
+ * Note: This pending intent will have lower priority over the {@link MediaSession.Token}
+ * returned from {@link #getMediaSession(KeyEvent, int, boolean)}.
+ *
+ * @param keyEvent a non-null KeyEvent whose key code is one of the supported media buttons.
+ * @param uid the uid value retrieved by calling {@link Binder#getCallingUid()} from
+ * {@link ISessionManager#dispatchMediaKeyEvent(String, boolean, KeyEvent, boolean)}
+ * @param asSystemService {@code true} if the event came from the system service via hardware
+ * devices. {@code false} if the event came from the app process through key injection.
+ * @return a {@link PendingIntent} instance that should receive the dispatched key event.
+ */
+ @Nullable
+ PendingIntent getMediaButtonReceiver(@NonNull KeyEvent keyEvent, int uid,
boolean asSystemService) {
return null;
}
diff --git a/services/core/java/com/android/server/media/MediaRoute2ProviderServiceProxy.java b/services/core/java/com/android/server/media/MediaRoute2ProviderServiceProxy.java
index 53205add0b38..d6b98e2de901 100644
--- a/services/core/java/com/android/server/media/MediaRoute2ProviderServiceProxy.java
+++ b/services/core/java/com/android/server/media/MediaRoute2ProviderServiceProxy.java
@@ -44,7 +44,6 @@ import java.util.Objects;
/**
* Maintains a connection to a particular {@link MediaRoute2ProviderService}.
*/
-// TODO: Need to revisit the bind/unbind/connect/disconnect logic in this class.
final class MediaRoute2ProviderServiceProxy extends MediaRoute2Provider
implements ServiceConnection {
private static final String TAG = "MR2ProviderSvcProxy";
@@ -265,8 +264,6 @@ final class MediaRoute2ProviderServiceProxy extends MediaRoute2Provider
if (DEBUG) {
Slog.d(TAG, this + ": Service binding died");
}
- // TODO: Investigate whether it tries to bind endlessly when the service is
- // badly implemented.
if (shouldBind()) {
unbind();
bind();
diff --git a/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java b/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java
index c65800a17f82..c12f89c25a9e 100644
--- a/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java
+++ b/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java
@@ -584,7 +584,7 @@ class MediaRouter2ServiceImpl {
mAllRouterRecords.put(binder, routerRecord);
userRecord.mHandler.sendMessage(
- obtainMessage(UserHandler::notifyRoutesToRouter,
+ obtainMessage(UserHandler::notifyRouterRegistered,
userRecord.mHandler, routerRecord));
}
@@ -1026,7 +1026,8 @@ class MediaRouter2ServiceImpl {
mHandler = new UserHandler(MediaRouter2ServiceImpl.this, this);
}
- // TODO: This assumes that only one router exists in a package. Is it true?
+ // TODO: This assumes that only one router exists in a package.
+ // Do this in Android S or later.
RouterRecord findRouterRecordLocked(String packageName) {
for (RouterRecord routerRecord : mRouterRecords) {
if (TextUtils.equals(routerRecord.mPackageName, packageName)) {
@@ -1121,7 +1122,6 @@ class MediaRouter2ServiceImpl {
private final UserRecord mUserRecord;
private final MediaRoute2ProviderWatcher mWatcher;
- //TODO: Make this thread-safe.
private final SystemMediaRoute2Provider mSystemProvider;
private final ArrayList<MediaRoute2Provider> mRouteProviders =
new ArrayList<>();
@@ -1153,7 +1153,6 @@ class MediaRouter2ServiceImpl {
private void stop() {
if (mRunning) {
mRunning = false;
- //TODO: may unselect routes
mWatcher.stop(); // also stops all providers
}
}
@@ -1386,7 +1385,6 @@ class MediaRouter2ServiceImpl {
final String providerId = route.getProviderId();
final MediaRoute2Provider provider = findProvider(providerId);
- // TODO: Remove this null check when the mMediaProviders are referenced only in handler.
if (provider == null) {
return;
}
@@ -1405,7 +1403,6 @@ class MediaRouter2ServiceImpl {
final String providerId = route.getProviderId();
final MediaRoute2Provider provider = findProvider(providerId);
- // TODO: Remove this null check when the mMediaProviders are referenced only in handler.
if (provider == null) {
return;
}
@@ -1425,7 +1422,6 @@ class MediaRouter2ServiceImpl {
final String providerId = route.getProviderId();
final MediaRoute2Provider provider = findProvider(providerId);
- // TODO: Remove this null check when the mMediaProviders are referenced only in handler.
if (provider == null) {
return;
}
@@ -1587,7 +1583,7 @@ class MediaRouter2ServiceImpl {
private void onSessionInfoChangedOnHandler(@NonNull MediaRoute2Provider provider,
@NonNull RoutingSessionInfo sessionInfo) {
List<IMediaRouter2Manager> managers = getManagers();
- notifySessionInfoChangedToManagers(managers, sessionInfo);
+ notifySessionUpdatedToManagers(managers, sessionInfo);
// For system provider, notify all routers.
if (provider == mSystemProvider) {
@@ -1612,7 +1608,7 @@ class MediaRouter2ServiceImpl {
private void onSessionReleasedOnHandler(@NonNull MediaRoute2Provider provider,
@NonNull RoutingSessionInfo sessionInfo) {
List<IMediaRouter2Manager> managers = getManagers();
- notifySessionInfoChangedToManagers(managers, sessionInfo);
+ notifySessionReleasedToManagers(managers, sessionInfo);
RouterRecord routerRecord = mSessionToRouterMap.get(sessionInfo.getId());
if (routerRecord == null) {
@@ -1641,8 +1637,8 @@ class MediaRouter2ServiceImpl {
// TODO: Notify router too when the related callback is introduced.
}
- // TODO: Find a way to prevent providers from notifying error on random uniqueRequestId.
- // Solutions can be:
+ // TODO(b/157873556): Find a way to prevent providers from notifying error on random reqID.
+ // Possible solutions can be:
// 1) Record the other type of requests too (not only session creation request)
// 2) Throw exception on providers when they try to notify error on
// random uniqueRequestId.
@@ -1773,8 +1769,8 @@ class MediaRouter2ServiceImpl {
}
}
- private void notifyRoutesToRouter(@NonNull RouterRecord routerRecord) {
- List<MediaRoute2Info> routes = new ArrayList<>();
+ private void notifyRouterRegistered(@NonNull RouterRecord routerRecord) {
+ List<MediaRoute2Info> currentRoutes = new ArrayList<>();
MediaRoute2ProviderInfo systemProviderInfo = null;
for (MediaRoute2ProviderInfo providerInfo : mLastProviderInfos) {
@@ -1784,27 +1780,32 @@ class MediaRouter2ServiceImpl {
systemProviderInfo = providerInfo;
continue;
}
- routes.addAll(providerInfo.getRoutes());
+ currentRoutes.addAll(providerInfo.getRoutes());
}
+ RoutingSessionInfo currentSystemSessionInfo;
if (routerRecord.mHasModifyAudioRoutingPermission) {
if (systemProviderInfo != null) {
- routes.addAll(systemProviderInfo.getRoutes());
+ currentRoutes.addAll(systemProviderInfo.getRoutes());
} else {
// This shouldn't happen.
Slog.w(TAG, "notifyRoutesToRouter: System route provider not found.");
}
+ currentSystemSessionInfo = mSystemProvider.getSessionInfos().get(0);
} else {
- routes.add(mSystemProvider.getDefaultRoute());
+ currentRoutes.add(mSystemProvider.getDefaultRoute());
+ currentSystemSessionInfo = mSystemProvider.getDefaultSessionInfo();
}
- if (routes.size() == 0) {
+ if (currentRoutes.size() == 0) {
return;
}
+
try {
- routerRecord.mRouter.notifyRoutesAdded(routes);
+ routerRecord.mRouter.notifyRouterRegistered(
+ currentRoutes, currentSystemSessionInfo);
} catch (RemoteException ex) {
- Slog.w(TAG, "Failed to notify all routes. Router probably died.", ex);
+ Slog.w(TAG, "Failed to notify router registered. Router probably died.", ex);
}
}
@@ -1912,15 +1913,28 @@ class MediaRouter2ServiceImpl {
}
}
- private void notifySessionInfoChangedToManagers(
+ private void notifySessionUpdatedToManagers(
@NonNull List<IMediaRouter2Manager> managers,
@NonNull RoutingSessionInfo sessionInfo) {
for (IMediaRouter2Manager manager : managers) {
try {
manager.notifySessionUpdated(sessionInfo);
} catch (RemoteException ex) {
- Slog.w(TAG, "notifySessionInfosChangedToManagers: "
- + "failed to notify. Manager probably died.", ex);
+ Slog.w(TAG, "notifySessionUpdatedToManagers: "
+ + "Failed to notify. Manager probably died.", ex);
+ }
+ }
+ }
+
+ private void notifySessionReleasedToManagers(
+ @NonNull List<IMediaRouter2Manager> managers,
+ @NonNull RoutingSessionInfo sessionInfo) {
+ for (IMediaRouter2Manager manager : managers) {
+ try {
+ manager.notifySessionReleased(sessionInfo);
+ } catch (RemoteException ex) {
+ Slog.w(TAG, "notifySessionReleasedToManagers: "
+ + "Failed to notify. Manager probably died.", ex);
}
}
}
diff --git a/services/core/java/com/android/server/media/MediaSessionService.java b/services/core/java/com/android/server/media/MediaSessionService.java
index f360a4ae7ad8..afae20dcf525 100644
--- a/services/core/java/com/android/server/media/MediaSessionService.java
+++ b/services/core/java/com/android/server/media/MediaSessionService.java
@@ -2404,18 +2404,32 @@ public class MediaSessionService extends SystemService implements Monitor {
return;
}
MediaSessionRecord session = null;
+ MediaButtonReceiverHolder mediaButtonReceiverHolder = null;
- // Retrieve custom session for key event if it exists.
if (mCustomMediaKeyDispatcher != null) {
- MediaSession.Token token = mCustomMediaKeyDispatcher.getSessionForKeyEvent(
- keyEvent, uid, asSystemService);
+ MediaSession.Token token = mCustomMediaKeyDispatcher.getMediaSession(keyEvent, uid,
+ asSystemService);
if (token != null) {
session = getMediaSessionRecordLocked(token);
}
+
+ if (session == null) {
+ PendingIntent pi = mCustomMediaKeyDispatcher.getMediaButtonReceiver(keyEvent,
+ uid, asSystemService);
+ if (pi != null) {
+ mediaButtonReceiverHolder = MediaButtonReceiverHolder.create(mContext,
+ mCurrentFullUserRecord.mFullUserId, pi);
+ }
+ }
}
- if (session == null) {
+ if (session == null && mediaButtonReceiverHolder == null) {
session = (MediaSessionRecord) mCurrentFullUserRecord.getMediaButtonSessionLocked();
+
+ if (session == null) {
+ mediaButtonReceiverHolder =
+ mCurrentFullUserRecord.mLastMediaButtonReceiverHolder;
+ }
}
if (session != null) {
@@ -2438,16 +2452,12 @@ public class MediaSessionService extends SystemService implements Monitor {
} catch (RemoteException e) {
Log.w(TAG, "Failed to send callback", e);
}
- } else if (mCurrentFullUserRecord.mLastMediaButtonReceiverHolder != null) {
+ } else if (mediaButtonReceiverHolder != null) {
if (needWakeLock) {
mKeyEventReceiver.acquireWakeLockLocked();
}
String callingPackageName =
(asSystemService) ? mContext.getPackageName() : packageName;
-
- MediaButtonReceiverHolder mediaButtonReceiverHolder =
- mCurrentFullUserRecord.mLastMediaButtonReceiverHolder;
-
boolean sent = mediaButtonReceiverHolder.send(
mContext, keyEvent, callingPackageName,
needWakeLock ? mKeyEventReceiver.mLastTimeoutId : -1, mKeyEventReceiver,
diff --git a/services/core/java/com/android/server/notification/BadgeExtractor.java b/services/core/java/com/android/server/notification/BadgeExtractor.java
index af8baa50d501..d323d8095525 100644
--- a/services/core/java/com/android/server/notification/BadgeExtractor.java
+++ b/services/core/java/com/android/server/notification/BadgeExtractor.java
@@ -19,6 +19,7 @@ import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_BADGE;
import android.content.Context;
import android.util.Slog;
+import android.app.Notification;
/**
* Determines whether a badge should be shown for this notification
@@ -61,6 +62,10 @@ public class BadgeExtractor implements NotificationSignalExtractor {
record.setShowBadge(false);
}
+ Notification.BubbleMetadata metadata = record.getNotification().getBubbleMetadata();
+ if (metadata != null && metadata.isNotificationSuppressed()) {
+ record.setShowBadge(false);
+ }
return null;
}
diff --git a/services/core/java/com/android/server/notification/NotificationHistoryDatabase.java b/services/core/java/com/android/server/notification/NotificationHistoryDatabase.java
index e846daf7a2e6..0ec4b39d8960 100644
--- a/services/core/java/com/android/server/notification/NotificationHistoryDatabase.java
+++ b/services/core/java/com/android/server/notification/NotificationHistoryDatabase.java
@@ -108,7 +108,7 @@ public class NotificationHistoryDatabase {
public void init() {
synchronized (mLock) {
try {
- if (!mHistoryDir.mkdir()) {
+ if (!mHistoryDir.exists() && !mHistoryDir.mkdir()) {
throw new IllegalStateException("could not create history directory");
}
mVersionFile.createNewFile();
@@ -197,7 +197,7 @@ public class NotificationHistoryDatabase {
readLocked(
file, notifications, new NotificationHistoryFilter.Builder().build());
} catch (Exception e) {
- Slog.e(TAG, "error reading " + file.getBaseFile().getName(), e);
+ Slog.e(TAG, "error reading " + file.getBaseFile().getAbsolutePath(), e);
}
}
@@ -223,7 +223,7 @@ public class NotificationHistoryDatabase {
break;
}
} catch (Exception e) {
- Slog.e(TAG, "error reading " + file.getBaseFile().getName(), e);
+ Slog.e(TAG, "error reading " + file.getBaseFile().getAbsolutePath(), e);
}
}
@@ -279,7 +279,7 @@ public class NotificationHistoryDatabase {
}
file.delete();
// TODO: delete all relevant bitmaps, once they exist
- mHistoryFiles.removeLast();
+ mHistoryFiles.remove(file);
}
private void scheduleDeletion(File file, long creationTime, int retentionDays) {
@@ -317,11 +317,17 @@ public class NotificationHistoryDatabase {
private static void readLocked(AtomicFile file, NotificationHistory notificationsOut,
NotificationHistoryFilter filter) throws IOException {
- try (FileInputStream in = file.openRead()) {
+ FileInputStream in = null;
+ try {
+ in = file.openRead();
NotificationHistoryProtoHelper.read(in, notificationsOut, filter);
} catch (FileNotFoundException e) {
- Slog.e(TAG, "Cannot file " + file.getBaseFile().getName(), e);
+ Slog.e(TAG, "Cannot open " + file.getBaseFile().getAbsolutePath(), e);
throw e;
+ } finally {
+ if (in != null) {
+ in.close();
+ }
}
}
@@ -334,9 +340,15 @@ public class NotificationHistoryDatabase {
}
if (ACTION_HISTORY_DELETION.equals(action)) {
try {
- final String filePath = intent.getStringExtra(EXTRA_KEY);
- AtomicFile fileToDelete = new AtomicFile(new File(filePath));
- fileToDelete.delete();
+ synchronized (mLock) {
+ final String filePath = intent.getStringExtra(EXTRA_KEY);
+ AtomicFile fileToDelete = new AtomicFile(new File(filePath));
+ if (DEBUG) {
+ Slog.d(TAG, "Removed " + fileToDelete.getBaseFile().getName());
+ }
+ fileToDelete.delete();
+ mHistoryFiles.remove(fileToDelete);
+ }
} catch (Exception e) {
Slog.e(TAG, "Failed to delete notification history file", e);
}
@@ -345,27 +357,23 @@ public class NotificationHistoryDatabase {
};
final class WriteBufferRunnable implements Runnable {
- long currentTime = 0;
- AtomicFile latestNotificationsFile;
@Override
public void run() {
- if (DEBUG) Slog.d(TAG, "WriteBufferRunnable");
+ long time = System.currentTimeMillis();
+ run(time, new AtomicFile(new File(mHistoryDir, String.valueOf(time))));
+ }
+
+ void run(long time, AtomicFile file) {
synchronized (mLock) {
- if (currentTime == 0) {
- currentTime = System.currentTimeMillis();
- }
- if (latestNotificationsFile == null) {
- latestNotificationsFile = new AtomicFile(
- new File(mHistoryDir, String.valueOf(currentTime)));
- }
+ if (DEBUG) Slog.d(TAG, "WriteBufferRunnable "
+ + file.getBaseFile().getAbsolutePath());
try {
- writeLocked(latestNotificationsFile, mBuffer);
- mHistoryFiles.addFirst(latestNotificationsFile);
+ writeLocked(file, mBuffer);
+ mHistoryFiles.addFirst(file);
mBuffer = new NotificationHistory();
- scheduleDeletion(latestNotificationsFile.getBaseFile(), currentTime,
- HISTORY_RETENTION_DAYS);
+ scheduleDeletion(file.getBaseFile(), time, HISTORY_RETENTION_DAYS);
} catch (IOException e) {
Slog.e(TAG, "Failed to write buffer to disk. not flushing buffer", e);
}
@@ -382,7 +390,7 @@ public class NotificationHistoryDatabase {
@Override
public void run() {
- if (DEBUG) Slog.d(TAG, "RemovePackageRunnable");
+ if (DEBUG) Slog.d(TAG, "RemovePackageRunnable " + mPkg);
synchronized (mLock) {
// Remove packageName entries from pending history
mBuffer.removeNotificationsFromWrite(mPkg);
@@ -398,7 +406,7 @@ public class NotificationHistoryDatabase {
writeLocked(af, notifications);
} catch (Exception e) {
Slog.e(TAG, "Cannot clean up file on pkg removal "
- + af.getBaseFile().getName(), e);
+ + af.getBaseFile().getAbsolutePath(), e);
}
}
}
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index 9d3385f20695..b64e99168445 100755
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -92,6 +92,7 @@ import static android.service.notification.NotificationListenerService.TRIM_FULL
import static android.service.notification.NotificationListenerService.TRIM_LIGHT;
import static android.view.WindowManager.LayoutParams.TYPE_TOAST;
+import static com.android.internal.util.FrameworkStatsLog.DND_MODE_RULE;
import static com.android.internal.util.FrameworkStatsLog.PACKAGE_NOTIFICATION_CHANNEL_GROUP_PREFERENCES;
import static com.android.internal.util.FrameworkStatsLog.PACKAGE_NOTIFICATION_CHANNEL_PREFERENCES;
import static com.android.internal.util.FrameworkStatsLog.PACKAGE_NOTIFICATION_PREFERENCES;
@@ -246,6 +247,7 @@ import com.android.internal.os.SomeArgs;
import com.android.internal.statusbar.NotificationVisibility;
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.CollectionUtils;
+import com.android.internal.util.ConcurrentUtils;
import com.android.internal.util.DumpUtils;
import com.android.internal.util.FastXmlSerializer;
import com.android.internal.util.Preconditions;
@@ -1905,7 +1907,8 @@ public class NotificationManagerService extends SystemService {
mMetricsLogger = new MetricsLogger();
mRankingHandler = rankingHandler;
mConditionProviders = conditionProviders;
- mZenModeHelper = new ZenModeHelper(getContext(), mHandler.getLooper(), mConditionProviders);
+ mZenModeHelper = new ZenModeHelper(getContext(), mHandler.getLooper(), mConditionProviders,
+ new SysUiStatsEvent.BuilderFactory());
mZenModeHelper.addCallback(new ZenModeHelper.Callback() {
@Override
public void onConfigChanged() {
@@ -2045,12 +2048,15 @@ public class NotificationManagerService extends SystemService {
mStripRemoteViewsSizeBytes = getContext().getResources().getInteger(
com.android.internal.R.integer.config_notificationStripRemoteViewSizeBytes);
- mMsgPkgsAllowedAsConvos = Set.of(
- getContext().getResources().getStringArray(
- com.android.internal.R.array.config_notificationMsgPkgsAllowedAsConvos));
+ mMsgPkgsAllowedAsConvos = Set.of(getStringArrayResource(
+ com.android.internal.R.array.config_notificationMsgPkgsAllowedAsConvos));
mStatsManager = statsManager;
}
+ protected String[] getStringArrayResource(int key) {
+ return getContext().getResources().getStringArray(key);
+ }
+
@Override
public void onStart() {
SnoozeHelper snoozeHelper = new SnoozeHelper(getContext(), (userId, r, muteOnReturn) -> {
@@ -2173,18 +2179,24 @@ public class NotificationManagerService extends SystemService {
mStatsManager.setPullAtomCallback(
PACKAGE_NOTIFICATION_PREFERENCES,
null, // use default PullAtomMetadata values
- BackgroundThread.getExecutor(),
+ ConcurrentUtils.DIRECT_EXECUTOR,
mPullAtomCallback
);
mStatsManager.setPullAtomCallback(
PACKAGE_NOTIFICATION_CHANNEL_PREFERENCES,
null, // use default PullAtomMetadata values
- BackgroundThread.getExecutor(),
+ ConcurrentUtils.DIRECT_EXECUTOR,
mPullAtomCallback
);
mStatsManager.setPullAtomCallback(
PACKAGE_NOTIFICATION_CHANNEL_GROUP_PREFERENCES,
null, // use default PullAtomMetadata values
+ ConcurrentUtils.DIRECT_EXECUTOR,
+ mPullAtomCallback
+ );
+ mStatsManager.setPullAtomCallback(
+ DND_MODE_RULE,
+ null, // use default PullAtomMetadata values
BackgroundThread.getExecutor(),
mPullAtomCallback
);
@@ -2197,6 +2209,7 @@ public class NotificationManagerService extends SystemService {
case PACKAGE_NOTIFICATION_PREFERENCES:
case PACKAGE_NOTIFICATION_CHANNEL_PREFERENCES:
case PACKAGE_NOTIFICATION_CHANNEL_GROUP_PREFERENCES:
+ case DND_MODE_RULE:
return pullNotificationStates(atomTag, data);
default:
throw new UnsupportedOperationException("Unknown tagId=" + atomTag);
@@ -2215,6 +2228,9 @@ public class NotificationManagerService extends SystemService {
case PACKAGE_NOTIFICATION_CHANNEL_GROUP_PREFERENCES:
mPreferencesHelper.pullPackageChannelGroupPreferencesStats(data);
break;
+ case DND_MODE_RULE:
+ mZenModeHelper.pullRules(data);
+ break;
}
return StatsManager.PULL_SUCCESS;
}
@@ -2671,7 +2687,7 @@ public class NotificationManagerService extends SystemService {
mHistoryManager.addNotification(new HistoricalNotification.Builder()
.setPackage(r.getSbn().getPackageName())
.setUid(r.getSbn().getUid())
- .setUserId(r.getUserId())
+ .setUserId(r.getSbn().getNormalizedUserId())
.setChannelId(r.getChannel().getId())
.setChannelName(r.getChannel().getName().toString())
.setPostedTimeMs(System.currentTimeMillis())
@@ -2728,10 +2744,7 @@ public class NotificationManagerService extends SystemService {
}
protected void maybeRegisterMessageSent(NotificationRecord r) {
- Context appContext = r.getSbn().getPackageContext(getContext());
- Notification.Builder nb =
- Notification.Builder.recoverBuilder(appContext, r.getNotification());
- if (nb.getStyle() instanceof Notification.MessagingStyle) {
+ if (r.isConversation()) {
if (r.getShortcutInfo() != null) {
if (mPreferencesHelper.setValidMessageSent(
r.getSbn().getPackageName(), r.getUid())) {
@@ -4014,7 +4027,7 @@ public class NotificationManagerService extends SystemService {
private void cancelNotificationFromListenerLocked(ManagedServiceInfo info,
int callingUid, int callingPid, String pkg, String tag, int id, int userId) {
cancelNotification(callingUid, callingPid, pkg, tag, id, 0,
- FLAG_ONGOING_EVENT | FLAG_FOREGROUND_SERVICE | FLAG_BUBBLE,
+ FLAG_ONGOING_EVENT | FLAG_FOREGROUND_SERVICE,
true,
userId, REASON_LISTENER_CANCEL, info);
}
@@ -6247,6 +6260,13 @@ public class NotificationManagerService extends SystemService {
mUsageStats.registerClickedByUser(r);
}
+ if (mReason == REASON_LISTENER_CANCEL
+ && (r.getNotification().flags & FLAG_BUBBLE) != 0) {
+ mNotificationDelegate.onBubbleNotificationSuppressionChanged(
+ r.getKey(), /* suppressed */ true);
+ return;
+ }
+
if ((r.getNotification().flags & mMustHaveFlags) != mMustHaveFlags) {
return;
}
diff --git a/services/core/java/com/android/server/notification/SysUiStatsEvent.java b/services/core/java/com/android/server/notification/SysUiStatsEvent.java
index 9bc2346d4e96..90737bdeae4a 100644
--- a/services/core/java/com/android/server/notification/SysUiStatsEvent.java
+++ b/services/core/java/com/android/server/notification/SysUiStatsEvent.java
@@ -58,6 +58,11 @@ public class SysUiStatsEvent {
mBuilder.writeBoolean(value);
return this;
}
+
+ public Builder writeByteArray(byte[] value) {
+ mBuilder.writeByteArray(value);
+ return this;
+ }
}
static class BuilderFactory {
diff --git a/services/core/java/com/android/server/notification/ZenModeHelper.java b/services/core/java/com/android/server/notification/ZenModeHelper.java
index a490b9c99bb4..4931d3f3e95c 100644
--- a/services/core/java/com/android/server/notification/ZenModeHelper.java
+++ b/services/core/java/com/android/server/notification/ZenModeHelper.java
@@ -20,6 +20,10 @@ import static android.app.NotificationManager.AUTOMATIC_RULE_STATUS_DISABLED;
import static android.app.NotificationManager.AUTOMATIC_RULE_STATUS_ENABLED;
import static android.app.NotificationManager.AUTOMATIC_RULE_STATUS_REMOVED;
import static android.app.NotificationManager.Policy.PRIORITY_SENDERS_ANY;
+import static android.service.notification.DNDModeProto.ROOT_CONFIG;
+
+import static com.android.internal.util.FrameworkStatsLog.ANNOTATION_ID_IS_UID;
+import static com.android.internal.util.FrameworkStatsLog.DND_MODE_RULE;
import android.app.AppOpsManager;
import android.app.AutomaticZenRule;
@@ -67,6 +71,7 @@ import android.util.ArrayMap;
import android.util.Log;
import android.util.Slog;
import android.util.SparseArray;
+import android.util.StatsEvent;
import android.util.proto.ProtoOutputStream;
import com.android.internal.R;
@@ -103,6 +108,7 @@ public class ZenModeHelper {
private final SettingsObserver mSettingsObserver;
private final AppOpsManager mAppOps;
@VisibleForTesting protected final NotificationManager mNotificationManager;
+ private final SysUiStatsEvent.BuilderFactory mStatsEventBuilderFactory;
@VisibleForTesting protected ZenModeConfig mDefaultConfig;
private final ArrayList<Callback> mCallbacks = new ArrayList<Callback>();
private final ZenModeFiltering mFiltering;
@@ -130,7 +136,8 @@ public class ZenModeHelper {
private String[] mPriorityOnlyDndExemptPackages;
- public ZenModeHelper(Context context, Looper looper, ConditionProviders conditionProviders) {
+ public ZenModeHelper(Context context, Looper looper, ConditionProviders conditionProviders,
+ SysUiStatsEvent.BuilderFactory statsEventBuilderFactory) {
mContext = context;
mHandler = new H(looper);
addCallback(mMetrics);
@@ -148,6 +155,7 @@ public class ZenModeHelper {
mFiltering = new ZenModeFiltering(mContext);
mConditions = new ZenModeConditions(this, conditionProviders);
mServiceConfig = conditionProviders.getConfig();
+ mStatsEventBuilderFactory = statsEventBuilderFactory;
}
public Looper getLooper() {
@@ -1170,6 +1178,72 @@ public class ZenModeHelper {
}
}
+ /**
+ * Generate pulled atoms about do not disturb configurations.
+ */
+ public void pullRules(List<StatsEvent> events) {
+ synchronized (mConfig) {
+ final int numConfigs = mConfigs.size();
+ int id = 0;
+ for (int i = 0; i < numConfigs; i++) {
+ final int user = mConfigs.keyAt(i);
+ final ZenModeConfig config = mConfigs.valueAt(i);
+ SysUiStatsEvent.Builder data = mStatsEventBuilderFactory.newBuilder()
+ .setAtomId(DND_MODE_RULE)
+ .writeInt(user)
+ .writeBoolean(config.manualRule != null) // enabled
+ .writeBoolean(config.areChannelsBypassingDnd)
+ .writeInt(ROOT_CONFIG)
+ .writeString("") // name, empty for root config
+ .writeInt(Process.SYSTEM_UID) // system owns root config
+ .addBooleanAnnotation(ANNOTATION_ID_IS_UID, true)
+ .writeByteArray(config.toZenPolicy().toProto());
+ events.add(data.build());
+ if (config.manualRule != null && config.manualRule.enabler != null) {
+ ruleToProto(user, config.manualRule, events);
+ }
+ for (ZenRule rule : config.automaticRules.values()) {
+ ruleToProto(user, rule, events);
+ }
+ }
+ }
+ }
+
+ private void ruleToProto(int user, ZenRule rule, List<StatsEvent> events) {
+ // Make the ID safe.
+ String id = rule.id == null ? "" : rule.id;
+ if (!ZenModeConfig.DEFAULT_RULE_IDS.contains(id)) {
+ id = "";
+ }
+
+ // Look for packages and enablers, enablers get priority.
+ String pkg = rule.pkg == null ? "" : rule.pkg;
+ if (rule.enabler != null) {
+ pkg = rule.enabler;
+ id = ZenModeConfig.MANUAL_RULE_ID;
+ }
+
+ // TODO: fetch the uid from the package manager
+ int uid = "android".equals(pkg) ? Process.SYSTEM_UID : 0;
+
+ SysUiStatsEvent.Builder data;
+ data = mStatsEventBuilderFactory.newBuilder()
+ .setAtomId(DND_MODE_RULE)
+ .writeInt(user)
+ .writeBoolean(rule.enabled)
+ .writeBoolean(false) // channels_bypassing unused for rules
+ .writeInt(rule.zenMode)
+ .writeString(id)
+ .writeInt(uid)
+ .addBooleanAnnotation(ANNOTATION_ID_IS_UID, true);
+ byte[] policyProto = new byte[]{};
+ if (rule.zenPolicy != null) {
+ policyProto = rule.zenPolicy.toProto();
+ }
+ data.writeByteArray(policyProto);
+ events.add(data.build());
+ }
+
@VisibleForTesting
protected final class RingerModeDelegate implements AudioManagerInternal.RingerModeDelegate {
@Override
diff --git a/services/core/java/com/android/server/om/IdmapManager.java b/services/core/java/com/android/server/om/IdmapManager.java
index 59735ebb24d2..d6b1b27360ca 100644
--- a/services/core/java/com/android/server/om/IdmapManager.java
+++ b/services/core/java/com/android/server/om/IdmapManager.java
@@ -65,7 +65,7 @@ final class IdmapManager {
* modified.
*/
boolean createIdmap(@NonNull final PackageInfo targetPackage,
- @NonNull final PackageInfo overlayPackage, int additionalPolicies, int userId) {
+ @NonNull final PackageInfo overlayPackage, int userId) {
if (DEBUG) {
Slog.d(TAG, "create idmap for " + targetPackage.packageName + " and "
+ overlayPackage.packageName);
@@ -73,14 +73,13 @@ final class IdmapManager {
final String targetPath = targetPackage.applicationInfo.getBaseCodePath();
final String overlayPath = overlayPackage.applicationInfo.getBaseCodePath();
try {
+ int policies = calculateFulfilledPolicies(targetPackage, overlayPackage, userId);
boolean enforce = enforceOverlayable(overlayPackage);
- int policies = calculateFulfilledPolicies(targetPackage, overlayPackage, userId)
- | additionalPolicies;
if (mIdmapDaemon.verifyIdmap(targetPath, overlayPath, policies, enforce, userId)) {
return false;
}
- return mIdmapDaemon.createIdmap(targetPath, overlayPath, policies, enforce, userId)
- != null;
+ return mIdmapDaemon.createIdmap(targetPath, overlayPath, policies,
+ enforce, userId) != null;
} catch (Exception e) {
Slog.w(TAG, "failed to generate idmap for " + targetPath + " and "
+ overlayPath + ": " + e.getMessage());
diff --git a/services/core/java/com/android/server/om/OverlayManagerService.java b/services/core/java/com/android/server/om/OverlayManagerService.java
index 3c5e47625fa2..396815399874 100644
--- a/services/core/java/com/android/server/om/OverlayManagerService.java
+++ b/services/core/java/com/android/server/om/OverlayManagerService.java
@@ -45,7 +45,6 @@ import android.content.pm.PackageInfo;
import android.content.pm.PackageManagerInternal;
import android.content.pm.UserInfo;
import android.content.res.ApkAssets;
-import android.content.res.Resources;
import android.net.Uri;
import android.os.Binder;
import android.os.Environment;
@@ -63,7 +62,6 @@ import android.util.AtomicFile;
import android.util.Slog;
import android.util.SparseArray;
-import com.android.internal.R;
import com.android.internal.content.om.OverlayConfig;
import com.android.server.FgThread;
import com.android.server.IoThread;
@@ -252,8 +250,7 @@ public final class OverlayManagerService extends SystemService {
mSettings = new OverlayManagerSettings();
mImpl = new OverlayManagerServiceImpl(mPackageManager, im, mSettings,
OverlayConfig.getSystemInstance(), getDefaultOverlayPackages(),
- new OverlayChangeListener(), getOverlayableConfigurator(),
- getOverlayableConfiguratorTargets());
+ new OverlayChangeListener());
mActorEnforcer = new OverlayActorEnforcer(mPackageManager);
final IntentFilter packageFilter = new IntentFilter();
@@ -336,28 +333,6 @@ public final class OverlayManagerService extends SystemService {
return defaultPackages.toArray(new String[defaultPackages.size()]);
}
-
- /**
- * Retrieves the package name that is recognized as an actor for the packages specified by
- * {@link #getOverlayableConfiguratorTargets()}.
- */
- @Nullable
- private String getOverlayableConfigurator() {
- return TextUtils.nullIfEmpty(Resources.getSystem()
- .getString(R.string.config_overlayableConfigurator));
- }
-
- /**
- * Retrieves the target packages that recognize the {@link #getOverlayableConfigurator} as an
- * actor for itself. Overlays targeting one of the specified targets that are signed with the
- * same signature as the overlayable configurator will be granted the "actor" policy.
- */
- @Nullable
- private String[] getOverlayableConfiguratorTargets() {
- return Resources.getSystem().getStringArray(
- R.array.config_overlayableConfiguratorTargets);
- }
-
private final class PackageReceiver extends BroadcastReceiver {
@Override
public void onReceive(@NonNull final Context context, @NonNull final Intent intent) {
diff --git a/services/core/java/com/android/server/om/OverlayManagerServiceImpl.java b/services/core/java/com/android/server/om/OverlayManagerServiceImpl.java
index 879ad4fdf011..05a4a38feef1 100644
--- a/services/core/java/com/android/server/om/OverlayManagerServiceImpl.java
+++ b/services/core/java/com/android/server/om/OverlayManagerServiceImpl.java
@@ -31,7 +31,6 @@ import android.annotation.Nullable;
import android.content.om.OverlayInfo;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
-import android.os.OverlayablePolicy;
import android.text.TextUtils;
import android.util.ArrayMap;
import android.util.ArraySet;
@@ -74,9 +73,6 @@ final class OverlayManagerServiceImpl {
private final String[] mDefaultOverlays;
private final OverlayChangeListener mListener;
- private final String mOverlayableConfigurator;
- private final String[] mOverlayableConfiguratorTargets;
-
/**
* Helper method to merge the overlay manager's (as read from overlays.xml)
* and package manager's (as parsed from AndroidManifest.xml files) views
@@ -119,17 +115,13 @@ final class OverlayManagerServiceImpl {
@NonNull final OverlayManagerSettings settings,
@NonNull final OverlayConfig overlayConfig,
@NonNull final String[] defaultOverlays,
- @NonNull final OverlayChangeListener listener,
- @Nullable final String overlayableConfigurator,
- @Nullable final String[] overlayableConfiguratorTargets) {
+ @NonNull final OverlayChangeListener listener) {
mPackageManager = packageManager;
mIdmapManager = idmapManager;
mSettings = settings;
mOverlayConfig = overlayConfig;
mDefaultOverlays = defaultOverlays;
mListener = listener;
- mOverlayableConfigurator = overlayableConfigurator;
- mOverlayableConfiguratorTargets = overlayableConfiguratorTargets;
}
/**
@@ -714,25 +706,7 @@ final class OverlayManagerServiceImpl {
if (targetPackage != null && overlayPackage != null
&& !("android".equals(targetPackageName)
&& !isPackageConfiguredMutable(overlayPackageName))) {
-
- int additionalPolicies = 0;
- if (TextUtils.nullIfEmpty(mOverlayableConfigurator) != null
- && ArrayUtils.contains(mOverlayableConfiguratorTargets, targetPackageName)
- && isPackageConfiguredMutable(overlayPackageName)
- && mPackageManager.signaturesMatching(mOverlayableConfigurator,
- overlayPackageName, userId)) {
- // The overlay targets a package that has the overlayable configurator configured as
- // its actor. The overlay and this actor are signed with the same signature, so
- // the overlay fulfills the actor policy.
- modified |= mSettings.setHasConfiguratorActorPolicy(overlayPackageName, userId,
- true);
- additionalPolicies |= OverlayablePolicy.ACTOR_SIGNATURE;
- } else if (mSettings.hasConfiguratorActorPolicy(overlayPackageName, userId)) {
- additionalPolicies |= OverlayablePolicy.ACTOR_SIGNATURE;
- }
-
- modified |= mIdmapManager.createIdmap(targetPackage, overlayPackage, additionalPolicies,
- userId);
+ modified |= mIdmapManager.createIdmap(targetPackage, overlayPackage, userId);
}
if (overlayPackage != null) {
diff --git a/services/core/java/com/android/server/om/OverlayManagerSettings.java b/services/core/java/com/android/server/om/OverlayManagerSettings.java
index f8226faf1336..3d520bf59068 100644
--- a/services/core/java/com/android/server/om/OverlayManagerSettings.java
+++ b/services/core/java/com/android/server/om/OverlayManagerSettings.java
@@ -73,7 +73,7 @@ final class OverlayManagerSettings {
remove(packageName, userId);
insert(new SettingsItem(packageName, userId, targetPackageName, targetOverlayableName,
baseCodePath, OverlayInfo.STATE_UNKNOWN, isEnabled, isMutable, priority,
- overlayCategory, false /* hasConfiguratorActorPolicy */));
+ overlayCategory));
}
/**
@@ -160,26 +160,6 @@ final class OverlayManagerSettings {
return mItems.get(idx).setState(state);
}
- boolean hasConfiguratorActorPolicy(@NonNull final String packageName, final int userId) {
- final int idx = select(packageName, userId);
- if (idx < 0) {
- throw new BadKeyException(packageName, userId);
- }
- return mItems.get(idx).hasConfiguratorActorPolicy();
- }
-
- /**
- * Returns true if the settings were modified, false if they remain the same.
- */
- boolean setHasConfiguratorActorPolicy(@NonNull final String packageName, final int userId,
- boolean hasPolicy) {
- final int idx = select(packageName, userId);
- if (idx < 0) {
- throw new BadKeyException(packageName, userId);
- }
- return mItems.get(idx).setHasConfiguratorActorPolicy(hasPolicy);
- }
-
List<OverlayInfo> getOverlaysForTarget(@NonNull final String targetPackageName,
final int userId) {
// Immutable RROs targeting "android" are loaded from AssetManager, and so they should be
@@ -343,17 +323,16 @@ final class OverlayManagerSettings {
pw.println(item.mPackageName + ":" + item.getUserId() + " {");
pw.increaseIndent();
- pw.println("mPackageName................: " + item.mPackageName);
- pw.println("mUserId.....................: " + item.getUserId());
- pw.println("mTargetPackageName..........: " + item.getTargetPackageName());
- pw.println("mTargetOverlayableName......: " + item.getTargetOverlayableName());
- pw.println("mBaseCodePath...............: " + item.getBaseCodePath());
- pw.println("mState......................: " + OverlayInfo.stateToString(item.getState()));
- pw.println("mIsEnabled..................: " + item.isEnabled());
- pw.println("mIsMutable..................: " + item.isMutable());
- pw.println("mPriority...................: " + item.mPriority);
- pw.println("mCategory...................: " + item.mCategory);
- pw.println("mHasConfiguratorActorPolicy.: " + item.hasConfiguratorActorPolicy());
+ pw.println("mPackageName...........: " + item.mPackageName);
+ pw.println("mUserId................: " + item.getUserId());
+ pw.println("mTargetPackageName.....: " + item.getTargetPackageName());
+ pw.println("mTargetOverlayableName.: " + item.getTargetOverlayableName());
+ pw.println("mBaseCodePath..........: " + item.getBaseCodePath());
+ pw.println("mState.................: " + OverlayInfo.stateToString(item.getState()));
+ pw.println("mIsEnabled.............: " + item.isEnabled());
+ pw.println("mIsMutable.............: " + item.isMutable());
+ pw.println("mPriority..............: " + item.mPriority);
+ pw.println("mCategory..............: " + item.mCategory);
pw.decreaseIndent();
pw.println("}");
@@ -392,9 +371,6 @@ final class OverlayManagerSettings {
case "category":
pw.println(item.mCategory);
break;
- case "hasconfiguratoractorpolicy":
- pw.println(item.mHasConfiguratorActorPolicy);
- break;
}
}
@@ -422,8 +398,6 @@ final class OverlayManagerSettings {
private static final String ATTR_CATEGORY = "category";
private static final String ATTR_USER_ID = "userId";
private static final String ATTR_VERSION = "version";
- private static final String ATTR_HAS_CONFIGURATOR_ACTOR_POLICY =
- "hasConfiguratorActorPolicy";
@VisibleForTesting
static final int CURRENT_VERSION = 4;
@@ -461,6 +435,10 @@ final class OverlayManagerSettings {
// Throw an exception which will cause the overlay file to be ignored
// and overwritten.
throw new XmlPullParserException("old version " + oldVersion + "; ignoring");
+ case 3:
+ // Upgrading from version 3 to 4 is not a breaking change so do not ignore the
+ // overlay file.
+ return;
default:
throw new XmlPullParserException("unrecognized version " + oldVersion);
}
@@ -480,12 +458,9 @@ final class OverlayManagerSettings {
final boolean isStatic = XmlUtils.readBooleanAttribute(parser, ATTR_IS_STATIC);
final int priority = XmlUtils.readIntAttribute(parser, ATTR_PRIORITY);
final String category = XmlUtils.readStringAttribute(parser, ATTR_CATEGORY);
- final boolean hasConfiguratorActorPolicy = XmlUtils.readBooleanAttribute(parser,
- ATTR_HAS_CONFIGURATOR_ACTOR_POLICY);
return new SettingsItem(packageName, userId, targetPackageName, targetOverlayableName,
- baseCodePath, state, isEnabled, !isStatic, priority, category,
- hasConfiguratorActorPolicy);
+ baseCodePath, state, isEnabled, !isStatic, priority, category);
}
public static void persist(@NonNull final ArrayList<SettingsItem> table,
@@ -520,8 +495,6 @@ final class OverlayManagerSettings {
XmlUtils.writeBooleanAttribute(xml, ATTR_IS_STATIC, !item.mIsMutable);
XmlUtils.writeIntAttribute(xml, ATTR_PRIORITY, item.mPriority);
XmlUtils.writeStringAttribute(xml, ATTR_CATEGORY, item.mCategory);
- XmlUtils.writeBooleanAttribute(xml, ATTR_HAS_CONFIGURATOR_ACTOR_POLICY,
- item.mHasConfiguratorActorPolicy);
xml.endTag(null, TAG_ITEM);
}
}
@@ -538,14 +511,12 @@ final class OverlayManagerSettings {
private boolean mIsMutable;
private int mPriority;
private String mCategory;
- private boolean mHasConfiguratorActorPolicy;
SettingsItem(@NonNull final String packageName, final int userId,
@NonNull final String targetPackageName,
@Nullable final String targetOverlayableName, @NonNull final String baseCodePath,
final @OverlayInfo.State int state, final boolean isEnabled,
- final boolean isMutable, final int priority, @Nullable String category,
- final boolean hasConfiguratorActorPolicy) {
+ final boolean isMutable, final int priority, @Nullable String category) {
mPackageName = packageName;
mUserId = userId;
mTargetPackageName = targetPackageName;
@@ -557,7 +528,6 @@ final class OverlayManagerSettings {
mCache = null;
mIsMutable = isMutable;
mPriority = priority;
- mHasConfiguratorActorPolicy = hasConfiguratorActorPolicy;
}
private String getTargetPackageName() {
@@ -648,18 +618,6 @@ final class OverlayManagerSettings {
private int getPriority() {
return mPriority;
}
-
- private boolean hasConfiguratorActorPolicy() {
- return mHasConfiguratorActorPolicy;
- }
-
- private boolean setHasConfiguratorActorPolicy(boolean hasPolicy) {
- if (mHasConfiguratorActorPolicy != hasPolicy) {
- mHasConfiguratorActorPolicy = hasPolicy;
- return true;
- }
- return false;
- }
}
private int select(@NonNull final String packageName, final int userId) {
diff --git a/services/core/java/com/android/server/pm/DataLoaderManagerService.java b/services/core/java/com/android/server/pm/DataLoaderManagerService.java
index 81ee7d9eeef7..52fdc7983636 100644
--- a/services/core/java/com/android/server/pm/DataLoaderManagerService.java
+++ b/services/core/java/com/android/server/pm/DataLoaderManagerService.java
@@ -21,7 +21,6 @@ import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
-import android.content.pm.ApplicationInfo;
import android.content.pm.DataLoaderParamsParcel;
import android.content.pm.IDataLoader;
import android.content.pm.IDataLoaderManager;
@@ -122,19 +121,7 @@ public class DataLoaderManagerService extends SystemService {
ri.serviceInfo.packageName, ri.serviceInfo.name);
// There should only be one matching provider inside the given package.
// If there's more than one, return the first one found.
- try {
- ApplicationInfo ai = pm.getApplicationInfo(resolved.getPackageName(), 0);
- if (!ai.isPrivilegedApp()) {
- Slog.w(TAG,
- "Data loader: " + resolved + " is not a privileged app, skipping.");
- continue;
- }
- return resolved;
- } catch (PackageManager.NameNotFoundException ex) {
- Slog.w(TAG,
- "Privileged data loader: " + resolved + " not found, skipping.");
- }
-
+ return resolved;
}
Slog.e(TAG, "Didn't find any matching data loader service provider.");
return null;
diff --git a/services/core/java/com/android/server/pm/PackageInstallerService.java b/services/core/java/com/android/server/pm/PackageInstallerService.java
index 236a6816b3e3..f827721be3b7 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerService.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerService.java
@@ -40,6 +40,7 @@ import android.content.pm.PackageInfo;
import android.content.pm.PackageInstaller;
import android.content.pm.PackageInstaller.SessionInfo;
import android.content.pm.PackageInstaller.SessionParams;
+import android.content.pm.PackageItemInfo;
import android.content.pm.PackageManager;
import android.content.pm.ParceledListSlice;
import android.content.pm.VersionedPackage;
@@ -126,8 +127,10 @@ public class PackageInstallerService extends IPackageInstaller.Stub implements
private static final long MAX_AGE_MILLIS = 3 * DateUtils.DAY_IN_MILLIS;
/** Automatically destroy staged sessions that have not changed state in this time */
private static final long MAX_TIME_SINCE_UPDATE_MILLIS = 7 * DateUtils.DAY_IN_MILLIS;
- /** Upper bound on number of active sessions for a UID */
- private static final long MAX_ACTIVE_SESSIONS = 1024;
+ /** Upper bound on number of active sessions for a UID that has INSTALL_PACKAGES */
+ private static final long MAX_ACTIVE_SESSIONS_WITH_PERMISSION = 1024;
+ /** Upper bound on number of active sessions for a UID without INSTALL_PACKAGES */
+ private static final long MAX_ACTIVE_SESSIONS_NO_PERMISSION = 50;
/** Upper bound on number of historical sessions for a UID */
private static final long MAX_HISTORICAL_SESSIONS = 1048576;
@@ -503,7 +506,18 @@ public class PackageInstallerService extends IPackageInstaller.Stub implements
+ "to use a data loader");
}
- String requestedInstallerPackageName = params.installerPackageName != null
+ // App package name and label length is restricted so that really long strings aren't
+ // written to disk.
+ if (params.appPackageName != null
+ && params.appPackageName.length() > SessionParams.MAX_PACKAGE_NAME_LENGTH) {
+ params.appPackageName = null;
+ }
+
+ params.appLabel = TextUtils.trimToSize(params.appLabel,
+ PackageItemInfo.MAX_SAFE_LABEL_LENGTH);
+
+ String requestedInstallerPackageName = (params.installerPackageName != null
+ && params.installerPackageName.length() < SessionParams.MAX_PACKAGE_NAME_LENGTH)
? params.installerPackageName : installerPackageName;
if ((callingUid == Process.SHELL_UID) || (callingUid == Process.ROOT_UID)) {
@@ -635,12 +649,23 @@ public class PackageInstallerService extends IPackageInstaller.Stub implements
}
}
+ if (params.whitelistedRestrictedPermissions != null) {
+ mPermissionManager.retainHardAndSoftRestrictedPermissions(
+ params.whitelistedRestrictedPermissions);
+ }
+
final int sessionId;
final PackageInstallerSession session;
synchronized (mSessions) {
// Sanity check that installer isn't going crazy
final int activeCount = getSessionCount(mSessions, callingUid);
- if (activeCount >= MAX_ACTIVE_SESSIONS) {
+ if (mContext.checkCallingOrSelfPermission(Manifest.permission.INSTALL_PACKAGES)
+ == PackageManager.PERMISSION_GRANTED) {
+ if (activeCount >= MAX_ACTIVE_SESSIONS_WITH_PERMISSION) {
+ throw new IllegalStateException(
+ "Too many active sessions for UID " + callingUid);
+ }
+ } else if (activeCount >= MAX_ACTIVE_SESSIONS_NO_PERMISSION) {
throw new IllegalStateException(
"Too many active sessions for UID " + callingUid);
}
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 6bb10c79d382..ae8b3a0e9acc 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -148,6 +148,8 @@ import android.app.ResourcesManager;
import android.app.admin.IDevicePolicyManager;
import android.app.admin.SecurityLog;
import android.app.backup.IBackupManager;
+import android.compat.annotation.ChangeId;
+import android.compat.annotation.EnabledAfter;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.ContentResolver;
@@ -639,6 +641,19 @@ public class PackageManagerService extends IPackageManager.Stub
*/
private static final int DEFAULT_VERIFICATION_RESPONSE = PackageManager.VERIFICATION_ALLOW;
+ /**
+ * Adding an installer package name to a package that does not have one set requires the
+ * INSTALL_PACKAGES permission.
+ *
+ * If the caller targets R, this will throw a SecurityException. Otherwise the request will
+ * fail silently. In both cases, and regardless of whether this change is enabled, the
+ * installer package will remain unchanged.
+ */
+ @ChangeId
+ @EnabledAfter(targetSdkVersion = Build.VERSION_CODES.Q)
+ private static final long THROW_EXCEPTION_ON_REQUIRE_INSTALL_PACKAGES_TO_ADD_INSTALLER_PACKAGE =
+ 150857253;
+
public static final String PLATFORM_PACKAGE_NAME = "android";
private static final String PACKAGE_MIME_TYPE = "application/vnd.android.package-archive";
@@ -5264,15 +5279,17 @@ public class PackageManagerService extends IPackageManager.Stub
* </ul>
*/
int updateFlagsForResolve(int flags, int userId, int callingUid, boolean wantInstantApps,
- boolean matchSystemOnly) {
+ boolean isImplicitImageCaptureIntentAndNotSetByDpc) {
return updateFlagsForResolve(flags, userId, callingUid,
- wantInstantApps, matchSystemOnly, false /*onlyExposedExplicitly*/);
+ wantInstantApps, false /*onlyExposedExplicitly*/,
+ isImplicitImageCaptureIntentAndNotSetByDpc);
}
int updateFlagsForResolve(int flags, int userId, int callingUid,
- boolean wantInstantApps, boolean onlyExposedExplicitly, boolean matchSystemOnly) {
+ boolean wantInstantApps, boolean onlyExposedExplicitly,
+ boolean isImplicitImageCaptureIntentAndNotSetByDpc) {
// Safe mode means we shouldn't match any third-party components
- if (mSafeMode || matchSystemOnly) {
+ if (mSafeMode || isImplicitImageCaptureIntentAndNotSetByDpc) {
flags |= PackageManager.MATCH_SYSTEM_ONLY;
}
if (getInstantAppPackageName(callingUid) != null) {
@@ -6400,7 +6417,8 @@ public class PackageManagerService extends IPackageManager.Stub
if (!mUserManager.exists(userId)) return null;
final int callingUid = Binder.getCallingUid();
flags = updateFlagsForResolve(flags, userId, filterCallingUid, resolveForStart,
- intent.isImplicitImageCaptureIntent() /*matchSystemOnly*/);
+ isImplicitImageCaptureIntentAndNotSetByDpcLocked(intent, userId, resolvedType,
+ flags));
mPermissionManager.enforceCrossUserPermission(callingUid, userId,
false /*requireFullPermission*/, false /*checkShell*/, "resolve intent");
@@ -6438,7 +6456,7 @@ public class PackageManagerService extends IPackageManager.Stub
final String resolvedType = intent.resolveTypeIfNeeded(mContext.getContentResolver());
final int flags = updateFlagsForResolve(
0, userId, callingUid, false /*includeInstantApps*/,
- intent.isImplicitImageCaptureIntent() /*matchSystemOnly*/);
+ isImplicitImageCaptureIntentAndNotSetByDpcLocked(intent, userId, resolvedType, 0));
final List<ResolveInfo> query = queryIntentActivitiesInternal(intent, resolvedType, flags,
userId);
synchronized (mLock) {
@@ -6684,6 +6702,40 @@ public class PackageManagerService extends IPackageManager.Stub
return true;
}
+ /**
+ * From Android R, camera intents have to match system apps. The only exception to this is if
+ * the DPC has set the camera persistent preferred activity. This case was introduced
+ * because it is important that the DPC has the ability to set both system and non-system
+ * camera persistent preferred activities.
+ *
+ * @return {@code true} if the intent is a camera intent and the persistent preferred
+ * activity was not set by the DPC.
+ */
+ @GuardedBy("mLock")
+ private boolean isImplicitImageCaptureIntentAndNotSetByDpcLocked(Intent intent, int userId,
+ String resolvedType, int flags) {
+ return intent.isImplicitImageCaptureIntent() && !isPersistentPreferredActivitySetByDpm(
+ intent, userId, resolvedType, flags);
+ }
+
+ private boolean isPersistentPreferredActivitySetByDpm(Intent intent, int userId,
+ String resolvedType, int flags) {
+ PersistentPreferredIntentResolver ppir = mSettings.mPersistentPreferredActivities
+ .get(userId);
+ //TODO(b/158003772): Remove double query
+ List<PersistentPreferredActivity> pprefs = ppir != null
+ ? ppir.queryIntent(intent, resolvedType,
+ (flags & PackageManager.MATCH_DEFAULT_ONLY) != 0,
+ userId)
+ : new ArrayList<>();
+ for (PersistentPreferredActivity ppa : pprefs) {
+ if (ppa.mIsSetByDpm) {
+ return true;
+ }
+ }
+ return false;
+ }
+
@GuardedBy("mLock")
private ResolveInfo findPersistentPreferredActivityLP(Intent intent, String resolvedType,
int flags, List<ResolveInfo> query, boolean debug, int userId) {
@@ -6767,7 +6819,8 @@ public class PackageManagerService extends IPackageManager.Stub
android.provider.Settings.Global.DEVICE_PROVISIONED, 0) == 1;
flags = updateFlagsForResolve(
flags, userId, callingUid, false /*includeInstantApps*/,
- intent.isImplicitImageCaptureIntent() /*matchSystemOnly*/);
+ isImplicitImageCaptureIntentAndNotSetByDpcLocked(intent, userId, resolvedType,
+ flags));
intent = updateIntentForResolve(intent);
// writer
synchronized (mLock) {
@@ -6980,7 +7033,8 @@ public class PackageManagerService extends IPackageManager.Stub
synchronized (mLock) {
int flags = updateFlagsForResolve(0, parent.id, callingUid,
false /*includeInstantApps*/,
- intent.isImplicitImageCaptureIntent() /*matchSystemOnly*/);
+ isImplicitImageCaptureIntentAndNotSetByDpcLocked(intent, parent.id,
+ resolvedType, 0));
CrossProfileDomainInfo xpDomainInfo = getCrossProfileDomainPreferredLpr(
intent, resolvedType, flags, sourceUserId, parent.id);
return xpDomainInfo != null;
@@ -7067,7 +7121,8 @@ public class PackageManagerService extends IPackageManager.Stub
flags = updateFlagsForResolve(flags, userId, filterCallingUid, resolveForStart,
comp != null || pkgName != null /*onlyExposedExplicitly*/,
- intent.isImplicitImageCaptureIntent() /*matchSystemOnly*/);
+ isImplicitImageCaptureIntentAndNotSetByDpcLocked(intent, userId, resolvedType,
+ flags));
if (comp != null) {
final List<ResolveInfo> list = new ArrayList<>(1);
final ActivityInfo ai = getActivityInfo(comp, flags, userId);
@@ -7856,7 +7911,8 @@ public class PackageManagerService extends IPackageManager.Stub
if (!mUserManager.exists(userId)) return Collections.emptyList();
final int callingUid = Binder.getCallingUid();
flags = updateFlagsForResolve(flags, userId, callingUid, false /*includeInstantApps*/,
- intent.isImplicitImageCaptureIntent() /*matchSystemOnly*/);
+ isImplicitImageCaptureIntentAndNotSetByDpcLocked(intent, userId, resolvedType,
+ flags));
mPermissionManager.enforceCrossUserPermission(callingUid, userId,
false /*requireFullPermission*/, false /*checkShell*/,
"query intent activity options");
@@ -8043,7 +8099,8 @@ public class PackageManagerService extends IPackageManager.Stub
"query intent receivers");
final String instantAppPkgName = getInstantAppPackageName(callingUid);
flags = updateFlagsForResolve(flags, userId, callingUid, false /*includeInstantApps*/,
- intent.isImplicitImageCaptureIntent() /*matchSystemOnly*/);
+ isImplicitImageCaptureIntentAndNotSetByDpcLocked(intent, userId, resolvedType,
+ flags));
ComponentName comp = intent.getComponent();
if (comp == null) {
if (intent.getSelector() != null) {
@@ -8134,7 +8191,7 @@ public class PackageManagerService extends IPackageManager.Stub
int userId, int callingUid) {
if (!mUserManager.exists(userId)) return null;
flags = updateFlagsForResolve(flags, userId, callingUid, false /*includeInstantApps*/,
- false /* matchSystemOnly */);
+ false /* isImplicitImageCaptureIntentAndNotSetByDpc */);
List<ResolveInfo> query = queryIntentServicesInternal(
intent, resolvedType, flags, userId, callingUid, false /*includeInstantApps*/);
if (query != null) {
@@ -8166,7 +8223,7 @@ public class PackageManagerService extends IPackageManager.Stub
"query intent receivers");
final String instantAppPkgName = getInstantAppPackageName(callingUid);
flags = updateFlagsForResolve(flags, userId, callingUid, includeInstantApps,
- false /* matchSystemOnly */);
+ false /* isImplicitImageCaptureIntentAndNotSetByDpc */);
ComponentName comp = intent.getComponent();
if (comp == null) {
if (intent.getSelector() != null) {
@@ -8304,7 +8361,7 @@ public class PackageManagerService extends IPackageManager.Stub
final int callingUid = Binder.getCallingUid();
final String instantAppPkgName = getInstantAppPackageName(callingUid);
flags = updateFlagsForResolve(flags, userId, callingUid, false /*includeInstantApps*/,
- false /* matchSystemOnly */);
+ false /* isImplicitImageCaptureIntentAndNotSetByDpc */);
ComponentName comp = intent.getComponent();
if (comp == null) {
if (intent.getSelector() != null) {
@@ -10656,6 +10713,20 @@ public class PackageManagerService extends IPackageManager.Stub
return resultList;
}
+ private int getVendorPartitionVersion() {
+ final String version = SystemProperties.get("ro.vndk.version");
+ if (!version.isEmpty()) {
+ try {
+ return Integer.parseInt(version);
+ } catch (NumberFormatException ignore) {
+ if (ArrayUtils.contains(Build.VERSION.ACTIVE_CODENAMES, version)) {
+ return Build.VERSION_CODES.CUR_DEVELOPMENT;
+ }
+ }
+ }
+ return Build.VERSION_CODES.P;
+ }
+
@GuardedBy({"mInstallLock", "mLock"})
private ScanResult scanPackageTracedLI(ParsedPackage parsedPackage,
final @ParseFlags int parseFlags, @ScanFlags int scanFlags, long currentTime,
@@ -10837,7 +10908,7 @@ public class PackageManagerService extends IPackageManager.Stub
// Scan as privileged apps that share a user with a priv-app.
final boolean skipVendorPrivilegeScan = ((scanFlags & SCAN_AS_VENDOR) != 0)
- && SystemProperties.getInt("ro.vndk.version", 28) < 28;
+ && getVendorPartitionVersion() < 28;
if (((scanFlags & SCAN_AS_PRIVILEGED) == 0)
&& !pkg.isPrivileged()
&& (pkg.getSharedUserId() != null)
@@ -10996,7 +11067,7 @@ public class PackageManagerService extends IPackageManager.Stub
} else {
pkgSetting = result.pkgSetting;
if (originalPkgSetting != null) {
- mSettings.addRenamedPackageLPw(parsedPackage.getPackageName(),
+ mSettings.addRenamedPackageLPw(parsedPackage.getRealPackage(),
originalPkgSetting.name);
mTransferredPackages.add(originalPkgSetting.name);
}
@@ -11105,7 +11176,7 @@ public class PackageManagerService extends IPackageManager.Stub
@GuardedBy("mLock")
private @Nullable PackageSetting getOriginalPackageLocked(@NonNull AndroidPackage pkg,
@Nullable String renamedPkgName) {
- if (!isPackageRenamed(pkg, renamedPkgName)) {
+ if (isPackageRenamed(pkg, renamedPkgName)) {
return null;
}
for (int i = ArrayUtils.size(pkg.getOriginalPackages()) - 1; i >= 0; --i) {
@@ -12013,6 +12084,20 @@ public class PackageManagerService extends IPackageManager.Stub
+ pkg.getPackageName()
+ " is static and cannot be upgraded.");
}
+ } else {
+ if ((scanFlags & SCAN_AS_VENDOR) != 0) {
+ if (pkg.getTargetSdkVersion() < getVendorPartitionVersion()) {
+ Slog.w(TAG, "System overlay " + pkg.getPackageName()
+ + " targets an SDK below the required SDK level of vendor"
+ + " overlays (" + getVendorPartitionVersion() + ")."
+ + " This will become an install error in a future release");
+ }
+ } else if (pkg.getTargetSdkVersion() < Build.VERSION.SDK_INT) {
+ Slog.w(TAG, "System overlay " + pkg.getPackageName()
+ + " targets an SDK below the required SDK level of system"
+ + " overlays (" + Build.VERSION.SDK_INT + ")."
+ + " This will become an install error in a future release");
+ }
}
} else {
// A non-preloaded overlay packages must have targetSdkVersion >= Q, or be
@@ -13433,6 +13518,17 @@ public class PackageManagerService extends IPackageManager.Stub
removeSuspensionsBySuspendingPackage(allPackages, suspendingPackage::equals, userId);
}
+ boolean isSuspendingAnyPackages(String suspendingPackage, int userId) {
+ synchronized (mLock) {
+ for (final PackageSetting ps : mSettings.mPackages.values()) {
+ if (ps.isSuspendedBy(suspendingPackage, userId)) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
/**
* Removes any suspensions on given packages that were added by packages that pass the given
* predicate.
@@ -14130,19 +14226,38 @@ public class PackageManagerService extends IPackageManager.Stub
// be signed with the same cert as the caller.
String targetInstallerPackageName =
targetPackageSetting.installSource.installerPackageName;
- if (targetInstallerPackageName != null) {
- PackageSetting setting = mSettings.mPackages.get(
- targetInstallerPackageName);
- // If the currently set package isn't valid, then it's always
- // okay to change it.
- if (setting != null) {
- if (compareSignatures(callerSignature,
- setting.signatures.mSigningDetails.signatures)
- != PackageManager.SIGNATURE_MATCH) {
- throw new SecurityException(
- "Caller does not have same cert as old installer package "
- + targetInstallerPackageName);
+ PackageSetting targetInstallerPkgSetting = targetInstallerPackageName == null ? null :
+ mSettings.mPackages.get(targetInstallerPackageName);
+
+ if (targetInstallerPkgSetting != null) {
+ if (compareSignatures(callerSignature,
+ targetInstallerPkgSetting.signatures.mSigningDetails.signatures)
+ != PackageManager.SIGNATURE_MATCH) {
+ throw new SecurityException(
+ "Caller does not have same cert as old installer package "
+ + targetInstallerPackageName);
+ }
+ } else if (mContext.checkCallingOrSelfPermission(Manifest.permission.INSTALL_PACKAGES)
+ != PackageManager.PERMISSION_GRANTED) {
+ // This is probably an attempt to exploit vulnerability b/150857253 of taking
+ // privileged installer permissions when the installer has been uninstalled or
+ // was never set.
+ EventLog.writeEvent(0x534e4554, "150857253", callingUid, "");
+
+ long binderToken = Binder.clearCallingIdentity();
+ try {
+ if (mInjector.getCompatibility().isChangeEnabledByUid(
+ THROW_EXCEPTION_ON_REQUIRE_INSTALL_PACKAGES_TO_ADD_INSTALLER_PACKAGE,
+ callingUid)) {
+ throw new SecurityException("Neither user " + callingUid
+ + " nor current process has "
+ + Manifest.permission.INSTALL_PACKAGES);
+ } else {
+ // If change disabled, fail silently for backwards compatibility
+ return;
}
+ } finally {
+ Binder.restoreCallingIdentity(binderToken);
}
}
@@ -19840,7 +19955,7 @@ public class PackageManagerService extends IPackageManager.Stub
}
synchronized (mLock) {
mSettings.editPersistentPreferredActivitiesLPw(userId).addFilter(
- new PersistentPreferredActivity(filter, activity));
+ new PersistentPreferredActivity(filter, activity, true));
scheduleWritePackageRestrictionsLocked(userId);
}
updateDefaultHomeNotLocked(userId);
@@ -23809,7 +23924,6 @@ public class PackageManagerService extends IPackageManager.Stub
callingUid);
}
-
@Override
public boolean isPlatformSigned(String packageName) {
PackageSetting packageSetting = mSettings.mPackages.get(packageName);
@@ -24914,6 +25028,16 @@ public class PackageManagerService extends IPackageManager.Stub
mSettings.writePackageRestrictionsLPr(userId);
}
}
+
+ @Override
+ public void unsuspendForSuspendingPackage(final String packageName, int affectedUser) {
+ PackageManagerService.this.unsuspendForSuspendingPackage(packageName, affectedUser);
+ }
+
+ @Override
+ public boolean isSuspendingAnyPackages(String suspendingPackage, int userId) {
+ return PackageManagerService.this.isSuspendingAnyPackages(suspendingPackage, userId);
+ }
}
@GuardedBy("mLock")
diff --git a/services/core/java/com/android/server/pm/PackageSettingBase.java b/services/core/java/com/android/server/pm/PackageSettingBase.java
index 00a5fe766593..834303cc14c6 100644
--- a/services/core/java/com/android/server/pm/PackageSettingBase.java
+++ b/services/core/java/com/android/server/pm/PackageSettingBase.java
@@ -422,6 +422,11 @@ public abstract class PackageSettingBase extends SettingBase {
return readUserState(userId).suspended;
}
+ boolean isSuspendedBy(String suspendingPackage, int userId) {
+ final PackageUserState state = readUserState(userId);
+ return state.suspendParams != null && state.suspendParams.containsKey(suspendingPackage);
+ }
+
void addOrUpdateSuspension(String suspendingPackage, SuspendDialogInfo dialogInfo,
PersistableBundle appExtras, PersistableBundle launcherExtras, int userId) {
final PackageUserState existingUserState = modifyUserState(userId);
diff --git a/services/core/java/com/android/server/pm/PersistentPreferredActivity.java b/services/core/java/com/android/server/pm/PersistentPreferredActivity.java
index 0d4cdf9dee53..5a6fd0923f53 100644
--- a/services/core/java/com/android/server/pm/PersistentPreferredActivity.java
+++ b/services/core/java/com/android/server/pm/PersistentPreferredActivity.java
@@ -16,31 +16,34 @@
package com.android.server.pm;
+import android.content.ComponentName;
+import android.content.IntentFilter;
+import android.util.Log;
+
import com.android.internal.util.XmlUtils;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
import org.xmlpull.v1.XmlSerializer;
-import android.content.ComponentName;
-import android.content.IntentFilter;
-import android.util.Log;
-
import java.io.IOException;
class PersistentPreferredActivity extends IntentFilter {
private static final String ATTR_NAME = "name"; // component name
private static final String ATTR_FILTER = "filter"; // filter
+ private static final String ATTR_SET_BY_DPM = "set-by-dpm"; // set by DPM
private static final String TAG = "PersistentPreferredActivity";
private static final boolean DEBUG_FILTERS = false;
final ComponentName mComponent;
+ final boolean mIsSetByDpm;
- PersistentPreferredActivity(IntentFilter filter, ComponentName activity) {
+ PersistentPreferredActivity(IntentFilter filter, ComponentName activity, boolean isSetByDpm) {
super(filter);
mComponent = activity;
+ mIsSetByDpm = isSetByDpm;
}
PersistentPreferredActivity(XmlPullParser parser) throws XmlPullParserException, IOException {
@@ -52,6 +55,8 @@ class PersistentPreferredActivity extends IntentFilter {
"Bad activity name " + shortComponent +
" at " + parser.getPositionDescription());
}
+ mIsSetByDpm = Boolean.parseBoolean(parser.getAttributeValue(null, ATTR_SET_BY_DPM));
+
int outerDepth = parser.getDepth();
String tagName = parser.getName();
int type;
@@ -83,6 +88,7 @@ class PersistentPreferredActivity extends IntentFilter {
public void writeToXml(XmlSerializer serializer) throws IOException {
serializer.attribute(null, ATTR_NAME, mComponent.flattenToShortString());
+ serializer.attribute(null, ATTR_SET_BY_DPM, Boolean.toString(mIsSetByDpm));
serializer.startTag(null, ATTR_FILTER);
super.writeToXml(serializer);
serializer.endTag(null, ATTR_FILTER);
@@ -91,6 +97,7 @@ class PersistentPreferredActivity extends IntentFilter {
@Override
public String toString() {
return "PersistentPreferredActivity{0x" + Integer.toHexString(System.identityHashCode(this))
- + " " + mComponent.flattenToShortString() + "}";
+ + " " + mComponent.flattenToShortString()
+ + ", mIsSetByDpm=" + mIsSetByDpm + "}";
}
}
diff --git a/services/core/java/com/android/server/pm/ShortcutService.java b/services/core/java/com/android/server/pm/ShortcutService.java
index 3ec139763e80..0c42ff6be520 100644
--- a/services/core/java/com/android/server/pm/ShortcutService.java
+++ b/services/core/java/com/android/server/pm/ShortcutService.java
@@ -2419,6 +2419,9 @@ public class ShortcutService extends IShortcutService.Stub {
@Override
public ParceledListSlice<ShortcutManager.ShareShortcutInfo> getShareTargets(String packageName,
IntentFilter filter, @UserIdInt int userId) {
+ Preconditions.checkStringNotEmpty(packageName, "packageName");
+ Objects.requireNonNull(filter, "intentFilter");
+
verifyCaller(packageName, userId);
enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_APP_PREDICTIONS,
"getShareTargets");
diff --git a/services/core/java/com/android/server/pm/StagingManager.java b/services/core/java/com/android/server/pm/StagingManager.java
index 79805e3b42ae..8ccf837f64dc 100644
--- a/services/core/java/com/android/server/pm/StagingManager.java
+++ b/services/core/java/com/android/server/pm/StagingManager.java
@@ -77,7 +77,11 @@ import com.android.server.pm.parsing.pkg.AndroidPackageUtils;
import com.android.server.pm.parsing.pkg.ParsedPackage;
import com.android.server.rollback.WatchdogRollbackLogger;
+import java.io.BufferedReader;
+import java.io.BufferedWriter;
import java.io.File;
+import java.io.FileReader;
+import java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
@@ -102,6 +106,9 @@ public class StagingManager {
private final PreRebootVerificationHandler mPreRebootVerificationHandler;
private final Supplier<PackageParser2> mPackageParserSupplier;
+ private final File mFailureReasonFile = new File("/metadata/staged-install/failure_reason.txt");
+ private String mFailureReason;
+
@GuardedBy("mStagedSessions")
private final SparseArray<PackageInstallerSession> mStagedSessions = new SparseArray<>();
@@ -125,6 +132,12 @@ public class StagingManager {
mPowerManager = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
mPreRebootVerificationHandler = new PreRebootVerificationHandler(
BackgroundThread.get().getLooper());
+
+ if (mFailureReasonFile.exists()) {
+ try (BufferedReader reader = new BufferedReader(new FileReader(mFailureReasonFile))) {
+ mFailureReason = reader.readLine();
+ } catch (Exception ignore) { }
+ }
}
/**
@@ -383,10 +396,19 @@ public class StagingManager {
}
// Reverts apex sessions and user data (if checkpoint is supported). Also reboots the device.
- private void abortCheckpoint(String errorMsg) {
- Slog.e(TAG, "Aborting checkpoint: " + errorMsg);
+ private void abortCheckpoint(int sessionId, String errorMsg) {
+ String failureReason = "Failed to install sessionId: " + sessionId + " Error: " + errorMsg;
+ Slog.e(TAG, failureReason);
try {
if (supportsCheckpoint() && needsCheckpoint()) {
+ // Store failure reason for next reboot
+ try (BufferedWriter writer =
+ new BufferedWriter(new FileWriter(mFailureReasonFile))) {
+ writer.write(failureReason);
+ } catch (Exception e) {
+ Slog.w(TAG, "Failed to save failure reason: ", e);
+ }
+
// Only revert apex sessions if device supports updating apex
if (mApexManager.isApexSupported()) {
mApexManager.revertActiveSessions();
@@ -592,14 +614,12 @@ public class StagingManager {
// If checkpoint is supported, then we only resume sessions if we are in checkpointing
// mode. If not, we fail all sessions.
if (supportsCheckpoint() && !needsCheckpoint()) {
- // TODO(b/146343545): Persist failure reason across checkpoint reboot
- Slog.d(TAG, "Reverting back to safe state. Marking " + session.sessionId
- + " as failed.");
- String errorMsg = "Reverting back to safe state";
- if (!TextUtils.isEmpty(mNativeFailureReason)) {
- errorMsg = "Entered fs-rollback mode and reverted session due to crashing "
- + "native process: " + mNativeFailureReason;
+ String errorMsg = "Reverting back to safe state. Marking " + session.sessionId
+ + " as failed";
+ if (!TextUtils.isEmpty(mFailureReason)) {
+ errorMsg = errorMsg + ": " + mFailureReason;
}
+ Slog.d(TAG, errorMsg);
session.setStagedSessionFailed(SessionInfo.STAGED_SESSION_UNKNOWN, errorMsg);
return;
}
@@ -624,7 +644,7 @@ public class StagingManager {
+ "supposed to be activated";
session.setStagedSessionFailed(SessionInfo.STAGED_SESSION_ACTIVATION_FAILED,
errorMsg);
- abortCheckpoint(errorMsg);
+ abortCheckpoint(session.sessionId, errorMsg);
return;
}
if (isApexSessionFailed(apexSessionInfo)) {
@@ -636,7 +656,7 @@ public class StagingManager {
}
session.setStagedSessionFailed(SessionInfo.STAGED_SESSION_ACTIVATION_FAILED,
errorMsg);
- abortCheckpoint(errorMsg);
+ abortCheckpoint(session.sessionId, errorMsg);
return;
}
if (!apexSessionInfo.isActivated && !apexSessionInfo.isSuccess) {
@@ -647,7 +667,7 @@ public class StagingManager {
+ "didn't activate nor fail. Marking it as failed anyway.";
session.setStagedSessionFailed(SessionInfo.STAGED_SESSION_ACTIVATION_FAILED,
errorMsg);
- abortCheckpoint(errorMsg);
+ abortCheckpoint(session.sessionId, errorMsg);
return;
}
}
@@ -664,7 +684,7 @@ public class StagingManager {
installApksInSession(session);
} catch (PackageManagerException e) {
session.setStagedSessionFailed(e.error, e.getMessage());
- abortCheckpoint(e.getMessage());
+ abortCheckpoint(session.sessionId, e.getMessage());
// If checkpoint is not supported, we have to handle failure for one staged session.
if (!hasApex) {
@@ -1189,6 +1209,8 @@ public class StagingManager {
ctx.unregisterReceiver(this);
}
}, new IntentFilter(Intent.ACTION_BOOT_COMPLETED));
+
+ mFailureReasonFile.delete();
}
private static class LocalIntentReceiverAsync {
diff --git a/services/core/java/com/android/server/pm/TEST_MAPPING b/services/core/java/com/android/server/pm/TEST_MAPPING
index 2614076e9b6c..eb51cc3cd25c 100644
--- a/services/core/java/com/android/server/pm/TEST_MAPPING
+++ b/services/core/java/com/android/server/pm/TEST_MAPPING
@@ -69,6 +69,9 @@
"exclude-annotation": "androidx.test.filters.Suppress"
}
]
+ },
+ {
+ "name": "PackageManagerServiceHostTests"
}
],
"postsubmit": [
diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java
index d5c9424528bd..2a6997cba4bb 100644
--- a/services/core/java/com/android/server/pm/UserManagerService.java
+++ b/services/core/java/com/android/server/pm/UserManagerService.java
@@ -989,6 +989,15 @@ public class UserManagerService extends IUserManager.Stub {
ensureCanModifyQuietMode(
callingPackage, Binder.getCallingUid(), userId, target != null, dontAskCredential);
+
+ if (onlyIfCredentialNotRequired && callingPackage.equals(
+ getPackageManagerInternal().getSystemUiServiceComponent().getPackageName())) {
+ // This is to prevent SysUI from accidentally allowing the profile to turned on
+ // without password when keyguard is still locked.
+ throw new SecurityException("SystemUI is not allowed to set "
+ + "QUIET_MODE_DISABLE_ONLY_IF_CREDENTIAL_NOT_REQUIRED");
+ }
+
final long identity = Binder.clearCallingIdentity();
try {
if (enableQuietMode) {
@@ -996,7 +1005,17 @@ public class UserManagerService extends IUserManager.Stub {
userId, true /* enableQuietMode */, target, callingPackage);
return true;
}
- mLockPatternUtils.tryUnlockWithCachedUnifiedChallenge(userId);
+ if (mLockPatternUtils.isManagedProfileWithUnifiedChallenge(userId)) {
+ KeyguardManager km = mContext.getSystemService(KeyguardManager.class);
+ // Normally only attempt to auto-unlock unified challenge if keyguard is not showing
+ // (to stop turning profile on automatically via the QS tile), except when we
+ // are called with QUIET_MODE_DISABLE_ONLY_IF_CREDENTIAL_NOT_REQUIRED, in which
+ // case always attempt to auto-unlock.
+ if (!km.isDeviceLocked(mLocalService.getProfileParentId(userId))
+ || onlyIfCredentialNotRequired) {
+ mLockPatternUtils.tryUnlockWithCachedUnifiedChallenge(userId);
+ }
+ }
final boolean needToShowConfirmCredential = !dontAskCredential
&& mLockPatternUtils.isSecure(userId)
&& !StorageManager.isUserKeyUnlocked(userId);
@@ -1029,6 +1048,8 @@ public class UserManagerService extends IUserManager.Stub {
*/
private void ensureCanModifyQuietMode(String callingPackage, int callingUid,
@UserIdInt int targetUserId, boolean startIntent, boolean dontAskCredential) {
+ verifyCallingPackage(callingPackage, callingUid);
+
if (hasManageUsersPermission()) {
return;
}
@@ -1050,7 +1071,6 @@ public class UserManagerService extends IUserManager.Stub {
return;
}
- verifyCallingPackage(callingPackage, callingUid);
final ShortcutServiceInternal shortcutInternal =
LocalServices.getService(ShortcutServiceInternal.class);
if (shortcutInternal != null) {
@@ -2250,9 +2270,6 @@ public class UserManagerService extends IUserManager.Stub {
// Managed profiles have their own specific rules.
final boolean isManagedProfile = type.isManagedProfile();
if (isManagedProfile) {
- if (ActivityManager.isLowRamDeviceStatic()) {
- return false;
- }
if (!mContext.getPackageManager().hasSystemFeature(
PackageManager.FEATURE_MANAGED_USERS)) {
return false;
diff --git a/services/core/java/com/android/server/pm/UserSystemPackageInstaller.java b/services/core/java/com/android/server/pm/UserSystemPackageInstaller.java
index 58732b4c778f..7c89b9850c5d 100644
--- a/services/core/java/com/android/server/pm/UserSystemPackageInstaller.java
+++ b/services/core/java/com/android/server/pm/UserSystemPackageInstaller.java
@@ -96,6 +96,8 @@ import java.util.Set;
class UserSystemPackageInstaller {
private static final String TAG = "UserManagerService";
+ private static final boolean DEBUG = false;
+
/**
* System Property whether to only install system packages on a user if they're whitelisted for
* that user type. These are flags and can be freely combined.
@@ -328,12 +330,15 @@ class UserSystemPackageInstaller {
// Check whether all whitelisted packages are indeed on the system.
final String notPresentFmt = "%s is whitelisted but not present.";
final String notSystemFmt = "%s is whitelisted and present but not a system package.";
+ final String overlayPackageFmt = "%s is whitelisted but it's auto-generated RRO package.";
for (String pkgName : allWhitelistedPackages) {
final AndroidPackage pkg = pmInt.getPackage(pkgName);
if (pkg == null) {
warnings.add(String.format(notPresentFmt, pkgName));
} else if (!pkg.isSystem()) {
warnings.add(String.format(notSystemFmt, pkgName));
+ } else if (isAutoGeneratedRRO(pkg)) {
+ warnings.add(String.format(overlayPackageFmt, pkgName));
}
}
return warnings;
@@ -407,6 +412,23 @@ class UserSystemPackageInstaller {
return isImplicitWhitelistSystemMode(getWhitelistMode());
}
+ /**
+ * Whether package name has auto-generated RRO package name suffix.
+ */
+ @VisibleForTesting
+ static boolean hasAutoGeneratedRROSuffix(String name) {
+ return name.endsWith(".auto_generated_rro_product__")
+ || name.endsWith(".auto_generated_rro_vendor__");
+ }
+
+ /**
+ * Whether the package is auto-generated RRO package.
+ */
+ private static boolean isAutoGeneratedRRO(AndroidPackage pkg) {
+ return pkg.isOverlay()
+ && (hasAutoGeneratedRROSuffix(pkg.getManifestPackageName()));
+ }
+
/** See {@link #isEnforceMode()}. */
private static boolean isEnforceMode(int whitelistMode) {
return (whitelistMode & USER_TYPE_PACKAGE_WHITELIST_MODE_ENFORCE) != 0;
@@ -518,7 +540,18 @@ class UserSystemPackageInstaller {
static boolean shouldInstallPackage(AndroidPackage sysPkg,
@NonNull ArrayMap<String, Long> userTypeWhitelist,
@NonNull Set<String> userWhitelist, boolean implicitlyWhitelist) {
- final String pkgName = sysPkg.getManifestPackageName();
+ final String pkgName;
+ if (isAutoGeneratedRRO(sysPkg)) {
+ pkgName = sysPkg.getOverlayTarget();
+ if (DEBUG) {
+ Slog.i(TAG, "shouldInstallPackage(): " + sysPkg.getManifestPackageName()
+ + " is auto-generated RRO package, will look for overlay system package: "
+ + pkgName);
+ }
+ } else {
+ pkgName = sysPkg.getManifestPackageName();
+ }
+
return (implicitlyWhitelist && !userTypeWhitelist.containsKey(pkgName))
|| userWhitelist.contains(pkgName);
}
diff --git a/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java b/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java
index 8f3bf39d4fc5..cd53fb9ba52f 100644
--- a/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java
+++ b/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java
@@ -816,7 +816,7 @@ public final class DefaultPermissionGrantPolicy {
if (!TextUtils.isEmpty(contentCapturePackageName)) {
grantPermissionsToSystemPackage(pm, contentCapturePackageName, userId,
PHONE_PERMISSIONS, SMS_PERMISSIONS, ALWAYS_LOCATION_PERMISSIONS,
- CONTACTS_PERMISSIONS, STORAGE_PERMISSIONS);
+ CONTACTS_PERMISSIONS);
}
// Atthention Service
diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
index b0d4d957fc21..d3f3ba1dc6bb 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
@@ -26,6 +26,7 @@ import static android.content.pm.ApplicationInfo.AUTO_REVOKE_DISCOURAGED;
import static android.content.pm.PackageManager.FLAGS_PERMISSION_RESTRICTION_ANY_EXEMPT;
import static android.content.pm.PackageManager.FLAG_PERMISSION_APPLY_RESTRICTION;
import static android.content.pm.PackageManager.FLAG_PERMISSION_GRANTED_BY_DEFAULT;
+import static android.content.pm.PackageManager.FLAG_PERMISSION_GRANTED_BY_ROLE;
import static android.content.pm.PackageManager.FLAG_PERMISSION_ONE_TIME;
import static android.content.pm.PackageManager.FLAG_PERMISSION_POLICY_FIXED;
import static android.content.pm.PackageManager.FLAG_PERMISSION_REVIEW_REQUIRED;
@@ -1804,8 +1805,9 @@ public class PermissionManagerService extends IPermissionManager.Stub {
continue;
}
- // If this permission was granted by default, make sure it is.
- if ((oldFlags & FLAG_PERMISSION_GRANTED_BY_DEFAULT) != 0) {
+ // If this permission was granted by default or role, make sure it is.
+ if ((oldFlags & FLAG_PERMISSION_GRANTED_BY_DEFAULT) != 0
+ || (oldFlags & FLAG_PERMISSION_GRANTED_BY_ROLE) != 0) {
// PermissionPolicyService will handle the app op for runtime permissions later.
grantRuntimePermissionInternal(permName, packageName, false,
Process.SYSTEM_UID, userId, delayingPermCallback);
@@ -4948,6 +4950,20 @@ public class PermissionManagerService extends IPermissionManager.Stub {
StorageManager.UUID_PRIVATE_INTERNAL, true, mDefaultPermissionCallback);
}
}
+
+ @Override
+ public void retainHardAndSoftRestrictedPermissions(@NonNull List<String> permissions) {
+ synchronized (mLock) {
+ Iterator<String> iterator = permissions.iterator();
+ while (iterator.hasNext()) {
+ String permission = iterator.next();
+ BasePermission basePermission = mSettings.mPermissions.get(permission);
+ if (basePermission == null || !basePermission.isHardOrSoftRestricted()) {
+ iterator.remove();
+ }
+ }
+ }
+ }
}
private static final class OnPermissionChangeListeners extends Handler {
diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInternal.java b/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInternal.java
index 57a25eddf7ce..4412162a5cc8 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInternal.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInternal.java
@@ -36,6 +36,7 @@ import java.util.function.Consumer;
* TODO: Should be merged into PermissionManagerInternal, but currently uses internal classes.
*/
public abstract class PermissionManagerServiceInternal extends PermissionManagerInternal {
+
/**
* Provider for package names.
*/
@@ -455,4 +456,10 @@ public abstract class PermissionManagerServiceInternal extends PermissionManager
/** Called when a new user has been created. */
public abstract void onNewUserCreated(@UserIdInt int userId);
+
+ /**
+ * Removes invalid permissions which are not {@link PermissionInfo#FLAG_HARD_RESTRICTED} or
+ * {@link PermissionInfo#FLAG_SOFT_RESTRICTED} from the input.
+ */
+ public abstract void retainHardAndSoftRestrictedPermissions(@NonNull List<String> permissions);
}
diff --git a/services/core/java/com/android/server/power/Notifier.java b/services/core/java/com/android/server/power/Notifier.java
index 0b95be15f157..8f0fd607f928 100644
--- a/services/core/java/com/android/server/power/Notifier.java
+++ b/services/core/java/com/android/server/power/Notifier.java
@@ -616,6 +616,7 @@ public class Notifier {
} catch (RemoteException ex) {
// Ignore
}
+ FrameworkStatsLog.write(FrameworkStatsLog.DISPLAY_WAKE_REPORTED, reason);
}
/**
diff --git a/services/core/java/com/android/server/power/PreRebootLogger.java b/services/core/java/com/android/server/power/PreRebootLogger.java
index cda00b404c0b..c9e81ed7a796 100644
--- a/services/core/java/com/android/server/power/PreRebootLogger.java
+++ b/services/core/java/com/android/server/power/PreRebootLogger.java
@@ -16,6 +16,7 @@
package com.android.server.power;
+import android.annotation.DurationMillisLong;
import android.annotation.NonNull;
import android.content.Context;
import android.os.Environment;
@@ -23,7 +24,7 @@ import android.os.IBinder;
import android.os.ParcelFileDescriptor;
import android.os.RemoteException;
import android.os.ServiceManager;
-import android.provider.Settings;
+import android.provider.Settings.Global;
import android.util.Slog;
import com.android.internal.annotations.GuardedBy;
@@ -34,6 +35,8 @@ import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileWriter;
import java.io.IOException;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicBoolean;
/**
* Provides utils to dump/wipe pre-reboot information.
@@ -46,10 +49,12 @@ final class PreRebootLogger {
private static final String[] SERVICES_TO_DUMP = {Context.ROLLBACK_SERVICE, "package"};
private static final Object sLock = new Object();
+ private static final long MAX_DUMP_TIME = TimeUnit.SECONDS.toMillis(20);
/**
* Process pre-reboot information. Dump pre-reboot information to {@link #PREREBOOT_DIR} if
- * enabled {@link Settings.Global#ADB_ENABLED}; wipe dumped information otherwise.
+ * enabled {@link Settings.Global#ADB_ENABLED} and having active staged session; wipe dumped
+ * information otherwise.
*/
static void log(Context context) {
log(context, getDumpDir());
@@ -57,28 +62,49 @@ final class PreRebootLogger {
@VisibleForTesting
static void log(Context context, @NonNull File dumpDir) {
- if (Settings.Global.getInt(
- context.getContentResolver(), Settings.Global.ADB_ENABLED, 0) == 1) {
- Slog.d(TAG, "Dumping pre-reboot information...");
- dump(dumpDir);
+ if (needDump(context)) {
+ dump(dumpDir, MAX_DUMP_TIME);
} else {
- Slog.d(TAG, "Wiping pre-reboot information...");
wipe(dumpDir);
}
}
- private static void dump(@NonNull File dumpDir) {
- synchronized (sLock) {
- for (String buffer : BUFFERS_TO_DUMP) {
- dumpLogsLocked(dumpDir, buffer);
- }
- for (String service : SERVICES_TO_DUMP) {
- dumpServiceLocked(dumpDir, service);
+ private static boolean needDump(Context context) {
+ return Global.getInt(context.getContentResolver(), Global.ADB_ENABLED, 0) == 1
+ && !context.getPackageManager().getPackageInstaller()
+ .getActiveStagedSessions().isEmpty();
+ }
+
+ @VisibleForTesting
+ static void dump(@NonNull File dumpDir, @DurationMillisLong long maxWaitTime) {
+ Slog.d(TAG, "Dumping pre-reboot information...");
+ final AtomicBoolean done = new AtomicBoolean(false);
+ final Thread t = new Thread(() -> {
+ synchronized (sLock) {
+ for (String buffer : BUFFERS_TO_DUMP) {
+ dumpLogsLocked(dumpDir, buffer);
+ }
+ for (String service : SERVICES_TO_DUMP) {
+ dumpServiceLocked(dumpDir, service);
+ }
}
+ done.set(true);
+ });
+ t.start();
+
+ try {
+ t.join(maxWaitTime);
+ } catch (InterruptedException e) {
+ Slog.e(TAG, "Failed to dump pre-reboot information due to interrupted", e);
+ }
+
+ if (!done.get()) {
+ Slog.w(TAG, "Failed to dump pre-reboot information due to timeout");
}
}
private static void wipe(@NonNull File dumpDir) {
+ Slog.d(TAG, "Wiping pre-reboot information...");
synchronized (sLock) {
for (File file : dumpDir.listFiles()) {
file.delete();
@@ -109,7 +135,7 @@ final class PreRebootLogger {
{"logcat", "-d", "-b", buffer, "-f", dumpFile.getAbsolutePath()};
Runtime.getRuntime().exec(cmdline).waitFor();
} catch (IOException | InterruptedException e) {
- Slog.d(TAG, "Dump system log buffer before reboot fail", e);
+ Slog.e(TAG, "Failed to dump system log buffer before reboot", e);
}
}
@@ -127,7 +153,7 @@ final class PreRebootLogger {
| ParcelFileDescriptor.MODE_WRITE_ONLY);
binder.dump(fd.getFileDescriptor(), ArrayUtils.emptyArray(String.class));
} catch (FileNotFoundException | RemoteException e) {
- Slog.d(TAG, String.format("Dump %s service before reboot fail", serviceName), e);
+ Slog.e(TAG, String.format("Failed to dump %s service before reboot", serviceName), e);
}
}
}
diff --git a/services/core/java/com/android/server/slice/SliceClientPermissions.java b/services/core/java/com/android/server/slice/SliceClientPermissions.java
index ab94a59c4d9c..e241205cfb99 100644
--- a/services/core/java/com/android/server/slice/SliceClientPermissions.java
+++ b/services/core/java/com/android/server/slice/SliceClientPermissions.java
@@ -160,6 +160,9 @@ public class SliceClientPermissions implements DirtyTracker, Persistable {
// Get to the beginning of the provider.
while (parser.getEventType() != XmlPullParser.START_TAG
|| !TAG_CLIENT.equals(parser.getName())) {
+ if (parser.getEventType() == XmlPullParser.END_DOCUMENT) {
+ throw new XmlPullParserException("Can't find client tag in xml");
+ }
parser.next();
}
int depth = parser.getDepth();
@@ -173,6 +176,9 @@ public class SliceClientPermissions implements DirtyTracker, Persistable {
parser.next();
while (parser.getDepth() > depth) {
+ if (parser.getEventType() == XmlPullParser.END_DOCUMENT) {
+ return provider;
+ }
if (parser.getEventType() == XmlPullParser.START_TAG
&& TAG_AUTHORITY.equals(parser.getName())) {
try {
diff --git a/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerModule.java b/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerModule.java
index 49c781905898..522e5e189232 100644
--- a/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerModule.java
+++ b/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerModule.java
@@ -23,8 +23,12 @@ import android.hardware.soundtrigger.V2_2.ISoundTriggerHw;
import android.media.soundtrigger_middleware.ISoundTriggerCallback;
import android.media.soundtrigger_middleware.ISoundTriggerModule;
import android.media.soundtrigger_middleware.ModelParameterRange;
+import android.media.soundtrigger_middleware.PhraseRecognitionEvent;
+import android.media.soundtrigger_middleware.PhraseRecognitionExtra;
import android.media.soundtrigger_middleware.PhraseSoundModel;
import android.media.soundtrigger_middleware.RecognitionConfig;
+import android.media.soundtrigger_middleware.RecognitionEvent;
+import android.media.soundtrigger_middleware.RecognitionStatus;
import android.media.soundtrigger_middleware.SoundModel;
import android.media.soundtrigger_middleware.SoundModelType;
import android.media.soundtrigger_middleware.SoundTriggerModuleProperties;
@@ -540,20 +544,20 @@ class SoundTriggerModule implements IHwBinder.DeathRecipient {
switch (mModelType) {
case SoundModelType.GENERIC: {
android.media.soundtrigger_middleware.RecognitionEvent event =
- new android.media.soundtrigger_middleware.RecognitionEvent();
+ newEmptyRecognitionEvent();
event.status =
android.media.soundtrigger_middleware.RecognitionStatus.ABORTED;
+ event.type = SoundModelType.GENERIC;
mCallback.onRecognition(mHandle, event);
}
break;
case SoundModelType.KEYPHRASE: {
android.media.soundtrigger_middleware.PhraseRecognitionEvent event =
- new android.media.soundtrigger_middleware.PhraseRecognitionEvent();
- event.common =
- new android.media.soundtrigger_middleware.RecognitionEvent();
+ newEmptyPhraseRecognitionEvent();
event.common.status =
android.media.soundtrigger_middleware.RecognitionStatus.ABORTED;
+ event.common.type = SoundModelType.KEYPHRASE;
mCallback.onPhraseRecognition(mHandle, event);
}
break;
@@ -574,7 +578,7 @@ class SoundTriggerModule implements IHwBinder.DeathRecipient {
@NonNull ISoundTriggerHwCallback.RecognitionEvent recognitionEvent,
int cookie) {
synchronized (SoundTriggerModule.this) {
- android.media.soundtrigger_middleware.RecognitionEvent aidlEvent =
+ RecognitionEvent aidlEvent =
ConversionUtil.hidl2aidlRecognitionEvent(recognitionEvent);
aidlEvent.captureSession = mSession.mSessionHandle;
try {
@@ -584,8 +588,7 @@ class SoundTriggerModule implements IHwBinder.DeathRecipient {
// In any case, client callbacks are considered best effort.
Log.e(TAG, "Client callback execption.", e);
}
- if (aidlEvent.status
- != android.media.soundtrigger_middleware.RecognitionStatus.FORCED) {
+ if (aidlEvent.status != RecognitionStatus.FORCED) {
setState(ModelState.LOADED);
}
}
@@ -596,7 +599,7 @@ class SoundTriggerModule implements IHwBinder.DeathRecipient {
@NonNull ISoundTriggerHwCallback.PhraseRecognitionEvent phraseRecognitionEvent,
int cookie) {
synchronized (SoundTriggerModule.this) {
- android.media.soundtrigger_middleware.PhraseRecognitionEvent aidlEvent =
+ PhraseRecognitionEvent aidlEvent =
ConversionUtil.hidl2aidlPhraseRecognitionEvent(phraseRecognitionEvent);
aidlEvent.common.captureSession = mSession.mSessionHandle;
try {
@@ -606,12 +609,40 @@ class SoundTriggerModule implements IHwBinder.DeathRecipient {
// In any case, client callbacks are considered best effort.
Log.e(TAG, "Client callback execption.", e);
}
- if (aidlEvent.common.status
- != android.media.soundtrigger_middleware.RecognitionStatus.FORCED) {
+ if (aidlEvent.common.status != RecognitionStatus.FORCED) {
setState(ModelState.LOADED);
}
}
}
}
}
+
+ /**
+ * Creates a default-initialized recognition event.
+ *
+ * Non-nullable object fields are default constructed.
+ * Non-nullable array fields are initialized to 0 length.
+ *
+ * @return The event.
+ */
+ private static RecognitionEvent newEmptyRecognitionEvent() {
+ RecognitionEvent result = new RecognitionEvent();
+ result.data = new byte[0];
+ return result;
+ }
+
+ /**
+ * Creates a default-initialized phrase recognition event.
+ *
+ * Non-nullable object fields are default constructed.
+ * Non-nullable array fields are initialized to 0 length.
+ *
+ * @return The event.
+ */
+ private static PhraseRecognitionEvent newEmptyPhraseRecognitionEvent() {
+ PhraseRecognitionEvent result = new PhraseRecognitionEvent();
+ result.common = newEmptyRecognitionEvent();
+ result.phraseExtras = new PhraseRecognitionExtra[0];
+ return result;
+ }
}
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 22455ad39960..c2bae1a8962b 100644
--- a/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java
+++ b/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java
@@ -19,6 +19,8 @@ package com.android.server.stats.pull;
import static android.app.AppOpsManager.OP_FLAG_SELF;
import static android.app.AppOpsManager.OP_FLAG_TRUSTED_PROXIED;
import static android.app.usage.NetworkStatsManager.FLAG_AUGMENT_WITH_SUBSCRIPTION_PLAN;
+import static android.app.usage.NetworkStatsManager.FLAG_POLL_FORCE;
+import static android.app.usage.NetworkStatsManager.FLAG_POLL_ON_OPEN;
import static android.content.pm.PackageInfo.REQUESTED_PERMISSION_GRANTED;
import static android.content.pm.PermissionInfo.PROTECTION_DANGEROUS;
import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
@@ -189,7 +191,6 @@ import java.util.Random;
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.CompletableFuture;
-import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.Executor;
import java.util.concurrent.ThreadLocalRandom;
import java.util.concurrent.TimeUnit;
@@ -243,11 +244,6 @@ public class StatsPullAtomService extends SystemService {
private static final String DANGEROUS_PERMISSION_STATE_SAMPLE_RATE =
"dangerous_permission_state_sample_rate";
- private final Object mNetworkStatsLock = new Object();
- @GuardedBy("mNetworkStatsLock")
- @Nullable
- private INetworkStatsSession mNetworkStatsSession;
-
private final Object mThermalLock = new Object();
@GuardedBy("mThermalLock")
private IThermalService mThermalService;
@@ -260,21 +256,17 @@ public class StatsPullAtomService extends SystemService {
@GuardedBy("mNotificationStatsLock")
private INotificationManager mNotificationManagerService;
- private final Object mProcessStatsLock = new Object();
- @GuardedBy("mProcessStatsLock")
+ @GuardedBy("mProcStatsLock")
private IProcessStats mProcessStatsService;
- private final Object mCpuTrackerLock = new Object();
- @GuardedBy("mCpuTrackerLock")
+ @GuardedBy("mProcessCpuTimeLock")
private ProcessCpuTracker mProcessCpuTracker;
- private final Object mDebugElapsedClockLock = new Object();
@GuardedBy("mDebugElapsedClockLock")
private long mDebugElapsedClockPreviousValue = 0;
@GuardedBy("mDebugElapsedClockLock")
private long mDebugElapsedClockPullCount = 0;
- private final Object mDebugFailingElapsedClockLock = new Object();
@GuardedBy("mDebugFailingElapsedClockLock")
private long mDebugFailingElapsedClockPreviousValue = 0;
@GuardedBy("mDebugFailingElapsedClockLock")
@@ -287,26 +279,40 @@ public class StatsPullAtomService extends SystemService {
private TelephonyManager mTelephony;
private SubscriptionManager mSubscriptionManager;
+ @GuardedBy("mKernelWakelockLock")
private KernelWakelockReader mKernelWakelockReader;
+ @GuardedBy("mKernelWakelockLock")
private KernelWakelockStats mTmpWakelockStats;
+ @GuardedBy("mDiskIoLock")
private StoragedUidIoStatsReader mStoragedUidIoStatsReader;
+ @GuardedBy("mCpuTimePerFreqLock")
private KernelCpuSpeedReader[] mKernelCpuSpeedReaders;
// Disables throttler on CPU time readers.
+ @GuardedBy("mCpuTimePerUidLock")
private KernelCpuUidUserSysTimeReader mCpuUidUserSysTimeReader;
+ @GuardedBy("mCpuTimePerUidFreqLock")
private KernelCpuUidFreqTimeReader mCpuUidFreqTimeReader;
+ @GuardedBy("mCpuActiveTimeLock")
private KernelCpuUidActiveTimeReader mCpuUidActiveTimeReader;
+ @GuardedBy("mClusterTimeLock")
private KernelCpuUidClusterTimeReader mCpuUidClusterTimeReader;
+ @GuardedBy("mProcStatsLock")
private File mBaseDir;
+ @GuardedBy("mHealthHalLock")
private BatteryService.HealthServiceWrapper mHealthService;
@Nullable
+ @GuardedBy("mCpuTimePerThreadFreqLock")
private KernelCpuThreadReaderDiff mKernelCpuThreadReader;
+ private final Object mBatteryStatsHelperLock = new Object();
+ @GuardedBy("mBatteryStatsHelperLock")
private BatteryStatsHelper mBatteryStatsHelper = null;
+ @GuardedBy("mBatteryStatsHelperLock")
private long mBatteryStatsHelperTimestampMs = -MAX_BATTERY_STATS_HELPER_FREQUENCY_MS;
private StatsPullAtomCallbackImpl mStatsCallbackImpl;
@@ -314,19 +320,75 @@ public class StatsPullAtomService extends SystemService {
private final Object mAppOpsSamplingRateLock = new Object();
@GuardedBy("mAppOpsSamplingRateLock")
private int mAppOpsSamplingRate = 0;
+ private final Object mDangerousAppOpsListLock = new Object();
+ @GuardedBy("mDangerousAppOpsListLock")
private final ArraySet<Integer> mDangerousAppOpsList = new ArraySet<>();
// Baselines that stores list of NetworkStats right after initializing, with associated
- // information. This is used to calculate difference when pulling
- // {Mobile|Wifi}BytesTransfer* atoms. Note that this is not thread-safe, and must
- // only be accessed on the background thread.
+ // information. This is used to calculate difference when pulling BytesTransfer atoms.
@NonNull
- private final List<NetworkStatsExt> mNetworkStatsBaselines = new ArrayList<>();
+ @GuardedBy("mDataBytesTransferLock")
+ private final ArrayList<NetworkStatsExt> mNetworkStatsBaselines = new ArrayList<>();
// Listener for monitoring subscriptions changed event.
private StatsSubscriptionsListener mStatsSubscriptionsListener;
- // List that store SubInfo of subscriptions that ever appeared since boot.
- private final CopyOnWriteArrayList<SubInfo> mHistoricalSubs = new CopyOnWriteArrayList<>();
+ // List that stores SubInfo of subscriptions that ever appeared since boot.
+ @GuardedBy("mDataBytesTransferLock")
+ private final ArrayList<SubInfo> mHistoricalSubs = new ArrayList<>();
+
+ // Puller locks
+ private final Object mDataBytesTransferLock = new Object();
+ private final Object mBluetoothBytesTransferLock = new Object();
+ private final Object mKernelWakelockLock = new Object();
+ private final Object mCpuTimePerFreqLock = new Object();
+ private final Object mCpuTimePerUidLock = new Object();
+ private final Object mCpuTimePerUidFreqLock = new Object();
+ private final Object mCpuActiveTimeLock = new Object();
+ private final Object mCpuClusterTimeLock = new Object();
+ private final Object mWifiActivityInfoLock = new Object();
+ private final Object mModemActivityInfoLock = new Object();
+ private final Object mBluetoothActivityInfoLock = new Object();
+ private final Object mSystemElapsedRealtimeLock = new Object();
+ private final Object mSystemUptimeLock = new Object();
+ private final Object mProcessMemoryStateLock = new Object();
+ private final Object mProcessMemoryHighWaterMarkLock = new Object();
+ private final Object mProcessMemorySnapshotLock = new Object();
+ private final Object mSystemIonHeapSizeLock = new Object();
+ private final Object mIonHeapSizeLock = new Object();
+ private final Object mProcessSystemIonHeapSizeLock = new Object();
+ private final Object mTemperatureLock = new Object();
+ private final Object mCooldownDeviceLock = new Object();
+ private final Object mBinderCallsStatsLock = new Object();
+ private final Object mBinderCallsStatsExceptionsLock = new Object();
+ private final Object mLooperStatsLock = new Object();
+ private final Object mDiskStatsLock = new Object();
+ private final Object mDirectoryUsageLock = new Object();
+ private final Object mAppSizeLock = new Object();
+ private final Object mCategorySizeLock = new Object();
+ private final Object mNumBiometricsEnrolledLock = new Object();
+ private final Object mProcStatsLock = new Object();
+ private final Object mDiskIoLock = new Object();
+ private final Object mPowerProfileLock = new Object();
+ private final Object mProcessCpuTimeLock = new Object();
+ private final Object mCpuTimePerThreadFreqLock = new Object();
+ private final Object mDeviceCalculatedPowerUseLock = new Object();
+ private final Object mDeviceCalculatedPowerBlameUidLock = new Object();
+ private final Object mDeviceCalculatedPowerBlameOtherLock = new Object();
+ private final Object mDebugElapsedClockLock = new Object();
+ private final Object mDebugFailingElapsedClockLock = new Object();
+ private final Object mBuildInformationLock = new Object();
+ private final Object mRoleHolderLock = new Object();
+ private final Object mTimeZoneDataInfoLock = new Object();
+ private final Object mExternalStorageInfoLock = new Object();
+ private final Object mAppsOnExternalStorageInfoLock = new Object();
+ private final Object mFaceSettingsLock = new Object();
+ private final Object mAppOpsLock = new Object();
+ private final Object mRuntimeAppOpAccessMessageLock = new Object();
+ private final Object mNotificationRemoteViewsLock = new Object();
+ private final Object mDangerousPermissionStateLock = new Object();
+ private final Object mHealthHalLock = new Object();
+ private final Object mAttributedAppOpsLock = new Object();
+ private final Object mSettingsStatsLock = new Object();
public StatsPullAtomService(Context context) {
super(context);
@@ -356,123 +418,229 @@ public class StatsPullAtomService extends SystemService {
case FrameworkStatsLog.MOBILE_BYTES_TRANSFER_BY_FG_BG:
case FrameworkStatsLog.BYTES_TRANSFER_BY_TAG_AND_METERED:
case FrameworkStatsLog.DATA_USAGE_BYTES_TRANSFER:
- return pullDataBytesTransfer(atomTag, data);
+ synchronized (mDataBytesTransferLock) {
+ return pullDataBytesTransferLocked(atomTag, data);
+ }
case FrameworkStatsLog.BLUETOOTH_BYTES_TRANSFER:
- return pullBluetoothBytesTransfer(atomTag, data);
+ synchronized (mBluetoothBytesTransferLock) {
+ return pullBluetoothBytesTransferLocked(atomTag, data);
+ }
case FrameworkStatsLog.KERNEL_WAKELOCK:
- return pullKernelWakelock(atomTag, data);
+ synchronized (mKernelWakelockLock) {
+ return pullKernelWakelockLocked(atomTag, data);
+ }
case FrameworkStatsLog.CPU_TIME_PER_FREQ:
- return pullCpuTimePerFreq(atomTag, data);
+ synchronized (mCpuTimePerFreqLock) {
+ return pullCpuTimePerFreqLocked(atomTag, data);
+ }
case FrameworkStatsLog.CPU_TIME_PER_UID:
- return pullCpuTimePerUid(atomTag, data);
+ synchronized (mCpuTimePerUidLock) {
+ return pullCpuTimePerUidLocked(atomTag, data);
+ }
case FrameworkStatsLog.CPU_TIME_PER_UID_FREQ:
- return pullCpuTimeperUidFreq(atomTag, data);
+ synchronized (mCpuTimePerUidFreqLock) {
+ return pullCpuTimePerUidFreqLocked(atomTag, data);
+ }
case FrameworkStatsLog.CPU_ACTIVE_TIME:
- return pullCpuActiveTime(atomTag, data);
+ synchronized (mCpuActiveTimeLock) {
+ return pullCpuActiveTimeLocked(atomTag, data);
+ }
case FrameworkStatsLog.CPU_CLUSTER_TIME:
- return pullCpuClusterTime(atomTag, data);
+ synchronized (mCpuClusterTimeLock) {
+ return pullCpuClusterTimeLocked(atomTag, data);
+ }
case FrameworkStatsLog.WIFI_ACTIVITY_INFO:
- return pullWifiActivityInfo(atomTag, data);
+ synchronized (mWifiActivityInfoLock) {
+ return pullWifiActivityInfoLocked(atomTag, data);
+ }
case FrameworkStatsLog.MODEM_ACTIVITY_INFO:
- return pullModemActivityInfo(atomTag, data);
+ synchronized (mModemActivityInfoLock) {
+ return pullModemActivityInfoLocked(atomTag, data);
+ }
case FrameworkStatsLog.BLUETOOTH_ACTIVITY_INFO:
- return pullBluetoothActivityInfo(atomTag, data);
+ synchronized (mBluetoothActivityInfoLock) {
+ return pullBluetoothActivityInfoLocked(atomTag, data);
+ }
case FrameworkStatsLog.SYSTEM_ELAPSED_REALTIME:
- return pullSystemElapsedRealtime(atomTag, data);
+ synchronized (mSystemElapsedRealtimeLock) {
+ return pullSystemElapsedRealtimeLocked(atomTag, data);
+ }
case FrameworkStatsLog.SYSTEM_UPTIME:
- return pullSystemUptime(atomTag, data);
+ synchronized (mSystemUptimeLock) {
+ return pullSystemUptimeLocked(atomTag, data);
+ }
case FrameworkStatsLog.PROCESS_MEMORY_STATE:
- return pullProcessMemoryState(atomTag, data);
+ synchronized (mProcessMemoryStateLock) {
+ return pullProcessMemoryStateLocked(atomTag, data);
+ }
case FrameworkStatsLog.PROCESS_MEMORY_HIGH_WATER_MARK:
- return pullProcessMemoryHighWaterMark(atomTag, data);
+ synchronized (mProcessMemoryHighWaterMarkLock) {
+ return pullProcessMemoryHighWaterMarkLocked(atomTag, data);
+ }
case FrameworkStatsLog.PROCESS_MEMORY_SNAPSHOT:
- return pullProcessMemorySnapshot(atomTag, data);
+ synchronized (mProcessMemorySnapshotLock) {
+ return pullProcessMemorySnapshotLocked(atomTag, data);
+ }
case FrameworkStatsLog.SYSTEM_ION_HEAP_SIZE:
- return pullSystemIonHeapSize(atomTag, data);
+ synchronized (mSystemIonHeapSizeLock) {
+ return pullSystemIonHeapSizeLocked(atomTag, data);
+ }
case FrameworkStatsLog.ION_HEAP_SIZE:
- return pullIonHeapSize(atomTag, data);
+ synchronized (mIonHeapSizeLock) {
+ return pullIonHeapSizeLocked(atomTag, data);
+ }
case FrameworkStatsLog.PROCESS_SYSTEM_ION_HEAP_SIZE:
- return pullProcessSystemIonHeapSize(atomTag, data);
+ synchronized (mProcessSystemIonHeapSizeLock) {
+ return pullProcessSystemIonHeapSizeLocked(atomTag, data);
+ }
case FrameworkStatsLog.TEMPERATURE:
- return pullTemperature(atomTag, data);
+ synchronized (mTemperatureLock) {
+ return pullTemperatureLocked(atomTag, data);
+ }
case FrameworkStatsLog.COOLING_DEVICE:
- return pullCooldownDevice(atomTag, data);
+ synchronized (mCooldownDeviceLock) {
+ return pullCooldownDeviceLocked(atomTag, data);
+ }
case FrameworkStatsLog.BINDER_CALLS:
- return pullBinderCallsStats(atomTag, data);
+ synchronized (mBinderCallsStatsLock) {
+ return pullBinderCallsStatsLocked(atomTag, data);
+ }
case FrameworkStatsLog.BINDER_CALLS_EXCEPTIONS:
- return pullBinderCallsStatsExceptions(atomTag, data);
+ synchronized (mBinderCallsStatsExceptionsLock) {
+ return pullBinderCallsStatsExceptionsLocked(atomTag, data);
+ }
case FrameworkStatsLog.LOOPER_STATS:
- return pullLooperStats(atomTag, data);
+ synchronized (mLooperStatsLock) {
+ return pullLooperStatsLocked(atomTag, data);
+ }
case FrameworkStatsLog.DISK_STATS:
- return pullDiskStats(atomTag, data);
+ synchronized (mDiskStatsLock) {
+ return pullDiskStatsLocked(atomTag, data);
+ }
case FrameworkStatsLog.DIRECTORY_USAGE:
- return pullDirectoryUsage(atomTag, data);
+ synchronized (mDirectoryUsageLock) {
+ return pullDirectoryUsageLocked(atomTag, data);
+ }
case FrameworkStatsLog.APP_SIZE:
- return pullAppSize(atomTag, data);
+ synchronized (mAppSizeLock) {
+ return pullAppSizeLocked(atomTag, data);
+ }
case FrameworkStatsLog.CATEGORY_SIZE:
- return pullCategorySize(atomTag, data);
+ synchronized (mCategorySizeLock) {
+ return pullCategorySizeLocked(atomTag, data);
+ }
case FrameworkStatsLog.NUM_FINGERPRINTS_ENROLLED:
- return pullNumBiometricsEnrolled(
- BiometricsProtoEnums.MODALITY_FINGERPRINT, atomTag, data);
+ synchronized (mNumBiometricsEnrolledLock) {
+ return pullNumBiometricsEnrolledLocked(
+ BiometricsProtoEnums.MODALITY_FINGERPRINT, atomTag, data);
+ }
case FrameworkStatsLog.NUM_FACES_ENROLLED:
- return pullNumBiometricsEnrolled(
- BiometricsProtoEnums.MODALITY_FACE, atomTag, data);
+ synchronized (mNumBiometricsEnrolledLock) {
+ return pullNumBiometricsEnrolledLocked(
+ BiometricsProtoEnums.MODALITY_FACE, atomTag, data);
+ }
case FrameworkStatsLog.PROC_STATS:
- return pullProcStats(ProcessStats.REPORT_ALL, atomTag, data);
+ synchronized (mProcStatsLock) {
+ return pullProcStatsLocked(ProcessStats.REPORT_ALL, atomTag, data);
+ }
case FrameworkStatsLog.PROC_STATS_PKG_PROC:
- return pullProcStats(ProcessStats.REPORT_PKG_PROC_STATS, atomTag, data);
+ synchronized (mProcStatsLock) {
+ return pullProcStatsLocked(ProcessStats.REPORT_PKG_PROC_STATS, atomTag,
+ data);
+ }
case FrameworkStatsLog.DISK_IO:
- return pullDiskIO(atomTag, data);
+ synchronized (mDiskIoLock) {
+ return pullDiskIOLocked(atomTag, data);
+ }
case FrameworkStatsLog.POWER_PROFILE:
- return pullPowerProfile(atomTag, data);
+ synchronized (mPowerProfileLock) {
+ return pullPowerProfileLocked(atomTag, data);
+ }
case FrameworkStatsLog.PROCESS_CPU_TIME:
- return pullProcessCpuTime(atomTag, data);
+ synchronized (mProcessCpuTimeLock) {
+ return pullProcessCpuTimeLocked(atomTag, data);
+ }
case FrameworkStatsLog.CPU_TIME_PER_THREAD_FREQ:
- return pullCpuTimePerThreadFreq(atomTag, data);
+ synchronized (mCpuTimePerThreadFreqLock) {
+ return pullCpuTimePerThreadFreqLocked(atomTag, data);
+ }
case FrameworkStatsLog.DEVICE_CALCULATED_POWER_USE:
- return pullDeviceCalculatedPowerUse(atomTag, data);
+ synchronized (mDeviceCalculatedPowerUseLock) {
+ return pullDeviceCalculatedPowerUseLocked(atomTag, data);
+ }
case FrameworkStatsLog.DEVICE_CALCULATED_POWER_BLAME_UID:
- return pullDeviceCalculatedPowerBlameUid(atomTag, data);
+ synchronized (mDeviceCalculatedPowerBlameUidLock) {
+ return pullDeviceCalculatedPowerBlameUidLocked(atomTag, data);
+ }
case FrameworkStatsLog.DEVICE_CALCULATED_POWER_BLAME_OTHER:
- return pullDeviceCalculatedPowerBlameOther(atomTag, data);
+ synchronized (mDeviceCalculatedPowerBlameOtherLock) {
+ return pullDeviceCalculatedPowerBlameOtherLocked(atomTag, data);
+ }
case FrameworkStatsLog.DEBUG_ELAPSED_CLOCK:
- return pullDebugElapsedClock(atomTag, data);
+ synchronized (mDebugElapsedClockLock) {
+ return pullDebugElapsedClockLocked(atomTag, data);
+ }
case FrameworkStatsLog.DEBUG_FAILING_ELAPSED_CLOCK:
- return pullDebugFailingElapsedClock(atomTag, data);
+ synchronized (mDebugFailingElapsedClockLock) {
+ return pullDebugFailingElapsedClockLocked(atomTag, data);
+ }
case FrameworkStatsLog.BUILD_INFORMATION:
- return pullBuildInformation(atomTag, data);
+ synchronized (mBuildInformationLock) {
+ return pullBuildInformationLocked(atomTag, data);
+ }
case FrameworkStatsLog.ROLE_HOLDER:
- return pullRoleHolder(atomTag, data);
+ synchronized (mRoleHolderLock) {
+ return pullRoleHolderLocked(atomTag, data);
+ }
case FrameworkStatsLog.DANGEROUS_PERMISSION_STATE:
- return pullDangerousPermissionState(atomTag, data);
+ case FrameworkStatsLog.DANGEROUS_PERMISSION_STATE_SAMPLED:
+ synchronized (mDangerousPermissionStateLock) {
+ return pullDangerousPermissionStateLocked(atomTag, data);
+ }
case FrameworkStatsLog.TIME_ZONE_DATA_INFO:
- return pullTimeZoneDataInfo(atomTag, data);
+ synchronized (mTimeZoneDataInfoLock) {
+ return pullTimeZoneDataInfoLocked(atomTag, data);
+ }
case FrameworkStatsLog.EXTERNAL_STORAGE_INFO:
- return pullExternalStorageInfo(atomTag, data);
+ synchronized (mExternalStorageInfoLock) {
+ return pullExternalStorageInfoLocked(atomTag, data);
+ }
case FrameworkStatsLog.APPS_ON_EXTERNAL_STORAGE_INFO:
- return pullAppsOnExternalStorageInfo(atomTag, data);
+ synchronized (mAppsOnExternalStorageInfoLock) {
+ return pullAppsOnExternalStorageInfoLocked(atomTag, data);
+ }
case FrameworkStatsLog.FACE_SETTINGS:
- return pullFaceSettings(atomTag, data);
+ synchronized (mFaceSettingsLock) {
+ return pullFaceSettingsLocked(atomTag, data);
+ }
case FrameworkStatsLog.APP_OPS:
- return pullAppOps(atomTag, data);
+ synchronized (mAppOpsLock) {
+ return pullAppOpsLocked(atomTag, data);
+ }
case FrameworkStatsLog.RUNTIME_APP_OP_ACCESS:
- return pullRuntimeAppOpAccessMessage(atomTag, data);
+ synchronized (mRuntimeAppOpAccessMessageLock) {
+ return pullRuntimeAppOpAccessMessageLocked(atomTag, data);
+ }
case FrameworkStatsLog.NOTIFICATION_REMOTE_VIEWS:
- return pullNotificationRemoteViews(atomTag, data);
- case FrameworkStatsLog.DANGEROUS_PERMISSION_STATE_SAMPLED:
- return pullDangerousPermissionState(atomTag, data);
+ synchronized (mNotificationRemoteViewsLock) {
+ return pullNotificationRemoteViewsLocked(atomTag, data);
+ }
case FrameworkStatsLog.BATTERY_LEVEL:
case FrameworkStatsLog.REMAINING_BATTERY_CAPACITY:
case FrameworkStatsLog.FULL_BATTERY_CAPACITY:
case FrameworkStatsLog.BATTERY_VOLTAGE:
case FrameworkStatsLog.BATTERY_CYCLE_COUNT:
- return pullHealthHal(atomTag, data);
+ synchronized (mHealthHalLock) {
+ return pullHealthHalLocked(atomTag, data);
+ }
case FrameworkStatsLog.ATTRIBUTED_APP_OPS:
- return pullAttributedAppOps(atomTag, data);
+ synchronized (mAttributedAppOpsLock) {
+ return pullAttributedAppOpsLocked(atomTag, data);
+ }
case FrameworkStatsLog.SETTING_SNAPSHOT:
- return pullSettingsStats(atomTag, data);
- case FrameworkStatsLog.DISPLAY_WAKE_REASON:
- return pullDisplayWakeStats(atomTag, data);
+ synchronized (mSettingsStatsLock) {
+ return pullSettingsStatsLocked(atomTag, data);
+ }
default:
throw new UnsupportedOperationException("Unknown tagId=" + atomTag);
}
@@ -503,6 +671,8 @@ public class StatsPullAtomService extends SystemService {
}
}
+ // We do not hold locks within this function because it is guaranteed to be called before the
+ // pullers are ever run, as the pullers are not yet registered with statsd.
void initializePullersState() {
// Get Context Managers
mStatsManager = (StatsManager) mContext.getSystemService(Context.STATS_MANAGER);
@@ -518,6 +688,7 @@ public class StatsPullAtomService extends SystemService {
// Initialize PROC_STATS
mBaseDir = new File(SystemServiceManager.ensureSystemDir(), "stats_pull");
+ mBaseDir.mkdirs();
// Disables throttler on CPU time readers.
mCpuUidUserSysTimeReader = new KernelCpuUidUserSysTimeReader(false);
@@ -545,9 +716,6 @@ public class StatsPullAtomService extends SystemService {
mKernelCpuThreadReader =
KernelCpuThreadReaderSettingsObserver.getSettingsModifiedReader(mContext);
- // Used by PROC_STATS and PROC_STATS_PKG_PROC atoms
- mBaseDir.mkdirs();
-
// Initialize HealthService
mHealthService = new BatteryService.HealthServiceWrapper();
try {
@@ -659,7 +827,6 @@ public class StatsPullAtomService extends SystemService {
registerBatteryVoltage();
registerBatteryCycleCount();
registerSettingsStats();
- registerDisplayWakeStats();
}
private void initAndRegisterNetworkStatsPullers() {
@@ -681,7 +848,7 @@ public class StatsPullAtomService extends SystemService {
collectNetworkStatsSnapshotForAtom(FrameworkStatsLog.DATA_USAGE_BYTES_TRANSFER));
// Listen to subscription changes to record historical subscriptions that activated before
- // pulling, this is used by {@link #pullMobileBytesTransfer}.
+ // pulling, this is used by {@code DATA_USAGE_BYTES_TRANSFER}.
mSubscriptionManager.addOnSubscriptionsChangedListener(
BackgroundThread.getExecutor(), mStatsSubscriptionsListener);
@@ -696,32 +863,26 @@ public class StatsPullAtomService extends SystemService {
/**
* Return the {@code INetworkStatsSession} object that holds the necessary properties needed
* for the subsequent queries to {@link com.android.server.net.NetworkStatsService}. Or
- * null if the service or binder cannot be obtained.
+ * null if the service or binder cannot be obtained. Calling this method will trigger poll
+ * in NetworkStatsService with once per 15 seconds rate-limit, unless {@code bypassRateLimit}
+ * is set to true. This is needed in {@link #getUidNetworkStatsSnapshotForTemplate}, where
+ * bypassing the limit is necessary for perfd to supply realtime stats to developers looking at
+ * the network usage of their app.
*/
@Nullable
- private INetworkStatsSession getNetworkStatsSession() {
- synchronized (mNetworkStatsLock) {
- if (mNetworkStatsSession != null) return mNetworkStatsSession;
-
- final INetworkStatsService networkStatsService =
- INetworkStatsService.Stub.asInterface(
- ServiceManager.getService(Context.NETWORK_STATS_SERVICE));
- if (networkStatsService == null) return null;
+ private INetworkStatsSession getNetworkStatsSession(boolean bypassRateLimit) {
+ final INetworkStatsService networkStatsService =
+ INetworkStatsService.Stub.asInterface(
+ ServiceManager.getService(Context.NETWORK_STATS_SERVICE));
+ if (networkStatsService == null) return null;
- try {
- networkStatsService.asBinder().linkToDeath(() -> {
- synchronized (mNetworkStatsLock) {
- mNetworkStatsSession = null;
- }
- }, /* flags */ 0);
- mNetworkStatsSession = networkStatsService.openSessionForUsageStats(
- FLAG_AUGMENT_WITH_SUBSCRIPTION_PLAN, mContext.getOpPackageName());
- } catch (RemoteException e) {
- Slog.e(TAG, "Cannot get NetworkStats session", e);
- mNetworkStatsSession = null;
- }
-
- return mNetworkStatsSession;
+ try {
+ return networkStatsService.openSessionForUsageStats(
+ FLAG_AUGMENT_WITH_SUBSCRIPTION_PLAN | (bypassRateLimit ? FLAG_POLL_FORCE
+ : FLAG_POLL_ON_OPEN), mContext.getOpPackageName());
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Cannot get NetworkStats session", e);
+ return null;
}
}
@@ -792,7 +953,7 @@ public class StatsPullAtomService extends SystemService {
}
private IProcessStats getIProcessStatsService() {
- synchronized (mProcessStatsLock) {
+ synchronized (mProcStatsLock) {
if (mProcessStatsService == null) {
mProcessStatsService = IProcessStats.Stub.asInterface(
ServiceManager.getService(ProcessStats.SERVICE_NAME));
@@ -800,7 +961,7 @@ public class StatsPullAtomService extends SystemService {
if (mProcessStatsService != null) {
try {
mProcessStatsService.asBinder().linkToDeath(() -> {
- synchronized (mProcessStatsLock) {
+ synchronized (mProcStatsLock) {
mProcessStatsService = null;
}
}, /* flags */ 0);
@@ -891,8 +1052,7 @@ public class StatsPullAtomService extends SystemService {
return ret;
}
- private int pullDataBytesTransfer(
- int atomTag, @NonNull List<StatsEvent> pulledData) {
+ private int pullDataBytesTransferLocked(int atomTag, @NonNull List<StatsEvent> pulledData) {
final List<NetworkStatsExt> current = collectNetworkStatsSnapshotForAtom(atomTag);
if (current == null) {
@@ -1032,7 +1192,13 @@ public class StatsPullAtomService extends SystemService {
final long bucketDuration = Settings.Global.getLong(mContext.getContentResolver(),
NETSTATS_UID_BUCKET_DURATION, NETSTATS_UID_DEFAULT_BUCKET_DURATION_MS);
try {
- final NetworkStats stats = getNetworkStatsSession().getSummaryForAllUid(template,
+ // TODO (b/156313635): This is short-term hack to allow perfd gets updated networkStats
+ // history when query in every second in order to show realtime statistics. However,
+ // this is not a good long-term solution since NetworkStatsService will make frequent
+ // I/O and also block main thread when polling.
+ // Consider making perfd queries NetworkStatsService directly.
+ final NetworkStats stats = getNetworkStatsSession(template.getMatchRule()
+ == NetworkTemplate.MATCH_WIFI_WILDCARD).getSummaryForAllUid(template,
currentTimeInMillis - elapsedMillisSinceBoot - bucketDuration,
currentTimeInMillis, includeTags);
return stats;
@@ -1240,12 +1406,11 @@ public class StatsPullAtomService extends SystemService {
return null;
}
- private synchronized BluetoothActivityEnergyInfo fetchBluetoothData() {
- // TODO: Investigate whether the synchronized keyword is needed.
+ private BluetoothActivityEnergyInfo fetchBluetoothData() {
final BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
if (adapter != null) {
- SynchronousResultReceiver bluetoothReceiver = new SynchronousResultReceiver(
- "bluetooth");
+ SynchronousResultReceiver bluetoothReceiver =
+ new SynchronousResultReceiver("bluetooth");
adapter.requestControllerActivityEnergyInfo(bluetoothReceiver);
return awaitControllerInfo(bluetoothReceiver);
} else {
@@ -1254,7 +1419,7 @@ public class StatsPullAtomService extends SystemService {
}
}
- int pullBluetoothBytesTransfer(int atomTag, List<StatsEvent> pulledData) {
+ int pullBluetoothBytesTransferLocked(int atomTag, List<StatsEvent> pulledData) {
BluetoothActivityEnergyInfo info = fetchBluetoothData();
if (info == null || info.getUidTraffic() == null) {
return StatsManager.PULL_SKIP;
@@ -1282,7 +1447,7 @@ public class StatsPullAtomService extends SystemService {
);
}
- int pullKernelWakelock(int atomTag, List<StatsEvent> pulledData) {
+ int pullKernelWakelockLocked(int atomTag, List<StatsEvent> pulledData) {
final KernelWakelockStats wakelockStats =
mKernelWakelockReader.readKernelWakelockStats(mTmpWakelockStats);
for (Map.Entry<String, KernelWakelockStats.Entry> ent : wakelockStats.entrySet()) {
@@ -1313,7 +1478,7 @@ public class StatsPullAtomService extends SystemService {
);
}
- int pullCpuTimePerFreq(int atomTag, List<StatsEvent> pulledData) {
+ int pullCpuTimePerFreqLocked(int atomTag, List<StatsEvent> pulledData) {
for (int cluster = 0; cluster < mKernelCpuSpeedReaders.length; cluster++) {
long[] clusterTimeMs = mKernelCpuSpeedReaders[cluster].readAbsolute();
if (clusterTimeMs != null) {
@@ -1344,7 +1509,7 @@ public class StatsPullAtomService extends SystemService {
);
}
- int pullCpuTimePerUid(int atomTag, List<StatsEvent> pulledData) {
+ int pullCpuTimePerUidLocked(int atomTag, List<StatsEvent> pulledData) {
mCpuUidUserSysTimeReader.readAbsolute((uid, timesUs) -> {
long userTimeUs = timesUs[0], systemTimeUs = timesUs[1];
StatsEvent e = StatsEvent.newBuilder()
@@ -1374,7 +1539,7 @@ public class StatsPullAtomService extends SystemService {
);
}
- int pullCpuTimeperUidFreq(int atomTag, List<StatsEvent> pulledData) {
+ int pullCpuTimePerUidFreqLocked(int atomTag, List<StatsEvent> pulledData) {
mCpuUidFreqTimeReader.readAbsolute((uid, cpuFreqTimeMs) -> {
for (int freqIndex = 0; freqIndex < cpuFreqTimeMs.length; ++freqIndex) {
if (cpuFreqTimeMs[freqIndex] != 0) {
@@ -1407,7 +1572,7 @@ public class StatsPullAtomService extends SystemService {
);
}
- int pullCpuActiveTime(int atomTag, List<StatsEvent> pulledData) {
+ int pullCpuActiveTimeLocked(int atomTag, List<StatsEvent> pulledData) {
mCpuUidActiveTimeReader.readAbsolute((uid, cpuActiveTimesMs) -> {
StatsEvent e = StatsEvent.newBuilder()
.setAtomId(atomTag)
@@ -1435,7 +1600,7 @@ public class StatsPullAtomService extends SystemService {
);
}
- int pullCpuClusterTime(int atomTag, List<StatsEvent> pulledData) {
+ int pullCpuClusterTimeLocked(int atomTag, List<StatsEvent> pulledData) {
mCpuUidClusterTimeReader.readAbsolute((uid, cpuClusterTimesMs) -> {
for (int i = 0; i < cpuClusterTimesMs.length; i++) {
StatsEvent e = StatsEvent.newBuilder()
@@ -1461,7 +1626,7 @@ public class StatsPullAtomService extends SystemService {
);
}
- int pullWifiActivityInfo(int atomTag, List<StatsEvent> pulledData) {
+ int pullWifiActivityInfoLocked(int atomTag, List<StatsEvent> pulledData) {
long token = Binder.clearCallingIdentity();
try {
SynchronousResultReceiver wifiReceiver = new SynchronousResultReceiver("wifi");
@@ -1513,7 +1678,7 @@ public class StatsPullAtomService extends SystemService {
);
}
- int pullModemActivityInfo(int atomTag, List<StatsEvent> pulledData) {
+ int pullModemActivityInfoLocked(int atomTag, List<StatsEvent> pulledData) {
long token = Binder.clearCallingIdentity();
try {
SynchronousResultReceiver modemReceiver = new SynchronousResultReceiver("telephony");
@@ -1551,7 +1716,7 @@ public class StatsPullAtomService extends SystemService {
);
}
- int pullBluetoothActivityInfo(int atomTag, List<StatsEvent> pulledData) {
+ int pullBluetoothActivityInfoLocked(int atomTag, List<StatsEvent> pulledData) {
BluetoothActivityEnergyInfo info = fetchBluetoothData();
if (info == null) {
return StatsManager.PULL_SKIP;
@@ -1583,7 +1748,7 @@ public class StatsPullAtomService extends SystemService {
);
}
- int pullSystemElapsedRealtime(int atomTag, List<StatsEvent> pulledData) {
+ int pullSystemElapsedRealtimeLocked(int atomTag, List<StatsEvent> pulledData) {
StatsEvent e = StatsEvent.newBuilder()
.setAtomId(atomTag)
.writeLong(SystemClock.elapsedRealtime())
@@ -1602,7 +1767,7 @@ public class StatsPullAtomService extends SystemService {
);
}
- int pullSystemUptime(int atomTag, List<StatsEvent> pulledData) {
+ int pullSystemUptimeLocked(int atomTag, List<StatsEvent> pulledData) {
StatsEvent e = StatsEvent.newBuilder()
.setAtomId(atomTag)
.writeLong(SystemClock.uptimeMillis())
@@ -1624,7 +1789,7 @@ public class StatsPullAtomService extends SystemService {
);
}
- int pullProcessMemoryState(int atomTag, List<StatsEvent> pulledData) {
+ int pullProcessMemoryStateLocked(int atomTag, List<StatsEvent> pulledData) {
List<ProcessMemoryState> processMemoryStates =
LocalServices.getService(ActivityManagerInternal.class)
.getMemoryStateForProcesses();
@@ -1668,7 +1833,7 @@ public class StatsPullAtomService extends SystemService {
);
}
- int pullProcessMemoryHighWaterMark(int atomTag, List<StatsEvent> pulledData) {
+ int pullProcessMemoryHighWaterMarkLocked(int atomTag, List<StatsEvent> pulledData) {
List<ProcessMemoryState> managedProcessList =
LocalServices.getService(ActivityManagerInternal.class)
.getMemoryStateForProcesses();
@@ -1723,7 +1888,7 @@ public class StatsPullAtomService extends SystemService {
);
}
- int pullProcessMemorySnapshot(int atomTag, List<StatsEvent> pulledData) {
+ int pullProcessMemorySnapshotLocked(int atomTag, List<StatsEvent> pulledData) {
List<ProcessMemoryState> managedProcessList =
LocalServices.getService(ActivityManagerInternal.class)
.getMemoryStateForProcesses();
@@ -1785,7 +1950,7 @@ public class StatsPullAtomService extends SystemService {
);
}
- int pullSystemIonHeapSize(int atomTag, List<StatsEvent> pulledData) {
+ int pullSystemIonHeapSizeLocked(int atomTag, List<StatsEvent> pulledData) {
final long systemIonHeapSizeInBytes = readSystemIonHeapSizeFromDebugfs();
StatsEvent e = StatsEvent.newBuilder()
.setAtomId(atomTag)
@@ -1808,7 +1973,7 @@ public class StatsPullAtomService extends SystemService {
);
}
- int pullIonHeapSize(int atomTag, List<StatsEvent> pulledData) {
+ int pullIonHeapSizeLocked(int atomTag, List<StatsEvent> pulledData) {
int ionHeapSizeInKilobytes = (int) getIonHeapsSizeKb();
StatsEvent e = StatsEvent.newBuilder()
.setAtomId(atomTag)
@@ -1828,7 +1993,7 @@ public class StatsPullAtomService extends SystemService {
);
}
- int pullProcessSystemIonHeapSize(int atomTag, List<StatsEvent> pulledData) {
+ int pullProcessSystemIonHeapSizeLocked(int atomTag, List<StatsEvent> pulledData) {
List<IonAllocations> result = readProcessSystemIonHeapSizesFromDebugfs();
for (IonAllocations allocations : result) {
StatsEvent e = StatsEvent.newBuilder()
@@ -1855,7 +2020,7 @@ public class StatsPullAtomService extends SystemService {
);
}
- int pullTemperature(int atomTag, List<StatsEvent> pulledData) {
+ int pullTemperatureLocked(int atomTag, List<StatsEvent> pulledData) {
IThermalService thermalService = getIThermalService();
if (thermalService == null) {
return StatsManager.PULL_SKIP;
@@ -1893,7 +2058,7 @@ public class StatsPullAtomService extends SystemService {
);
}
- int pullCooldownDevice(int atomTag, List<StatsEvent> pulledData) {
+ int pullCooldownDeviceLocked(int atomTag, List<StatsEvent> pulledData) {
IThermalService thermalService = getIThermalService();
if (thermalService == null) {
return StatsManager.PULL_SKIP;
@@ -1933,7 +2098,7 @@ public class StatsPullAtomService extends SystemService {
);
}
- int pullBinderCallsStats(int atomTag, List<StatsEvent> pulledData) {
+ int pullBinderCallsStatsLocked(int atomTag, List<StatsEvent> pulledData) {
BinderCallsStatsService.Internal binderStats =
LocalServices.getService(BinderCallsStatsService.Internal.class);
if (binderStats == null) {
@@ -1977,7 +2142,7 @@ public class StatsPullAtomService extends SystemService {
);
}
- int pullBinderCallsStatsExceptions(int atomTag, List<StatsEvent> pulledData) {
+ int pullBinderCallsStatsExceptionsLocked(int atomTag, List<StatsEvent> pulledData) {
BinderCallsStatsService.Internal binderStats =
LocalServices.getService(BinderCallsStatsService.Internal.class);
if (binderStats == null) {
@@ -2012,7 +2177,7 @@ public class StatsPullAtomService extends SystemService {
);
}
- int pullLooperStats(int atomTag, List<StatsEvent> pulledData) {
+ int pullLooperStatsLocked(int atomTag, List<StatsEvent> pulledData) {
LooperStats looperStats = LocalServices.getService(LooperStats.class);
if (looperStats == null) {
return StatsManager.PULL_SKIP;
@@ -2055,7 +2220,7 @@ public class StatsPullAtomService extends SystemService {
);
}
- int pullDiskStats(int atomTag, List<StatsEvent> pulledData) {
+ int pullDiskStatsLocked(int atomTag, List<StatsEvent> pulledData) {
// Run a quick-and-dirty performance test: write 512 bytes
byte[] junk = new byte[512];
for (int i = 0; i < junk.length; i++) junk[i] = (byte) i; // Write nonzero bytes
@@ -2121,7 +2286,7 @@ public class StatsPullAtomService extends SystemService {
);
}
- int pullDirectoryUsage(int atomTag, List<StatsEvent> pulledData) {
+ int pullDirectoryUsageLocked(int atomTag, List<StatsEvent> pulledData) {
StatFs statFsData = new StatFs(Environment.getDataDirectory().getAbsolutePath());
StatFs statFsSystem = new StatFs(Environment.getRootDirectory().getAbsolutePath());
StatFs statFsCache = new StatFs(Environment.getDownloadCacheDirectory().getAbsolutePath());
@@ -2162,7 +2327,7 @@ public class StatsPullAtomService extends SystemService {
);
}
- int pullAppSize(int atomTag, List<StatsEvent> pulledData) {
+ int pullAppSizeLocked(int atomTag, List<StatsEvent> pulledData) {
try {
String jsonStr = IoUtils.readFileAsString(DiskStatsLoggingService.DUMPSYS_CACHE_PATH);
JSONObject json = new JSONObject(jsonStr);
@@ -2190,7 +2355,7 @@ public class StatsPullAtomService extends SystemService {
pulledData.add(e);
}
} catch (IOException | JSONException e) {
- Slog.e(TAG, "exception reading diskstats cache file", e);
+ Slog.w(TAG, "Unable to read diskstats cache file within pullAppSize");
return StatsManager.PULL_SKIP;
}
return StatsManager.PULL_SUCCESS;
@@ -2206,7 +2371,7 @@ public class StatsPullAtomService extends SystemService {
);
}
- int pullCategorySize(int atomTag, List<StatsEvent> pulledData) {
+ int pullCategorySizeLocked(int atomTag, List<StatsEvent> pulledData) {
try {
String jsonStr = IoUtils.readFileAsString(DiskStatsLoggingService.DUMPSYS_CACHE_PATH);
JSONObject json = new JSONObject(jsonStr);
@@ -2294,7 +2459,7 @@ public class StatsPullAtomService extends SystemService {
.build();
pulledData.add(e);
} catch (IOException | JSONException e) {
- Slog.e(TAG, "exception reading diskstats cache file", e);
+ Slog.w(TAG, "Unable to read diskstats cache file within pullCategorySize");
return StatsManager.PULL_SKIP;
}
return StatsManager.PULL_SUCCESS;
@@ -2320,7 +2485,8 @@ public class StatsPullAtomService extends SystemService {
);
}
- private int pullNumBiometricsEnrolled(int modality, int atomTag, List<StatsEvent> pulledData) {
+ private int pullNumBiometricsEnrolledLocked(int modality, int atomTag,
+ List<StatsEvent> pulledData) {
final PackageManager pm = mContext.getPackageManager();
FingerprintManager fingerprintManager = null;
FaceManager faceManager = null;
@@ -2388,43 +2554,41 @@ public class StatsPullAtomService extends SystemService {
);
}
- private int pullProcStats(int section, int atomTag, List<StatsEvent> pulledData) {
+ private int pullProcStatsLocked(int section, int atomTag, List<StatsEvent> pulledData) {
IProcessStats processStatsService = getIProcessStatsService();
if (processStatsService == null) {
return StatsManager.PULL_SKIP;
}
- synchronized (mProcessStatsLock) {
- final long token = Binder.clearCallingIdentity();
- try {
- // force procstats to flush & combine old files into one store
- long lastHighWaterMark = readProcStatsHighWaterMark(section);
- List<ParcelFileDescriptor> statsFiles = new ArrayList<>();
+ final long token = Binder.clearCallingIdentity();
+ try {
+ // force procstats to flush & combine old files into one store
+ long lastHighWaterMark = readProcStatsHighWaterMark(section);
+ List<ParcelFileDescriptor> statsFiles = new ArrayList<>();
- ProcessStats procStats = new ProcessStats(false);
- long highWaterMark = processStatsService.getCommittedStatsMerged(
- lastHighWaterMark, section, true, statsFiles, procStats);
+ ProcessStats procStats = new ProcessStats(false);
+ long highWaterMark = processStatsService.getCommittedStatsMerged(
+ lastHighWaterMark, section, true, statsFiles, procStats);
- // aggregate the data together for westworld consumption
- ProtoOutputStream proto = new ProtoOutputStream();
- procStats.dumpAggregatedProtoForStatsd(proto);
+ // aggregate the data together for westworld consumption
+ ProtoOutputStream proto = new ProtoOutputStream();
+ procStats.dumpAggregatedProtoForStatsd(proto);
- StatsEvent e = StatsEvent.newBuilder()
- .setAtomId(atomTag)
- .writeByteArray(proto.getBytes())
- .build();
- pulledData.add(e);
+ StatsEvent e = StatsEvent.newBuilder()
+ .setAtomId(atomTag)
+ .writeByteArray(proto.getBytes())
+ .build();
+ pulledData.add(e);
- new File(mBaseDir.getAbsolutePath() + "/" + section + "_" + lastHighWaterMark)
- .delete();
- new File(mBaseDir.getAbsolutePath() + "/" + section + "_" + highWaterMark)
- .createNewFile();
- } catch (RemoteException | IOException e) {
- Slog.e(TAG, "Getting procstats failed: ", e);
- return StatsManager.PULL_SKIP;
- } finally {
- Binder.restoreCallingIdentity(token);
- }
+ new File(mBaseDir.getAbsolutePath() + "/" + section + "_" + lastHighWaterMark)
+ .delete();
+ new File(mBaseDir.getAbsolutePath() + "/" + section + "_" + highWaterMark)
+ .createNewFile();
+ } catch (RemoteException | IOException e) {
+ Slog.e(TAG, "Getting procstats failed: ", e);
+ return StatsManager.PULL_SKIP;
+ } finally {
+ Binder.restoreCallingIdentity(token);
}
return StatsManager.PULL_SUCCESS;
}
@@ -2464,7 +2628,7 @@ public class StatsPullAtomService extends SystemService {
);
}
- int pullDiskIO(int atomTag, List<StatsEvent> pulledData) {
+ int pullDiskIOLocked(int atomTag, List<StatsEvent> pulledData) {
mStoragedUidIoStatsReader.readAbsolute((uid, fgCharsRead, fgCharsWrite, fgBytesRead,
fgBytesWrite, bgCharsRead, bgCharsWrite, bgBytesRead, bgBytesWrite,
fgFsync, bgFsync) -> {
@@ -2498,7 +2662,7 @@ public class StatsPullAtomService extends SystemService {
);
}
- int pullPowerProfile(int atomTag, List<StatsEvent> pulledData) {
+ int pullPowerProfileLocked(int atomTag, List<StatsEvent> pulledData) {
PowerProfile powerProfile = new PowerProfile(mContext);
ProtoOutputStream proto = new ProtoOutputStream();
powerProfile.dumpDebug(proto);
@@ -2525,25 +2689,23 @@ public class StatsPullAtomService extends SystemService {
);
}
- int pullProcessCpuTime(int atomTag, List<StatsEvent> pulledData) {
- synchronized (mCpuTrackerLock) {
- if (mProcessCpuTracker == null) {
- mProcessCpuTracker = new ProcessCpuTracker(false);
- mProcessCpuTracker.init();
- }
- mProcessCpuTracker.update();
- for (int i = 0; i < mProcessCpuTracker.countStats(); i++) {
- ProcessCpuTracker.Stats st = mProcessCpuTracker.getStats(i);
- StatsEvent e = StatsEvent.newBuilder()
- .setAtomId(atomTag)
- .writeInt(st.uid)
- .addBooleanAnnotation(ANNOTATION_ID_IS_UID, true)
- .writeString(st.name)
- .writeLong(st.base_utime)
- .writeLong(st.base_stime)
- .build();
- pulledData.add(e);
- }
+ int pullProcessCpuTimeLocked(int atomTag, List<StatsEvent> pulledData) {
+ if (mProcessCpuTracker == null) {
+ mProcessCpuTracker = new ProcessCpuTracker(false);
+ mProcessCpuTracker.init();
+ }
+ mProcessCpuTracker.update();
+ for (int i = 0; i < mProcessCpuTracker.countStats(); i++) {
+ ProcessCpuTracker.Stats st = mProcessCpuTracker.getStats(i);
+ StatsEvent e = StatsEvent.newBuilder()
+ .setAtomId(atomTag)
+ .writeInt(st.uid)
+ .addBooleanAnnotation(ANNOTATION_ID_IS_UID, true)
+ .writeString(st.name)
+ .writeLong(st.base_utime)
+ .writeLong(st.base_stime)
+ .build();
+ pulledData.add(e);
}
return StatsManager.PULL_SUCCESS;
}
@@ -2561,7 +2723,7 @@ public class StatsPullAtomService extends SystemService {
);
}
- int pullCpuTimePerThreadFreq(int atomTag, List<StatsEvent> pulledData) {
+ int pullCpuTimePerThreadFreqLocked(int atomTag, List<StatsEvent> pulledData) {
if (this.mKernelCpuThreadReader == null) {
Slog.e(TAG, "mKernelCpuThreadReader is null");
return StatsManager.PULL_SKIP;
@@ -2620,23 +2782,27 @@ public class StatsPullAtomService extends SystemService {
}
private BatteryStatsHelper getBatteryStatsHelper() {
- if (mBatteryStatsHelper == null) {
- final long callingToken = Binder.clearCallingIdentity();
- try {
- // clearCallingIdentity required for BatteryStatsHelper.checkWifiOnly().
- mBatteryStatsHelper = new BatteryStatsHelper(mContext, false);
- } finally {
- Binder.restoreCallingIdentity(callingToken);
+ synchronized (mBatteryStatsHelperLock) {
+ if (mBatteryStatsHelper == null) {
+ final long callingToken = Binder.clearCallingIdentity();
+ try {
+ // clearCallingIdentity required for BatteryStatsHelper.checkWifiOnly().
+ mBatteryStatsHelper = new BatteryStatsHelper(mContext, false);
+ } finally {
+ Binder.restoreCallingIdentity(callingToken);
+ }
+ mBatteryStatsHelper.create((Bundle) null);
+ }
+ long currentTime = SystemClock.elapsedRealtime();
+ if (currentTime - mBatteryStatsHelperTimestampMs
+ >= MAX_BATTERY_STATS_HELPER_FREQUENCY_MS) {
+ // Load BatteryStats and do all the calculations.
+ mBatteryStatsHelper.refreshStats(BatteryStats.STATS_SINCE_CHARGED,
+ UserHandle.USER_ALL);
+ // Calculations are done so we don't need to save the raw BatteryStats data in RAM.
+ mBatteryStatsHelper.clearStats();
+ mBatteryStatsHelperTimestampMs = currentTime;
}
- mBatteryStatsHelper.create((Bundle) null);
- }
- long currentTime = SystemClock.elapsedRealtime();
- if (currentTime - mBatteryStatsHelperTimestampMs >= MAX_BATTERY_STATS_HELPER_FREQUENCY_MS) {
- // Load BatteryStats and do all the calculations.
- mBatteryStatsHelper.refreshStats(BatteryStats.STATS_SINCE_CHARGED, UserHandle.USER_ALL);
- // Calculations are done so we don't need to save the raw BatteryStats data in RAM.
- mBatteryStatsHelper.clearStats();
- mBatteryStatsHelperTimestampMs = currentTime;
}
return mBatteryStatsHelper;
}
@@ -2655,7 +2821,7 @@ public class StatsPullAtomService extends SystemService {
);
}
- int pullDeviceCalculatedPowerUse(int atomTag, List<StatsEvent> pulledData) {
+ int pullDeviceCalculatedPowerUseLocked(int atomTag, List<StatsEvent> pulledData) {
BatteryStatsHelper bsHelper = getBatteryStatsHelper();
StatsEvent e = StatsEvent.newBuilder()
.setAtomId(atomTag)
@@ -2675,7 +2841,7 @@ public class StatsPullAtomService extends SystemService {
);
}
- int pullDeviceCalculatedPowerBlameUid(int atomTag, List<StatsEvent> pulledData) {
+ int pullDeviceCalculatedPowerBlameUidLocked(int atomTag, List<StatsEvent> pulledData) {
final List<BatterySipper> sippers = getBatteryStatsHelper().getUsageList();
if (sippers == null) {
return StatsManager.PULL_SKIP;
@@ -2706,7 +2872,7 @@ public class StatsPullAtomService extends SystemService {
);
}
- int pullDeviceCalculatedPowerBlameOther(int atomTag, List<StatsEvent> pulledData) {
+ int pullDeviceCalculatedPowerBlameOtherLocked(int atomTag, List<StatsEvent> pulledData) {
final List<BatterySipper> sippers = getBatteryStatsHelper().getUsageList();
if (sippers == null) {
return StatsManager.PULL_SKIP;
@@ -2742,41 +2908,37 @@ public class StatsPullAtomService extends SystemService {
);
}
- int pullDebugElapsedClock(int atomTag, List<StatsEvent> pulledData) {
+ int pullDebugElapsedClockLocked(int atomTag, List<StatsEvent> pulledData) {
final long elapsedMillis = SystemClock.elapsedRealtime();
+ final long clockDiffMillis = mDebugElapsedClockPreviousValue == 0
+ ? 0 : elapsedMillis - mDebugElapsedClockPreviousValue;
- synchronized (mDebugElapsedClockLock) {
- final long clockDiffMillis = mDebugElapsedClockPreviousValue == 0
- ? 0 : elapsedMillis - mDebugElapsedClockPreviousValue;
+ StatsEvent e = StatsEvent.newBuilder()
+ .setAtomId(atomTag)
+ .writeLong(mDebugElapsedClockPullCount)
+ .writeLong(elapsedMillis)
+ // Log it twice to be able to test multi-value aggregation from ValueMetric.
+ .writeLong(elapsedMillis)
+ .writeLong(clockDiffMillis)
+ .writeInt(1 /* always set */)
+ .build();
+ pulledData.add(e);
- StatsEvent e = StatsEvent.newBuilder()
+ if (mDebugElapsedClockPullCount % 2 == 1) {
+ StatsEvent e2 = StatsEvent.newBuilder()
.setAtomId(atomTag)
.writeLong(mDebugElapsedClockPullCount)
.writeLong(elapsedMillis)
// Log it twice to be able to test multi-value aggregation from ValueMetric.
.writeLong(elapsedMillis)
.writeLong(clockDiffMillis)
- .writeInt(1 /* always set */)
+ .writeInt(2 /* set on odd pulls */)
.build();
- pulledData.add(e);
-
- if (mDebugElapsedClockPullCount % 2 == 1) {
- StatsEvent e2 = StatsEvent.newBuilder()
- .setAtomId(atomTag)
- .writeLong(mDebugElapsedClockPullCount)
- .writeLong(elapsedMillis)
- // Log it twice to be able to test multi-value aggregation from ValueMetric.
- .writeLong(elapsedMillis)
- .writeLong(clockDiffMillis)
- .writeInt(2 /* set on odd pulls */)
- .build();
- pulledData.add(e2);
- }
-
- mDebugElapsedClockPullCount++;
- mDebugElapsedClockPreviousValue = elapsedMillis;
+ pulledData.add(e2);
}
+ mDebugElapsedClockPullCount++;
+ mDebugElapsedClockPreviousValue = elapsedMillis;
return StatsManager.PULL_SUCCESS;
}
@@ -2793,31 +2955,27 @@ public class StatsPullAtomService extends SystemService {
);
}
- int pullDebugFailingElapsedClock(int atomTag, List<StatsEvent> pulledData) {
+ int pullDebugFailingElapsedClockLocked(int atomTag, List<StatsEvent> pulledData) {
final long elapsedMillis = SystemClock.elapsedRealtime();
-
- synchronized (mDebugFailingElapsedClockLock) {
- // Fails every 5 buckets.
- if (mDebugFailingElapsedClockPullCount++ % 5 == 0) {
- mDebugFailingElapsedClockPreviousValue = elapsedMillis;
- Slog.e(TAG, "Failing debug elapsed clock");
- return StatsManager.PULL_SKIP;
- }
-
- StatsEvent e = StatsEvent.newBuilder()
- .setAtomId(atomTag)
- .writeLong(mDebugFailingElapsedClockPullCount)
- .writeLong(elapsedMillis)
- // Log it twice to be able to test multi-value aggregation from ValueMetric.
- .writeLong(elapsedMillis)
- .writeLong(mDebugFailingElapsedClockPreviousValue == 0
- ? 0 : elapsedMillis - mDebugFailingElapsedClockPreviousValue)
- .build();
- pulledData.add(e);
-
+ // Fails every 5 buckets.
+ if (mDebugFailingElapsedClockPullCount++ % 5 == 0) {
mDebugFailingElapsedClockPreviousValue = elapsedMillis;
+ Slog.e(TAG, "Failing debug elapsed clock");
+ return StatsManager.PULL_SKIP;
}
+ StatsEvent e = StatsEvent.newBuilder()
+ .setAtomId(atomTag)
+ .writeLong(mDebugFailingElapsedClockPullCount)
+ .writeLong(elapsedMillis)
+ // Log it twice to be able to test multi-value aggregation from ValueMetric.
+ .writeLong(elapsedMillis)
+ .writeLong(mDebugFailingElapsedClockPreviousValue == 0
+ ? 0 : elapsedMillis - mDebugFailingElapsedClockPreviousValue)
+ .build();
+ pulledData.add(e);
+
+ mDebugFailingElapsedClockPreviousValue = elapsedMillis;
return StatsManager.PULL_SUCCESS;
}
@@ -2831,7 +2989,7 @@ public class StatsPullAtomService extends SystemService {
);
}
- int pullBuildInformation(int atomTag, List<StatsEvent> pulledData) {
+ int pullBuildInformationLocked(int atomTag, List<StatsEvent> pulledData) {
StatsEvent e = StatsEvent.newBuilder()
.setAtomId(atomTag)
.writeString(Build.FINGERPRINT)
@@ -2859,7 +3017,7 @@ public class StatsPullAtomService extends SystemService {
}
// Add a RoleHolder atom for each package that holds a role.
- int pullRoleHolder(int atomTag, List<StatsEvent> pulledData) {
+ int pullRoleHolderLocked(int atomTag, List<StatsEvent> pulledData) {
long callingToken = Binder.clearCallingIdentity();
try {
PackageManager pm = mContext.getPackageManager();
@@ -2917,7 +3075,7 @@ public class StatsPullAtomService extends SystemService {
);
}
- int pullDangerousPermissionState(int atomTag, List<StatsEvent> pulledData) {
+ int pullDangerousPermissionStateLocked(int atomTag, List<StatsEvent> pulledData) {
final long token = Binder.clearCallingIdentity();
float samplingRate = DeviceConfig.getFloat(DeviceConfig.NAMESPACE_PERMISSIONS,
DANGEROUS_PERMISSION_STATE_SAMPLE_RATE, 0.02f);
@@ -3010,7 +3168,7 @@ public class StatsPullAtomService extends SystemService {
);
}
- int pullTimeZoneDataInfo(int atomTag, List<StatsEvent> pulledData) {
+ int pullTimeZoneDataInfoLocked(int atomTag, List<StatsEvent> pulledData) {
String tzDbVersion = "Unknown";
try {
tzDbVersion = android.icu.util.TimeZone.getTZDataVersion();
@@ -3037,7 +3195,7 @@ public class StatsPullAtomService extends SystemService {
);
}
- int pullExternalStorageInfo(int atomTag, List<StatsEvent> pulledData) {
+ int pullExternalStorageInfoLocked(int atomTag, List<StatsEvent> pulledData) {
if (mStorageManager == null) {
return StatsManager.PULL_SKIP;
}
@@ -3087,7 +3245,7 @@ public class StatsPullAtomService extends SystemService {
);
}
- int pullAppsOnExternalStorageInfo(int atomTag, List<StatsEvent> pulledData) {
+ int pullAppsOnExternalStorageInfoLocked(int atomTag, List<StatsEvent> pulledData) {
if (mStorageManager == null) {
return StatsManager.PULL_SKIP;
}
@@ -3143,7 +3301,7 @@ public class StatsPullAtomService extends SystemService {
);
}
- int pullFaceSettings(int atomTag, List<StatsEvent> pulledData) {
+ int pullFaceSettingsLocked(int atomTag, List<StatsEvent> pulledData) {
final long callingToken = Binder.clearCallingIdentity();
try {
List<UserInfo> users = mContext.getSystemService(UserManager.class).getUsers();
@@ -3225,7 +3383,7 @@ public class StatsPullAtomService extends SystemService {
}
}
- int pullAppOps(int atomTag, List<StatsEvent> pulledData) {
+ int pullAppOpsLocked(int atomTag, List<StatsEvent> pulledData) {
final long token = Binder.clearCallingIdentity();
try {
AppOpsManager appOps = mContext.getSystemService(AppOpsManager.class);
@@ -3302,7 +3460,7 @@ public class StatsPullAtomService extends SystemService {
);
}
- int pullAttributedAppOps(int atomTag, List<StatsEvent> pulledData) {
+ int pullAttributedAppOpsLocked(int atomTag, List<StatsEvent> pulledData) {
final long token = Binder.clearCallingIdentity();
try {
AppOpsManager appOps = mContext.getSystemService(AppOpsManager.class);
@@ -3322,8 +3480,8 @@ public class StatsPullAtomService extends SystemService {
public void run() {
try {
estimateAppOpsSamplingRate();
- } catch (Exception e) {
- Slog.e(TAG, "AppOps sampling ratio estimation failed");
+ } catch (Throwable e) {
+ Slog.e(TAG, "AppOps sampling ratio estimation failed: ", e);
synchronized (mAppOpsSamplingRateLock) {
mAppOpsSamplingRate = min(mAppOpsSamplingRate, 10);
}
@@ -3361,10 +3519,10 @@ public class StatsPullAtomService extends SystemService {
CompletableFuture<HistoricalOps> ops = new CompletableFuture<>();
HistoricalOpsRequest histOpsRequest =
new HistoricalOpsRequest.Builder(
- Instant.now().minus(1, ChronoUnit.DAYS).toEpochMilli(),
+ Math.max(Instant.now().minus(1, ChronoUnit.DAYS).toEpochMilli(), 0),
Long.MAX_VALUE).setFlags(
OP_FLAGS_PULLED).build();
- appOps.getHistoricalOps(histOpsRequest, mContext.getMainExecutor(), ops::complete);
+ appOps.getHistoricalOps(histOpsRequest, AsyncTask.THREAD_POOL_EXECUTOR, ops::complete);
HistoricalOps histOps = ops.get(EXTERNAL_STATS_SYNC_TIMEOUT_MILLIS,
TimeUnit.MILLISECONDS);
List<AppOpEntry> opsList =
@@ -3380,7 +3538,9 @@ public class StatsPullAtomService extends SystemService {
}
int estimatedSamplingRate = (int) constrain(
appOpsTargetCollectionSize * 100 / estimatedSize, 0, 100);
- mAppOpsSamplingRate = min(mAppOpsSamplingRate, estimatedSamplingRate);
+ synchronized (mAppOpsSamplingRateLock) {
+ mAppOpsSamplingRate = min(mAppOpsSamplingRate, estimatedSamplingRate);
+ }
}
private List<AppOpEntry> processHistoricalOps(
@@ -3423,7 +3583,7 @@ public class StatsPullAtomService extends SystemService {
}
}
- int pullRuntimeAppOpAccessMessage(int atomTag, List<StatsEvent> pulledData) {
+ int pullRuntimeAppOpAccessMessageLocked(int atomTag, List<StatsEvent> pulledData) {
final long token = Binder.clearCallingIdentity();
try {
AppOpsManager appOps = mContext.getSystemService(AppOpsManager.class);
@@ -3510,7 +3670,7 @@ public class StatsPullAtomService extends SystemService {
);
}
- int pullNotificationRemoteViews(int atomTag, List<StatsEvent> pulledData) {
+ int pullNotificationRemoteViewsLocked(int atomTag, List<StatsEvent> pulledData) {
INotificationManager notificationManagerService = getINotificationManagerService();
if (notificationManagerService == null) {
return StatsManager.PULL_SKIP;
@@ -3604,7 +3764,7 @@ public class StatsPullAtomService extends SystemService {
);
}
- int pullHealthHal(int atomTag, List<StatsEvent> pulledData) {
+ int pullHealthHalLocked(int atomTag, List<StatsEvent> pulledData) {
IHealth healthService = mHealthService.getLastService();
if (healthService == null) {
return StatsManager.PULL_SKIP;
@@ -3654,7 +3814,7 @@ public class StatsPullAtomService extends SystemService {
);
}
- int pullSettingsStats(int atomTag, List<StatsEvent> pulledData) {
+ int pullSettingsStatsLocked(int atomTag, List<StatsEvent> pulledData) {
UserManager userManager = mContext.getSystemService(UserManager.class);
if (userManager == null) {
return StatsManager.PULL_SKIP;
@@ -3681,21 +3841,6 @@ public class StatsPullAtomService extends SystemService {
return StatsManager.PULL_SUCCESS;
}
- private void registerDisplayWakeStats() {
- int tagId = FrameworkStatsLog.DISPLAY_WAKE_REASON;
- mStatsManager.setPullAtomCallback(
- tagId,
- null, // use default PullAtomMetadata values
- DIRECT_EXECUTOR,
- mStatsCallbackImpl
- );
- }
-
- int pullDisplayWakeStats(int atomTag, List<StatsEvent> pulledData) {
- //TODO: Denny, implement read/write DisplayWakeStats, b/154172964
- return 0;
- }
-
// Thermal event received from vendor thermal management subsystem
private static final class ThermalEventListener extends IThermalEventListener.Stub {
@Override
@@ -3752,11 +3897,13 @@ public class StatsPullAtomService extends SystemService {
final SubInfo subInfo = new SubInfo(subId, sub.getCarrierId(), mcc, mnc,
subscriberId, sub.isOpportunistic());
Slog.i(TAG, "subId " + subId + " added into historical sub list");
- mHistoricalSubs.add(subInfo);
- // Since getting snapshot when pulling will also include data before boot,
- // query stats as baseline to prevent double count is needed.
- mNetworkStatsBaselines.addAll(getDataUsageBytesTransferSnapshotForSub(subInfo));
+ synchronized (mDataBytesTransferLock) {
+ mHistoricalSubs.add(subInfo);
+ // Since getting snapshot when pulling will also include data before boot,
+ // query stats as baseline to prevent double count is needed.
+ mNetworkStatsBaselines.addAll(getDataUsageBytesTransferSnapshotForSub(subInfo));
+ }
}
}
}
diff --git a/services/core/java/com/android/server/storage/StorageUserConnection.java b/services/core/java/com/android/server/storage/StorageUserConnection.java
index c18a6ebc32ef..94a250236200 100644
--- a/services/core/java/com/android/server/storage/StorageUserConnection.java
+++ b/services/core/java/com/android/server/storage/StorageUserConnection.java
@@ -413,20 +413,18 @@ public final class StorageUserConnection {
resetUserSessions();
}
};
- }
- Slog.i(TAG, "Binding to the ExternalStorageService for user " + mUserId);
- if (mContext.bindServiceAsUser(new Intent().setComponent(name), mServiceConnection,
- Context.BIND_AUTO_CREATE | Context.BIND_IMPORTANT,
- UserHandle.of(mUserId))) {
- Slog.i(TAG, "Bound to the ExternalStorageService for user " + mUserId);
- return mLatch;
- } else {
- synchronized (mLock) {
+ Slog.i(TAG, "Binding to the ExternalStorageService for user " + mUserId);
+ if (mContext.bindServiceAsUser(new Intent().setComponent(name), mServiceConnection,
+ Context.BIND_AUTO_CREATE | Context.BIND_IMPORTANT,
+ UserHandle.of(mUserId))) {
+ Slog.i(TAG, "Bound to the ExternalStorageService for user " + mUserId);
+ return mLatch;
+ } else {
mIsConnecting = false;
+ throw new ExternalStorageServiceException(
+ "Failed to bind to the ExternalStorageService for user " + mUserId);
}
- throw new ExternalStorageServiceException(
- "Failed to bind to the ExternalStorageService for user " + mUserId);
}
}
}
diff --git a/services/core/java/com/android/server/textclassifier/FixedSizeQueue.java b/services/core/java/com/android/server/textclassifier/FixedSizeQueue.java
new file mode 100644
index 000000000000..edb258db88c8
--- /dev/null
+++ b/services/core/java/com/android/server/textclassifier/FixedSizeQueue.java
@@ -0,0 +1,103 @@
+/*
+ * 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.server.textclassifier;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.util.Preconditions;
+
+import java.util.ArrayDeque;
+import java.util.Objects;
+import java.util.Queue;
+
+/**
+ * A fixed-size queue which automatically evicts the oldest element from the queue when it is full.
+ *
+ * <p>This class does not accept null element.
+ *
+ * @param <E> the type of elements held in this queue
+ */
+@VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
+public final class FixedSizeQueue<E> {
+
+ private final Queue<E> mDelegate;
+
+ @Nullable
+ private final OnEntryEvictedListener<E> mOnEntryEvictedListener;
+
+ private final int mMaxSize;
+
+ public FixedSizeQueue(int maxSize, @Nullable OnEntryEvictedListener<E> onEntryEvictedListener) {
+ Preconditions.checkArgument(maxSize > 0, "maxSize (%s) must > 0", maxSize);
+ mDelegate = new ArrayDeque<>(maxSize);
+ mMaxSize = maxSize;
+ mOnEntryEvictedListener = onEntryEvictedListener;
+ }
+
+ /** Returns the number of items in the queue. */
+ public int size() {
+ return mDelegate.size();
+ }
+
+ /** Adds an element to the queue, evicts the oldest element if it reaches its max capacity. */
+ public boolean add(@NonNull E element) {
+ Objects.requireNonNull(element);
+ if (size() == mMaxSize) {
+ E removed = mDelegate.remove();
+ if (mOnEntryEvictedListener != null) {
+ mOnEntryEvictedListener.onEntryEvicted(removed);
+ }
+ }
+ mDelegate.add(element);
+ return true;
+ }
+
+ /**
+ * Returns and removes the head of the queue, or returns null if this queue is empty.
+ */
+ @Nullable
+ public E poll() {
+ return mDelegate.poll();
+ }
+
+ /**
+ * Removes an element from the queue, returns a boolean to indicate if an element is removed.
+ */
+ public boolean remove(@NonNull E element) {
+ Objects.requireNonNull(element);
+ return mDelegate.remove(element);
+ }
+
+ /** Returns whether the queue is empty. */
+ public boolean isEmpty() {
+ return mDelegate.isEmpty();
+ }
+
+ /**
+ * A listener to get notified when an element is evicted.
+ *
+ * @param <E> the type of element
+ */
+ public interface OnEntryEvictedListener<E> {
+ /**
+ * Notifies that an element is evicted because the queue is reaching its max capacity.
+ */
+ void onEntryEvicted(@NonNull E element);
+ }
+}
diff --git a/services/core/java/com/android/server/textclassifier/TEST_MAPPING b/services/core/java/com/android/server/textclassifier/TEST_MAPPING
new file mode 100644
index 000000000000..ccf26315852d
--- /dev/null
+++ b/services/core/java/com/android/server/textclassifier/TEST_MAPPING
@@ -0,0 +1,7 @@
+{
+ "imports": [
+ {
+ "path": "frameworks/base/core/java/android/view/textclassifier"
+ }
+ ]
+}
diff --git a/services/core/java/com/android/server/textclassifier/TextClassificationManagerService.java b/services/core/java/com/android/server/textclassifier/TextClassificationManagerService.java
index cd65c6c3ceb1..1707d9542813 100644
--- a/services/core/java/com/android/server/textclassifier/TextClassificationManagerService.java
+++ b/services/core/java/com/android/server/textclassifier/TextClassificationManagerService.java
@@ -41,6 +41,7 @@ import android.service.textclassifier.TextClassifierService;
import android.service.textclassifier.TextClassifierService.ConnectionState;
import android.text.TextUtils;
import android.util.ArrayMap;
+import android.util.LruCache;
import android.util.Slog;
import android.util.SparseArray;
import android.view.textclassifier.ConversationAction;
@@ -68,12 +69,10 @@ import com.android.server.SystemService;
import java.io.FileDescriptor;
import java.io.PrintWriter;
-import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Objects;
-import java.util.Queue;
/**
* A manager for TextClassifier services.
@@ -308,13 +307,15 @@ public final class TextClassificationManagerService extends ITextClassifierServi
Objects.requireNonNull(classificationContext);
Objects.requireNonNull(classificationContext.getSystemTextClassifierMetadata());
+ synchronized (mLock) {
+ mSessionCache.put(sessionId, classificationContext);
+ }
handleRequest(
classificationContext.getSystemTextClassifierMetadata(),
/* verifyCallingPackage= */ true,
/* attemptToBind= */ false,
service -> {
service.onCreateTextClassificationSession(classificationContext, sessionId);
- mSessionCache.put(sessionId, classificationContext);
},
"onCreateTextClassificationSession",
NO_OP_CALLBACK);
@@ -588,12 +589,14 @@ public final class TextClassificationManagerService extends ITextClassifierServi
* are cleaned up automatically when the client process is dead.
*/
static final class SessionCache {
+ private static final int MAX_CACHE_SIZE = 100;
+
@NonNull
private final Object mLock;
@NonNull
@GuardedBy("mLock")
- private final Map<TextClassificationSessionId, StrippedTextClassificationContext> mCache =
- new ArrayMap<>();
+ private final LruCache<TextClassificationSessionId, StrippedTextClassificationContext>
+ mCache = new LruCache<>(MAX_CACHE_SIZE);
@NonNull
@GuardedBy("mLock")
private final Map<TextClassificationSessionId, DeathRecipient> mDeathRecipients =
@@ -775,6 +778,8 @@ public final class TextClassificationManagerService extends ITextClassifierServi
}
private final class ServiceState {
+ private static final int MAX_PENDING_REQUESTS = 20;
+
@UserIdInt
final int mUserId;
@NonNull
@@ -786,7 +791,15 @@ public final class TextClassificationManagerService extends ITextClassifierServi
final int mBindServiceFlags;
@NonNull
@GuardedBy("mLock")
- final Queue<PendingRequest> mPendingRequests = new ArrayDeque<>();
+ final FixedSizeQueue<PendingRequest> mPendingRequests =
+ new FixedSizeQueue<>(MAX_PENDING_REQUESTS,
+ request -> {
+ Slog.w(LOG_TAG,
+ String.format("Pending request[%s] is dropped", request.mName));
+ if (request.mOnServiceFailure != null) {
+ request.mOnServiceFailure.run();
+ }
+ });
@Nullable
@GuardedBy("mLock")
ITextClassifierService mService;
@@ -882,6 +895,9 @@ public final class TextClassificationManagerService extends ITextClassifierServi
Slog.d(LOG_TAG, "Binding to " + serviceIntent.getComponent());
willBind = mContext.bindServiceAsUser(
serviceIntent, mConnection, mBindServiceFlags, UserHandle.of(mUserId));
+ if (!willBind) {
+ Slog.e(LOG_TAG, "Could not bind to " + componentName);
+ }
mBinding = willBind;
} finally {
Binder.restoreCallingIdentity(identity);
@@ -907,7 +923,7 @@ public final class TextClassificationManagerService extends ITextClassifierServi
pw.printPair("bindServiceFlags", mBindServiceFlags);
pw.printPair("boundServiceUid", mBoundServiceUid);
pw.printPair("binding", mBinding);
- pw.printPair("numberRequests", mPendingRequests.size());
+ pw.printPair("numOfPendingRequests", mPendingRequests.size());
}
}
@@ -954,16 +970,19 @@ public final class TextClassificationManagerService extends ITextClassifierServi
@Override
public void onServiceDisconnected(ComponentName name) {
+ Slog.i(LOG_TAG, "onServiceDisconnected called with " + name);
cleanupService();
}
@Override
public void onBindingDied(ComponentName name) {
+ Slog.i(LOG_TAG, "onBindingDied called with " + name);
cleanupService();
}
@Override
public void onNullBinding(ComponentName name) {
+ Slog.i(LOG_TAG, "onNullBinding called with " + name);
cleanupService();
}
diff --git a/services/core/java/com/android/server/uri/UriGrantsManagerService.java b/services/core/java/com/android/server/uri/UriGrantsManagerService.java
index 3796c5fda411..c38d649ada9b 100644
--- a/services/core/java/com/android/server/uri/UriGrantsManagerService.java
+++ b/services/core/java/com/android/server/uri/UriGrantsManagerService.java
@@ -77,6 +77,7 @@ import android.util.Slog;
import android.util.SparseArray;
import android.util.Xml;
+import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.FastXmlSerializer;
@@ -114,7 +115,7 @@ public class UriGrantsManagerService extends IUriGrantsManager.Stub {
private static final String TAG = "UriGrantsManagerService";
// Maximum number of persisted Uri grants a package is allowed
private static final int MAX_PERSISTED_URI_GRANTS = 128;
- private static final boolean ENABLE_DYNAMIC_PERMISSIONS = true;
+ private static final boolean ENABLE_DYNAMIC_PERMISSIONS = false;
private final Object mLock = new Object();
private final H mH;
@@ -122,6 +123,7 @@ public class UriGrantsManagerService extends IUriGrantsManager.Stub {
PackageManagerInternal mPmInternal;
/** File storing persisted {@link #mGrantedUriPermissions}. */
+ @GuardedBy("mLock")
private final AtomicFile mGrantFile;
/** XML constants used in {@link #mGrantFile} */
@@ -142,6 +144,7 @@ public class UriGrantsManagerService extends IUriGrantsManager.Stub {
* This optimized lookup structure maps from {@link UriPermission#targetUid}
* to {@link UriPermission#uri} to {@link UriPermission}.
*/
+ @GuardedBy("mLock")
private final SparseArray<ArrayMap<GrantUri, UriPermission>>
mGrantedUriPermissions = new SparseArray<>();
@@ -206,39 +209,44 @@ public class UriGrantsManagerService extends IUriGrantsManager.Stub {
}
}
+ @Override
+ public void grantUriPermissionFromOwner(IBinder token, int fromUid, String targetPkg,
+ Uri uri, final int modeFlags, int sourceUserId, int targetUserId) {
+ grantUriPermissionFromOwnerUnlocked(token, fromUid, targetPkg, uri, modeFlags, sourceUserId,
+ targetUserId);
+ }
+
/**
* @param uri This uri must NOT contain an embedded userId.
* @param sourceUserId The userId in which the uri is to be resolved.
* @param targetUserId The userId of the app that receives the grant.
*/
- @Override
- public void grantUriPermissionFromOwner(IBinder token, int fromUid, String targetPkg, Uri uri,
- final int modeFlags, int sourceUserId, int targetUserId) {
+ private void grantUriPermissionFromOwnerUnlocked(IBinder token, int fromUid, String targetPkg,
+ Uri uri, final int modeFlags, int sourceUserId, int targetUserId) {
targetUserId = mAmInternal.handleIncomingUser(Binder.getCallingPid(),
Binder.getCallingUid(), targetUserId, false, ALLOW_FULL_ONLY,
"grantUriPermissionFromOwner", null);
- synchronized(mLock) {
- UriPermissionOwner owner = UriPermissionOwner.fromExternalToken(token);
- if (owner == null) {
- throw new IllegalArgumentException("Unknown owner: " + token);
- }
- if (fromUid != Binder.getCallingUid()) {
- if (Binder.getCallingUid() != myUid()) {
- // Only system code can grant URI permissions on behalf
- // of other users.
- throw new SecurityException("nice try");
- }
- }
- if (targetPkg == null) {
- throw new IllegalArgumentException("null target");
- }
- if (uri == null) {
- throw new IllegalArgumentException("null uri");
- }
- grantUriPermission(fromUid, targetPkg, new GrantUri(sourceUserId, uri, modeFlags),
- modeFlags, owner, targetUserId);
+ UriPermissionOwner owner = UriPermissionOwner.fromExternalToken(token);
+ if (owner == null) {
+ throw new IllegalArgumentException("Unknown owner: " + token);
}
+ if (fromUid != Binder.getCallingUid()) {
+ if (Binder.getCallingUid() != myUid()) {
+ // Only system code can grant URI permissions on behalf
+ // of other users.
+ throw new SecurityException("nice try");
+ }
+ }
+ if (targetPkg == null) {
+ throw new IllegalArgumentException("null target");
+ }
+ if (uri == null) {
+ throw new IllegalArgumentException("null uri");
+ }
+
+ grantUriPermissionUnlocked(fromUid, targetPkg, new GrantUri(sourceUserId, uri, modeFlags),
+ modeFlags, owner, targetUserId);
}
@Override
@@ -362,7 +370,7 @@ public class UriGrantsManagerService extends IUriGrantsManager.Stub {
persistChanged |= prefixPerm.takePersistableModes(modeFlags);
}
- persistChanged |= maybePrunePersistedUriGrants(uid);
+ persistChanged |= maybePrunePersistedUriGrantsLocked(uid);
if (persistChanged) {
schedulePersistUriGrants();
@@ -374,8 +382,8 @@ public class UriGrantsManagerService extends IUriGrantsManager.Stub {
public void clearGrantedUriPermissions(String packageName, int userId) {
mAmInternal.enforceCallingPermission(
CLEAR_APP_GRANTED_URI_PERMISSIONS, "clearGrantedUriPermissions");
- synchronized(mLock) {
- removeUriPermissionsForPackage(packageName, userId, true, true);
+ synchronized (mLock) {
+ removeUriPermissionsForPackageLocked(packageName, userId, true, true);
}
}
@@ -416,11 +424,11 @@ public class UriGrantsManagerService extends IUriGrantsManager.Stub {
if (exactPerm != null) {
persistChanged |= exactPerm.releasePersistableModes(modeFlags);
- removeUriPermissionIfNeeded(exactPerm);
+ removeUriPermissionIfNeededLocked(exactPerm);
}
if (prefixPerm != null) {
persistChanged |= prefixPerm.releasePersistableModes(modeFlags);
- removeUriPermissionIfNeeded(prefixPerm);
+ removeUriPermissionIfNeededLocked(prefixPerm);
}
if (persistChanged) {
@@ -441,8 +449,9 @@ public class UriGrantsManagerService extends IUriGrantsManager.Stub {
* @param targetOnly When {@code true}, only remove permissions where the app is the target,
* not source.
*/
- void removeUriPermissionsForPackage(
- String packageName, int userHandle, boolean persistable, boolean targetOnly) {
+ @GuardedBy("mLock")
+ private void removeUriPermissionsForPackageLocked(String packageName, int userHandle,
+ boolean persistable, boolean targetOnly) {
if (userHandle == UserHandle.USER_ALL && packageName == null) {
throw new IllegalArgumentException("Must narrow by either package or user");
}
@@ -494,7 +503,9 @@ public class UriGrantsManagerService extends IUriGrantsManager.Stub {
}
/** Returns if the ContentProvider has granted a uri to callingUid */
- boolean checkAuthorityGrants(int callingUid, ProviderInfo cpi, int userId, boolean checkUser) {
+ @GuardedBy("mLock")
+ private boolean checkAuthorityGrantsLocked(int callingUid, ProviderInfo cpi, int userId,
+ boolean checkUser) {
final ArrayMap<GrantUri, UriPermission> perms = mGrantedUriPermissions.get(callingUid);
if (perms != null) {
for (int i = perms.size() - 1; i >= 0; i--) {
@@ -530,7 +541,8 @@ public class UriGrantsManagerService extends IUriGrantsManager.Stub {
*
* @return if any mutations occured that require persisting.
*/
- private boolean maybePrunePersistedUriGrants(int uid) {
+ @GuardedBy("mLock")
+ private boolean maybePrunePersistedUriGrantsLocked(int uid) {
final ArrayMap<GrantUri, UriPermission> perms = mGrantedUriPermissions.get(uid);
if (perms == null) return false;
if (perms.size() < MAX_PERSISTED_URI_GRANTS) return false;
@@ -552,14 +564,14 @@ public class UriGrantsManagerService extends IUriGrantsManager.Stub {
if (DEBUG) Slog.v(TAG, "Trimming grant created at " + perm.persistedCreateTime);
perm.releasePersistableModes(~0);
- removeUriPermissionIfNeeded(perm);
+ removeUriPermissionIfNeededLocked(perm);
}
return true;
}
/** Like checkGrantUriPermission, but takes an Intent. */
- NeededUriGrants checkGrantUriPermissionFromIntent(int callingUid,
+ private NeededUriGrants checkGrantUriPermissionFromIntentUnlocked(int callingUid,
String targetPkg, Intent intent, int mode, NeededUriGrants needed, int targetUserId) {
if (DEBUG) Slog.v(TAG,
"Checking URI perm to data=" + (intent != null ? intent.getData() : null)
@@ -598,7 +610,8 @@ public class UriGrantsManagerService extends IUriGrantsManager.Stub {
}
if (data != null) {
GrantUri grantUri = GrantUri.resolve(contentUserHint, data, mode);
- targetUid = checkGrantUriPermission(callingUid, targetPkg, grantUri, mode, targetUid);
+ targetUid = checkGrantUriPermissionUnlocked(callingUid, targetPkg, grantUri, mode,
+ targetUid);
if (targetUid > 0) {
if (needed == null) {
needed = new NeededUriGrants(targetPkg, targetUid, mode);
@@ -611,7 +624,7 @@ public class UriGrantsManagerService extends IUriGrantsManager.Stub {
Uri uri = clip.getItemAt(i).getUri();
if (uri != null) {
GrantUri grantUri = GrantUri.resolve(contentUserHint, uri, mode);
- targetUid = checkGrantUriPermission(callingUid, targetPkg,
+ targetUid = checkGrantUriPermissionUnlocked(callingUid, targetPkg,
grantUri, mode, targetUid);
if (targetUid > 0) {
if (needed == null) {
@@ -622,7 +635,7 @@ public class UriGrantsManagerService extends IUriGrantsManager.Stub {
} else {
Intent clipIntent = clip.getItemAt(i).getIntent();
if (clipIntent != null) {
- NeededUriGrants newNeeded = checkGrantUriPermissionFromIntent(
+ NeededUriGrants newNeeded = checkGrantUriPermissionFromIntentUnlocked(
callingUid, targetPkg, clipIntent, mode, needed, targetUserId);
if (newNeeded != null) {
needed = newNeeded;
@@ -635,7 +648,8 @@ public class UriGrantsManagerService extends IUriGrantsManager.Stub {
return needed;
}
- void readGrantedUriPermissions() {
+ @GuardedBy("mLock")
+ private void readGrantedUriPermissionsLocked() {
if (DEBUG) Slog.v(TAG, "readGrantedUriPermissions()");
final long now = System.currentTimeMillis();
@@ -681,7 +695,7 @@ public class UriGrantsManagerService extends IUriGrantsManager.Stub {
if (targetUid != -1) {
final GrantUri grantUri = new GrantUri(sourceUserId, uri,
prefix ? Intent.FLAG_GRANT_PREFIX_URI_PERMISSION : 0);
- final UriPermission perm = findOrCreateUriPermission(
+ final UriPermission perm = findOrCreateUriPermissionLocked(
sourcePkg, targetPkg, targetUid, grantUri);
perm.initPersistedModes(modeFlags, createdTime);
}
@@ -703,7 +717,8 @@ public class UriGrantsManagerService extends IUriGrantsManager.Stub {
}
}
- private UriPermission findOrCreateUriPermission(String sourcePkg,
+ @GuardedBy("mLock")
+ private UriPermission findOrCreateUriPermissionLocked(String sourcePkg,
String targetPkg, int targetUid, GrantUri grantUri) {
ArrayMap<GrantUri, UriPermission> targetUris = mGrantedUriPermissions.get(targetUid);
if (targetUris == null) {
@@ -740,15 +755,18 @@ public class UriGrantsManagerService extends IUriGrantsManager.Stub {
return;
}
- final UriPermission perm = findOrCreateUriPermission(
- pi.packageName, targetPkg, targetUid, grantUri);
+ final UriPermission perm;
+ synchronized (mLock) {
+ perm = findOrCreateUriPermissionLocked(pi.packageName, targetPkg, targetUid, grantUri);
+ }
perm.grantModes(modeFlags, owner);
mPmInternal.grantImplicitAccess(UserHandle.getUserId(targetUid), null,
UserHandle.getAppId(targetUid), pi.applicationInfo.uid, false /*direct*/);
}
/** Like grantUriPermissionUnchecked, but takes an Intent. */
- void grantUriPermissionUncheckedFromIntent(NeededUriGrants needed, UriPermissionOwner owner) {
+ private void grantUriPermissionUncheckedFromIntent(NeededUriGrants needed,
+ UriPermissionOwner owner) {
if (needed == null) {
return;
}
@@ -759,7 +777,7 @@ public class UriGrantsManagerService extends IUriGrantsManager.Stub {
}
}
- void grantUriPermission(int callingUid, String targetPkg, GrantUri grantUri,
+ private void grantUriPermissionUnlocked(int callingUid, String targetPkg, GrantUri grantUri,
final int modeFlags, UriPermissionOwner owner, int targetUserId) {
if (targetPkg == null) {
throw new NullPointerException("targetPkg");
@@ -767,7 +785,8 @@ public class UriGrantsManagerService extends IUriGrantsManager.Stub {
int targetUid = mPmInternal.getPackageUidInternal(targetPkg, MATCH_DEBUG_TRIAGED_MISSING,
targetUserId);
- targetUid = checkGrantUriPermission(callingUid, targetPkg, grantUri, modeFlags, targetUid);
+ targetUid = checkGrantUriPermissionUnlocked(callingUid, targetPkg, grantUri, modeFlags,
+ targetUid);
if (targetUid < 0) {
return;
}
@@ -775,7 +794,7 @@ public class UriGrantsManagerService extends IUriGrantsManager.Stub {
grantUriPermissionUnchecked(targetUid, targetPkg, grantUri, modeFlags, owner);
}
- void revokeUriPermission(String targetPackage, int callingUid, GrantUri grantUri,
+ private void revokeUriPermission(String targetPackage, int callingUid, GrantUri grantUri,
final int modeFlags) {
if (DEBUG) Slog.v(TAG, "Revoking all granted permissions to " + grantUri);
@@ -788,8 +807,19 @@ public class UriGrantsManagerService extends IUriGrantsManager.Stub {
return;
}
+ final boolean callerHoldsPermissions = checkHoldingPermissionsUnlocked(pi, grantUri,
+ callingUid, modeFlags);
+ synchronized (mLock) {
+ revokeUriPermissionLocked(targetPackage, callingUid, grantUri, modeFlags,
+ callerHoldsPermissions);
+ }
+ }
+
+ @GuardedBy("mLock")
+ private void revokeUriPermissionLocked(String targetPackage, int callingUid, GrantUri grantUri,
+ final int modeFlags, final boolean callerHoldsPermissions) {
// Does the caller have this permission on the URI?
- if (!checkHoldingPermissions(pi, grantUri, callingUid, modeFlags)) {
+ if (!callerHoldsPermissions) {
// If they don't have direct access to the URI, then revoke any
// ownerless URI permissions that have been granted to them.
final ArrayMap<GrantUri, UriPermission> perms = mGrantedUriPermissions.get(callingUid);
@@ -861,7 +891,7 @@ public class UriGrantsManagerService extends IUriGrantsManager.Stub {
* the given {@link ProviderInfo}. Final permission checking is always done
* in {@link ContentProvider}.
*/
- private boolean checkHoldingPermissions(
+ private boolean checkHoldingPermissionsUnlocked(
ProviderInfo pi, GrantUri grantUri, int uid, final int modeFlags) {
if (DEBUG) Slog.v(TAG, "checkHoldingPermissions: uri=" + grantUri + " uid=" + uid);
if (UserHandle.getUserId(uid) != grantUri.sourceUserId) {
@@ -870,11 +900,17 @@ public class UriGrantsManagerService extends IUriGrantsManager.Stub {
return false;
}
}
- return checkHoldingPermissionsInternal(pi, grantUri, uid, modeFlags, true);
+ return checkHoldingPermissionsInternalUnlocked(pi, grantUri, uid, modeFlags, true);
}
- private boolean checkHoldingPermissionsInternal(ProviderInfo pi,
+ private boolean checkHoldingPermissionsInternalUnlocked(ProviderInfo pi,
GrantUri grantUri, int uid, final int modeFlags, boolean considerUidPermissions) {
+ // We must never hold our local mLock in this method, since we may need
+ // to call into ActivityManager for dynamic permission checks
+ if (Thread.holdsLock(mLock)) {
+ throw new IllegalStateException("Must never hold local mLock");
+ }
+
if (pi.applicationInfo.uid == uid) {
return true;
} else if (!pi.exported) {
@@ -968,7 +1004,8 @@ public class UriGrantsManagerService extends IUriGrantsManager.Stub {
return readMet && writeMet && forceMet;
}
- private void removeUriPermissionIfNeeded(UriPermission perm) {
+ @GuardedBy("mLock")
+ private void removeUriPermissionIfNeededLocked(UriPermission perm) {
if (perm.modeFlags != 0) {
return;
}
@@ -985,6 +1022,7 @@ public class UriGrantsManagerService extends IUriGrantsManager.Stub {
}
}
+ @GuardedBy("mLock")
private UriPermission findUriPermissionLocked(int targetUid, GrantUri grantUri) {
final ArrayMap<GrantUri, UriPermission> targetUris = mGrantedUriPermissions.get(targetUid);
if (targetUris != null) {
@@ -1020,7 +1058,7 @@ public class UriGrantsManagerService extends IUriGrantsManager.Stub {
* If you already know the uid of the target, you can supply it in
* lastTargetUid else set that to -1.
*/
- int checkGrantUriPermission(int callingUid, String targetPkg, GrantUri grantUri,
+ private int checkGrantUriPermissionUnlocked(int callingUid, String targetPkg, GrantUri grantUri,
int modeFlags, int lastTargetUid) {
if (!Intent.isAccessUriMode(modeFlags)) {
return -1;
@@ -1076,7 +1114,7 @@ public class UriGrantsManagerService extends IUriGrantsManager.Stub {
boolean targetHoldsPermission = false;
if (targetUid >= 0) {
// First... does the target actually need this permission?
- if (checkHoldingPermissions(pi, grantUri, targetUid, modeFlags)) {
+ if (checkHoldingPermissionsUnlocked(pi, grantUri, targetUid, modeFlags)) {
// No need to grant the target this permission.
if (DEBUG) Slog.v(TAG,
"Target " + targetPkg + " already has full permission to " + grantUri);
@@ -1144,7 +1182,7 @@ public class UriGrantsManagerService extends IUriGrantsManager.Stub {
*/
boolean specialCrossUserGrant = targetUid >= 0
&& UserHandle.getUserId(targetUid) != grantUri.sourceUserId
- && checkHoldingPermissionsInternal(pi, grantUri, callingUid,
+ && checkHoldingPermissionsInternalUnlocked(pi, grantUri, callingUid,
modeFlags, false /*without considering the uid permissions*/);
// Second... is the provider allowing granting of URI permissions?
@@ -1179,9 +1217,13 @@ public class UriGrantsManagerService extends IUriGrantsManager.Stub {
}
// Third... does the caller itself have permission to access this uri?
- if (!checkHoldingPermissions(pi, grantUri, callingUid, modeFlags)) {
+ if (!checkHoldingPermissionsUnlocked(pi, grantUri, callingUid, modeFlags)) {
// Require they hold a strong enough Uri permission
- if (!checkUriPermission(grantUri, callingUid, modeFlags)) {
+ final boolean res;
+ synchronized (mLock) {
+ res = checkUriPermissionLocked(grantUri, callingUid, modeFlags);
+ }
+ if (!res) {
if (android.Manifest.permission.MANAGE_DOCUMENTS.equals(pi.readPermission)) {
throw new SecurityException(
"UID " + callingUid + " does not have permission to " + grantUri
@@ -1200,13 +1242,14 @@ public class UriGrantsManagerService extends IUriGrantsManager.Stub {
/**
* @param userId The userId in which the uri is to be resolved.
*/
- int checkGrantUriPermission(int callingUid, String targetPkg, Uri uri, int modeFlags,
- int userId) {
- return checkGrantUriPermission(callingUid, targetPkg,
+ private int checkGrantUriPermissionUnlocked(int callingUid, String targetPkg, Uri uri,
+ int modeFlags, int userId) {
+ return checkGrantUriPermissionUnlocked(callingUid, targetPkg,
new GrantUri(userId, uri, modeFlags), modeFlags, -1);
}
- boolean checkUriPermission(GrantUri grantUri, int uid, final int modeFlags) {
+ @GuardedBy("mLock")
+ private boolean checkUriPermissionLocked(GrantUri grantUri, int uid, final int modeFlags) {
final boolean persistable = (modeFlags & Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION) != 0;
final int minStrength = persistable ? UriPermission.STRENGTH_PERSISTABLE
: UriPermission.STRENGTH_OWNED;
@@ -1238,7 +1281,8 @@ public class UriGrantsManagerService extends IUriGrantsManager.Stub {
return false;
}
- private void writeGrantedUriPermissions() {
+ @GuardedBy("mLock")
+ private void writeGrantedUriPermissionsLocked() {
if (DEBUG) Slog.v(TAG, "writeGrantedUriPermissions()");
final long startTime = SystemClock.uptimeMillis();
@@ -1299,34 +1343,35 @@ public class UriGrantsManagerService extends IUriGrantsManager.Stub {
public void handleMessage(Message msg) {
switch (msg.what) {
case PERSIST_URI_GRANTS_MSG: {
- writeGrantedUriPermissions();
+ synchronized (mLock) {
+ writeGrantedUriPermissionsLocked();
+ }
break;
}
}
}
}
- final class LocalService implements UriGrantsManagerInternal {
+ private final class LocalService implements UriGrantsManagerInternal {
@Override
public void removeUriPermissionIfNeeded(UriPermission perm) {
synchronized (mLock) {
- UriGrantsManagerService.this.removeUriPermissionIfNeeded(perm);
+ UriGrantsManagerService.this.removeUriPermissionIfNeededLocked(perm);
}
}
@Override
public void revokeUriPermission(String targetPackage, int callingUid, GrantUri grantUri,
int modeFlags) {
- synchronized (mLock) {
- UriGrantsManagerService.this.revokeUriPermission(
- targetPackage, callingUid, grantUri, modeFlags);
- }
+ UriGrantsManagerService.this.revokeUriPermission(
+ targetPackage, callingUid, grantUri, modeFlags);
}
@Override
public boolean checkUriPermission(GrantUri grantUri, int uid, int modeFlags) {
synchronized (mLock) {
- return UriGrantsManagerService.this.checkUriPermission(grantUri, uid, modeFlags);
+ return UriGrantsManagerService.this.checkUriPermissionLocked(grantUri, uid,
+ modeFlags);
}
}
@@ -1334,83 +1379,73 @@ public class UriGrantsManagerService extends IUriGrantsManager.Stub {
public int checkGrantUriPermission(int callingUid, String targetPkg, Uri uri, int modeFlags,
int userId) {
enforceNotIsolatedCaller("checkGrantUriPermission");
- synchronized (mLock) {
- return UriGrantsManagerService.this.checkGrantUriPermission(
- callingUid, targetPkg, uri, modeFlags, userId);
- }
+ return UriGrantsManagerService.this.checkGrantUriPermissionUnlocked(
+ callingUid, targetPkg, uri, modeFlags, userId);
}
@Override
public NeededUriGrants checkGrantUriPermissionFromIntent(Intent intent, int callingUid,
String targetPkg, int targetUserId) {
- synchronized (mLock) {
- final int mode = (intent != null) ? intent.getFlags() : 0;
- return UriGrantsManagerService.this.checkGrantUriPermissionFromIntent(
- callingUid, targetPkg, intent, mode, null, targetUserId);
- }
+ final int mode = (intent != null) ? intent.getFlags() : 0;
+ return UriGrantsManagerService.this.checkGrantUriPermissionFromIntentUnlocked(
+ callingUid, targetPkg, intent, mode, null, targetUserId);
}
@Override
public void grantUriPermissionUncheckedFromIntent(NeededUriGrants needed,
UriPermissionOwner owner) {
- synchronized (mLock) {
- UriGrantsManagerService.this.grantUriPermissionUncheckedFromIntent(needed, owner);
- }
+ UriGrantsManagerService.this.grantUriPermissionUncheckedFromIntent(needed, owner);
}
@Override
public void onSystemReady() {
synchronized (mLock) {
- UriGrantsManagerService.this.readGrantedUriPermissions();
+ UriGrantsManagerService.this.readGrantedUriPermissionsLocked();
}
}
@Override
public IBinder newUriPermissionOwner(String name) {
enforceNotIsolatedCaller("newUriPermissionOwner");
- synchronized(mLock) {
- UriPermissionOwner owner = new UriPermissionOwner(this, name);
- return owner.getExternalToken();
- }
+ UriPermissionOwner owner = new UriPermissionOwner(this, name);
+ return owner.getExternalToken();
}
@Override
public void removeUriPermissionsForPackage(String packageName, int userHandle,
boolean persistable, boolean targetOnly) {
- synchronized(mLock) {
- UriGrantsManagerService.this.removeUriPermissionsForPackage(
+ synchronized (mLock) {
+ UriGrantsManagerService.this.removeUriPermissionsForPackageLocked(
packageName, userHandle, persistable, targetOnly);
}
}
@Override
public void revokeUriPermissionFromOwner(IBinder token, Uri uri, int mode, int userId) {
- synchronized(mLock) {
- final UriPermissionOwner owner = UriPermissionOwner.fromExternalToken(token);
- if (owner == null) {
- throw new IllegalArgumentException("Unknown owner: " + token);
- }
+ final UriPermissionOwner owner = UriPermissionOwner.fromExternalToken(token);
+ if (owner == null) {
+ throw new IllegalArgumentException("Unknown owner: " + token);
+ }
- if (uri == null) {
- owner.removeUriPermissions(mode);
- } else {
- owner.removeUriPermission(new GrantUri(userId, uri, mode), mode);
- }
+ if (uri == null) {
+ owner.removeUriPermissions(mode);
+ } else {
+ owner.removeUriPermission(new GrantUri(userId, uri, mode), mode);
}
}
@Override
public boolean checkAuthorityGrants(int callingUid, ProviderInfo cpi, int userId,
boolean checkUser) {
- synchronized(mLock) {
- return UriGrantsManagerService.this.checkAuthorityGrants(
+ synchronized (mLock) {
+ return UriGrantsManagerService.this.checkAuthorityGrantsLocked(
callingUid, cpi, userId, checkUser);
}
}
@Override
public void dump(PrintWriter pw, boolean dumpAll, String dumpPackage) {
- synchronized(mLock) {
+ synchronized (mLock) {
boolean needSep = false;
boolean printedAnything = false;
if (mGrantedUriPermissions.size() > 0) {
diff --git a/services/core/java/com/android/server/wm/AccessibilityController.java b/services/core/java/com/android/server/wm/AccessibilityController.java
index 34998a025663..b9240c78d711 100644
--- a/services/core/java/com/android/server/wm/AccessibilityController.java
+++ b/services/core/java/com/android/server/wm/AccessibilityController.java
@@ -898,11 +898,16 @@ final class AccessibilityController {
/* ignore */
}
mSurfaceControl = surfaceControl;
- mService.mTransactionFactory.get().setLayer(mSurfaceControl,
- mService.mPolicy.getWindowLayerFromTypeLw(TYPE_MAGNIFICATION_OVERLAY)
- * WindowManagerService.TYPE_LAYER_MULTIPLIER)
- .setPosition(mSurfaceControl, 0, 0)
- .apply();
+
+ final SurfaceControl.Transaction t = mService.mTransactionFactory.get();
+ final int layer =
+ mService.mPolicy.getWindowLayerFromTypeLw(TYPE_MAGNIFICATION_OVERLAY) *
+ WindowManagerService.TYPE_LAYER_MULTIPLIER;
+ t.setLayer(mSurfaceControl, layer).setPosition(mSurfaceControl, 0, 0);
+ InputMonitor.setTrustedOverlayInputInfo(mSurfaceControl, t,
+ mDisplayContent.getDisplayId(), "Magnification Overlay");
+ t.apply();
+
mSurface.copyFrom(mSurfaceControl);
mAnimationController = new AnimationController(context,
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index fe2b144bcdd6..be2f9d410475 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -2842,7 +2842,8 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
// their client may have activities.
// No longer have activities, so update LRU list and oom adj.
app.updateProcessInfo(true /* updateServiceConnectionActivities */,
- false /* activityChange */, true /* updateOomAdj */);
+ false /* activityChange */, true /* updateOomAdj */,
+ false /* addPendingTopUid */);
}
}
@@ -7539,7 +7540,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
public String toString() {
if (stringName != null) {
return stringName + " t" + (task == null ? INVALID_TASK_ID : task.mTaskId) +
- (finishing ? " f}" : "") + (mIsExiting ? " mIsExiting=" : "") + "}";
+ (finishing ? " f}" : "") + (mIsExiting ? " isExiting" : "") + "}";
}
StringBuilder sb = new StringBuilder(128);
sb.append("ActivityRecord{");
diff --git a/services/core/java/com/android/server/wm/ActivityStack.java b/services/core/java/com/android/server/wm/ActivityStack.java
index 00b2a58dbe8f..4bede4c3623f 100644
--- a/services/core/java/com/android/server/wm/ActivityStack.java
+++ b/services/core/java/com/android/server/wm/ActivityStack.java
@@ -23,7 +23,6 @@ import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
-import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
import static android.app.WindowConfiguration.activityTypeToString;
import static android.app.WindowConfiguration.windowingModeToString;
@@ -269,9 +268,6 @@ class ActivityStack extends Task {
private final AnimatingActivityRegistry mAnimatingActivityRegistry =
new AnimatingActivityRegistry();
- /** Stores the override windowing-mode from before a transient mode change (eg. split) */
- private int mRestoreOverrideWindowingMode = WINDOWING_MODE_UNDEFINED;
-
private boolean mTopActivityOccludesKeyguard;
private ActivityRecord mTopDismissingKeyguardActivity;
@@ -662,19 +658,6 @@ class ActivityStack extends Task {
}
/**
- * A transient windowing mode is one which activities enter into temporarily. Examples of this
- * are Split window modes and pip. Non-transient modes are modes that displays can adopt.
- *
- * @param windowingMode the windowingMode to test for transient-ness.
- * @return {@code true} if the windowing mode is transient, {@code false} otherwise.
- */
- private static boolean isTransientWindowingMode(int windowingMode) {
- return windowingMode == WINDOWING_MODE_PINNED
- || windowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY
- || windowingMode == WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
- }
-
- /**
* Specialization of {@link #setWindowingMode(int)} for this subclass.
*
* @param preferredWindowingMode the preferred windowing mode. This may not be honored depending
@@ -698,11 +681,6 @@ class ActivityStack extends Task {
final int currentOverrideMode = getRequestedOverrideWindowingMode();
final Task topTask = getTopMostTask();
int windowingMode = preferredWindowingMode;
- if (preferredWindowingMode == WINDOWING_MODE_UNDEFINED
- && isTransientWindowingMode(currentMode)) {
- // Leaving a transient mode. Interpret UNDEFINED as "restore"
- windowingMode = mRestoreOverrideWindowingMode;
- }
// Need to make sure windowing mode is supported. If we in the process of creating the stack
// no need to resolve the windowing mode again as it is already resolved to the right mode.
@@ -712,29 +690,16 @@ class ActivityStack extends Task {
windowingMode = WINDOWING_MODE_UNDEFINED;
}
}
- if (taskDisplayArea.getRootSplitScreenPrimaryTask() == this
- && windowingMode == WINDOWING_MODE_SPLIT_SCREEN_SECONDARY) {
- // Resolution to split-screen secondary for the primary split-screen stack means
- // we want to leave split-screen mode.
- windowingMode = mRestoreOverrideWindowingMode;
- }
final boolean alreadyInSplitScreenMode = taskDisplayArea.isSplitScreenModeActivated();
- // Take any required action due to us not supporting the preferred windowing mode.
- if (alreadyInSplitScreenMode && windowingMode == WINDOWING_MODE_FULLSCREEN
+ if (creating && alreadyInSplitScreenMode && windowingMode == WINDOWING_MODE_FULLSCREEN
&& isActivityTypeStandardOrUndefined()) {
- final boolean preferredSplitScreen =
- preferredWindowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY
- || preferredWindowingMode == WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
- if (preferredSplitScreen || creating) {
- // Looks like we can't launch in split screen mode or the stack we are launching
- // doesn't support split-screen mode, go ahead an dismiss split-screen and display a
- // warning toast about it.
- mAtmService.getTaskChangeNotificationController()
- .notifyActivityDismissingDockedStack();
- taskDisplayArea.onSplitScreenModeDismissed(this);
- }
+ // If the stack is being created explicitly in fullscreen mode, dismiss split-screen
+ // and display a warning toast about it.
+ mAtmService.getTaskChangeNotificationController()
+ .notifyActivityDismissingDockedStack();
+ taskDisplayArea.onSplitScreenModeDismissed(this);
}
if (currentMode == windowingMode) {
@@ -797,9 +762,6 @@ class ActivityStack extends Task {
+ " while there is already one isn't currently supported");
//return;
}
- if (isTransientWindowingMode(windowingMode) && !isTransientWindowingMode(currentMode)) {
- mRestoreOverrideWindowingMode = currentOverrideMode;
- }
mTmpRect2.setEmpty();
if (windowingMode != WINDOWING_MODE_FULLSCREEN) {
@@ -819,6 +781,22 @@ class ActivityStack extends Task {
mRootWindowContainer.ensureActivitiesVisible(null, 0, PRESERVE_WINDOWS);
mRootWindowContainer.resumeFocusedStacksTopActivities();
+
+ final boolean pinnedToFullscreen = currentMode == WINDOWING_MODE_PINNED
+ && windowingMode == WINDOWING_MODE_FULLSCREEN;
+ if (pinnedToFullscreen && topActivity != null && !isForceHidden()) {
+ mDisplayContent.getPinnedStackController().setPipWindowingModeChanging(true);
+ try {
+ // Report orientation as soon as possible so that the display can freeze earlier if
+ // the display orientation will be changed. Because the surface bounds of activity
+ // may have been set to fullscreen but the activity hasn't redrawn its content yet,
+ // the rotation animation needs to capture snapshot earlier to avoid animating from
+ // an intermediate state.
+ topActivity.reportDescendantOrientationChangeIfNeeded();
+ } finally {
+ mDisplayContent.getPinnedStackController().setPipWindowingModeChanging(false);
+ }
+ }
}
@Override
@@ -1704,7 +1682,8 @@ class ActivityStack extends Task {
// happens to be sitting towards the end.
if (next.attachedToProcess()) {
next.app.updateProcessInfo(false /* updateServiceConnectionActivities */,
- true /* activityChange */, false /* updateOomAdj */);
+ true /* activityChange */, false /* updateOomAdj */,
+ false /* addPendingTopUid */);
} else if (!next.isProcessRunning()) {
// Since the start-process is asynchronous, if we already know the process of next
// activity isn't running, we can start the process earlier to save the time to wait
@@ -1861,7 +1840,8 @@ class ActivityStack extends Task {
next.setState(RESUMED, "resumeTopActivityInnerLocked");
next.app.updateProcessInfo(false /* updateServiceConnectionActivities */,
- true /* activityChange */, true /* updateOomAdj */);
+ true /* activityChange */, true /* updateOomAdj */,
+ true /* addPendingTopUid */);
// Have the window manager re-evaluate the orientation of
// the screen based on the new activity order.
@@ -3252,22 +3232,22 @@ class ActivityStack extends Task {
@Override
void dump(PrintWriter pw, String prefix, boolean dumpAll) {
- pw.println(prefix + "mStackId=" + getRootTaskId());
- pw.println(prefix + "mDeferRemoval=" + mDeferRemoval);
- pw.println(prefix + "mBounds=" + getRawBounds().toShortString());
- for (int taskNdx = mChildren.size() - 1; taskNdx >= 0; taskNdx--) {
- mChildren.get(taskNdx).dump(pw, prefix + " ", dumpAll);
+ if (mDeferRemoval) {
+ pw.println(prefix + "mDeferRemoval=true");
}
+ super.dump(pw, prefix, dumpAll);
if (!mExitingActivities.isEmpty()) {
pw.println();
- pw.println(" Exiting application tokens:");
+ pw.println(prefix + "Exiting application tokens:");
+ final String doublePrefix = prefix + " ";
for (int i = mExitingActivities.size() - 1; i >= 0; i--) {
WindowToken token = mExitingActivities.get(i);
- pw.print(" Exiting App #"); pw.print(i);
+ pw.print(doublePrefix + "Exiting App #" + i);
pw.print(' '); pw.print(token);
pw.println(':');
- token.dump(pw, " ", dumpAll);
+ token.dump(pw, doublePrefix, dumpAll);
}
+ pw.println();
}
mAnimatingActivityRegistry.dump(pw, "AnimatingApps:", prefix);
}
diff --git a/services/core/java/com/android/server/wm/ActivityStackSupervisor.java b/services/core/java/com/android/server/wm/ActivityStackSupervisor.java
index b7ca1a9aeab8..1f9e8609c2ad 100644
--- a/services/core/java/com/android/server/wm/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/wm/ActivityStackSupervisor.java
@@ -1886,7 +1886,7 @@ public class ActivityStackSupervisor implements RecentTasks.Callbacks {
public void dump(PrintWriter pw, String prefix) {
pw.println();
pw.println("ActivityStackSupervisor state:");
- mRootWindowContainer.dump(pw, prefix);
+ mRootWindowContainer.dump(pw, prefix, true /* dumpAll */);
getKeyguardController().dump(pw, prefix);
mService.getLockTaskController().dump(pw, prefix);
pw.print(prefix);
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
index 5f591b54b067..6dd1ea934497 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
@@ -1685,6 +1685,11 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
final NeededUriGrants resultGrants = collectGrants(resultData, r.resultTo);
synchronized (mGlobalLock) {
+ // Sanity check in case activity was removed before entering global lock.
+ if (!r.isInHistory()) {
+ return true;
+ }
+
// Keep track of the root activity of the task before we finish it
final Task tr = r.getTask();
final ActivityRecord rootR = tr.getRootActivity();
@@ -4873,6 +4878,10 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
return;
}
+ if (isInPictureInPictureMode(activity)) {
+ throw new IllegalStateException("Activity is already in PIP mode");
+ }
+
final boolean canEnterPictureInPicture = activity.checkEnterPictureInPictureState(
"requestPictureInPictureMode", /* beforeStopping */ false);
if (!canEnterPictureInPicture) {
diff --git a/services/core/java/com/android/server/wm/AlertWindowNotification.java b/services/core/java/com/android/server/wm/AlertWindowNotification.java
index 7b511ec20541..fde036950245 100644
--- a/services/core/java/com/android/server/wm/AlertWindowNotification.java
+++ b/services/core/java/com/android/server/wm/AlertWindowNotification.java
@@ -18,6 +18,7 @@ package com.android.server.wm;
import static android.app.NotificationManager.IMPORTANCE_MIN;
import static android.app.PendingIntent.FLAG_CANCEL_CURRENT;
+import static android.app.PendingIntent.FLAG_IMMUTABLE;
import static android.content.Context.NOTIFICATION_SERVICE;
import static android.content.Intent.FLAG_ACTIVITY_CLEAR_TASK;
import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
@@ -139,7 +140,8 @@ class AlertWindowNotification {
Uri.fromParts("package", packageName, null));
intent.setFlags(FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_CLEAR_TASK);
// Calls into activity manager...
- return PendingIntent.getActivity(context, mRequestCode, intent, FLAG_CANCEL_CURRENT);
+ return PendingIntent.getActivity(context, mRequestCode, intent,
+ FLAG_CANCEL_CURRENT | FLAG_IMMUTABLE);
}
private void createNotificationChannel(Context context, String appName) {
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index 8903776469db..4e19a5224bb4 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -1481,6 +1481,10 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
// has it own policy for bounds, the activity bounds based on parent is unknown.
return false;
}
+ if (mPinnedStackControllerLocked.isPipActiveOrWindowingModeChanging()) {
+ // Use normal rotation animation because seamless PiP rotation is not supported yet.
+ return false;
+ }
setFixedRotationLaunchingApp(r, rotation);
return true;
@@ -2973,12 +2977,10 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
pw.println();
mWallpaperController.dump(pw, " ");
- pw.println();
- pw.print("mSystemGestureExclusion=");
if (mSystemGestureExclusionListeners.getRegisteredCallbackCount() > 0) {
+ pw.println();
+ pw.print(" mSystemGestureExclusion=");
pw.println(mSystemGestureExclusion);
- } else {
- pw.println("<no lstnrs>");
}
pw.println();
@@ -3502,22 +3504,21 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
* doesn't support IME/system decorations.
*
* @param target current IME target.
- * @return {@link WindowState} that can host IME.
+ * @return {@link InsetsControlTarget} that can host IME.
*/
- WindowState getImeHostOrFallback(WindowState target) {
+ InsetsControlTarget getImeHostOrFallback(WindowState target) {
if (target != null && target.getDisplayContent().canShowIme()) {
return target;
}
return getImeFallback();
}
- WindowState getImeFallback() {
-
+ InsetsControlTarget getImeFallback() {
// host is in non-default display that doesn't support system decor, default to
- // default display's StatusBar to control IME.
- // TODO: (b/148234093)find a better host OR control IME animation/visibility directly
- // because it won't work when statusbar isn't available.
- return mWmService.getDefaultDisplayContentLocked().getDisplayPolicy().getStatusBar();
+ // default display's StatusBar to control IME (when available), else let system control it.
+ WindowState statusBar =
+ mWmService.getDefaultDisplayContentLocked().getDisplayPolicy().getStatusBar();
+ return statusBar != null ? statusBar : mRemoteInsetsControlTarget;
}
boolean canShowIme() {
@@ -4772,6 +4773,9 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
* @param sc The new SurfaceControl, where the DisplayContent's surfaces will be re-parented to.
*/
void reparentDisplayContent(WindowState win, SurfaceControl sc) {
+ if (mParentWindow != null) {
+ mParentWindow.removeEmbeddedDisplayContent(this);
+ }
mParentWindow = win;
mParentWindow.addEmbeddedDisplayContent(this);
mParentSurfaceControl = sc;
diff --git a/services/core/java/com/android/server/wm/EmulatorDisplayOverlay.java b/services/core/java/com/android/server/wm/EmulatorDisplayOverlay.java
index 2165b0e8b593..c9cc94423fe2 100644
--- a/services/core/java/com/android/server/wm/EmulatorDisplayOverlay.java
+++ b/services/core/java/com/android/server/wm/EmulatorDisplayOverlay.java
@@ -66,6 +66,9 @@ class EmulatorDisplayOverlay {
t.setLayer(ctrl, zOrder);
t.setPosition(ctrl, 0, 0);
t.show(ctrl);
+ // Ensure we aren't considered as obscuring for Input purposes.
+ InputMonitor.setTrustedOverlayInputInfo(ctrl, t,
+ dc.getDisplayId(), "EmulatorDisplayOverlay");
mSurface.copyFrom(ctrl);
} catch (OutOfResourcesException e) {
}
diff --git a/services/core/java/com/android/server/wm/InputMonitor.java b/services/core/java/com/android/server/wm/InputMonitor.java
index efcd61df5c75..8734b5efa45d 100644
--- a/services/core/java/com/android/server/wm/InputMonitor.java
+++ b/services/core/java/com/android/server/wm/InputMonitor.java
@@ -16,13 +16,17 @@
package com.android.server.wm;
+import static android.os.Process.myPid;
+import static android.os.Process.myUid;
import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER;
import static android.view.WindowManager.INPUT_CONSUMER_NAVIGATION;
import static android.view.WindowManager.INPUT_CONSUMER_PIP;
import static android.view.WindowManager.INPUT_CONSUMER_RECENTS_ANIMATION;
import static android.view.WindowManager.INPUT_CONSUMER_WALLPAPER;
import static android.view.WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL;
+import static android.view.WindowManager.LayoutParams.INPUT_FEATURE_NO_INPUT_CHANNEL;
import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_DISABLE_WALLPAPER_TOUCH_EVENTS;
+import static android.view.WindowManager.LayoutParams.TYPE_SECURE_SYSTEM_OVERLAY;
import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER;
import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_FOCUS_LIGHT;
@@ -550,4 +554,26 @@ final class InputMonitor {
}
}
}
+
+ /**
+ * Helper function to generate an InputInfo with type SECURE_SYSTEM_OVERLAY. This input
+ * info will not have an input channel or be touchable, but is used to omit Surfaces
+ * from occlusion detection, so that System global overlays like the Watermark aren't
+ * counted by the InputDispatcher as occluding applications below.
+ */
+ static void setTrustedOverlayInputInfo(SurfaceControl sc, SurfaceControl.Transaction t,
+ int displayId, String name) {
+ InputWindowHandle inputWindowHandle = new InputWindowHandle(null, displayId);
+ inputWindowHandle.name = name;
+ inputWindowHandle.layoutParamsType = TYPE_SECURE_SYSTEM_OVERLAY;
+ inputWindowHandle.dispatchingTimeoutNanos = -1;
+ inputWindowHandle.visible = true;
+ inputWindowHandle.canReceiveKeys = false;
+ inputWindowHandle.hasFocus = false;
+ inputWindowHandle.ownerPid = myPid();
+ inputWindowHandle.ownerUid = myUid();
+ inputWindowHandle.inputFeatures = INPUT_FEATURE_NO_INPUT_CHANNEL;
+ inputWindowHandle.scaleFactor = 1;
+ t.setInputWindowInfo(sc, inputWindowHandle);
+ }
}
diff --git a/services/core/java/com/android/server/wm/PinnedStackController.java b/services/core/java/com/android/server/wm/PinnedStackController.java
index 56312aa1b0b8..52ada472f0aa 100644
--- a/services/core/java/com/android/server/wm/PinnedStackController.java
+++ b/services/core/java/com/android/server/wm/PinnedStackController.java
@@ -23,7 +23,6 @@ import android.app.RemoteAction;
import android.content.ComponentName;
import android.content.pm.ParceledListSlice;
import android.content.res.Resources;
-import android.os.Handler;
import android.os.IBinder;
import android.os.RemoteException;
import android.util.DisplayMetrics;
@@ -33,8 +32,6 @@ import android.view.DisplayInfo;
import android.view.IPinnedStackController;
import android.view.IPinnedStackListener;
-import com.android.server.UiThread;
-
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.List;
@@ -61,7 +58,6 @@ class PinnedStackController {
private final WindowManagerService mService;
private final DisplayContent mDisplayContent;
- private final Handler mHandler = UiThread.getHandler();
private IPinnedStackListener mPinnedStackListener;
private final PinnedStackListenerDeathHandler mPinnedStackListenerDeathHandler =
@@ -69,6 +65,9 @@ class PinnedStackController {
private final PinnedStackControllerCallback mCallbacks = new PinnedStackControllerCallback();
+ /** Whether the PiP is entering or leaving. */
+ private boolean mIsPipWindowingModeChanging;
+
private boolean mIsImeShowing;
private int mImeHeight;
@@ -161,6 +160,20 @@ class PinnedStackController {
Float.compare(aspectRatio, mMaxAspectRatio) <= 0;
}
+ /** Returns {@code true} if the PiP is on screen or is changing windowing mode. */
+ boolean isPipActiveOrWindowingModeChanging() {
+ if (mIsPipWindowingModeChanging) {
+ return true;
+ }
+ final Task pinnedTask = mDisplayContent.getDefaultTaskDisplayArea().getRootPinnedTask();
+ return pinnedTask != null && pinnedTask.hasChild();
+ }
+
+ /** Sets whether a visible stack is changing from or to pinned mode. */
+ void setPipWindowingModeChanging(boolean isPipWindowingModeChanging) {
+ mIsPipWindowingModeChanging = isPipWindowingModeChanging;
+ }
+
/**
* Activity is hidden (either stopped or removed), resets the last saved snap fraction
* so that the default bounds will be returned for the next session.
diff --git a/services/core/java/com/android/server/wm/RootWindowContainer.java b/services/core/java/com/android/server/wm/RootWindowContainer.java
index ae5adcae5b9b..583663c5455f 100644
--- a/services/core/java/com/android/server/wm/RootWindowContainer.java
+++ b/services/core/java/com/android/server/wm/RootWindowContainer.java
@@ -3570,12 +3570,14 @@ class RootWindowContainer extends WindowContainer<DisplayContent>
}
}
- public void dump(PrintWriter pw, String prefix) {
+ @Override
+ public void dump(PrintWriter pw, String prefix, boolean dumpAll) {
+ super.dump(pw, prefix, dumpAll);
pw.print(prefix);
pw.println("topDisplayFocusedStack=" + getTopDisplayFocusedStack());
for (int i = getChildCount() - 1; i >= 0; --i) {
final DisplayContent display = getChildAt(i);
- display.dump(pw, prefix, true /* dumpAll */);
+ display.dump(pw, prefix, dumpAll);
}
pw.println();
}
diff --git a/services/core/java/com/android/server/wm/StrictModeFlash.java b/services/core/java/com/android/server/wm/StrictModeFlash.java
index f537005c955c..fa62daaff3fc 100644
--- a/services/core/java/com/android/server/wm/StrictModeFlash.java
+++ b/services/core/java/com/android/server/wm/StrictModeFlash.java
@@ -54,6 +54,10 @@ class StrictModeFlash {
t.setLayer(ctrl, WindowManagerService.TYPE_LAYER_MULTIPLIER * 101);
t.setPosition(ctrl, 0, 0);
t.show(ctrl);
+ // Ensure we aren't considered as obscuring for Input purposes.
+ InputMonitor.setTrustedOverlayInputInfo(ctrl, t, dc.getDisplayId(),
+ "StrictModeFlash");
+
mSurface.copyFrom(ctrl);
} catch (OutOfResourcesException e) {
}
diff --git a/services/core/java/com/android/server/wm/SurfaceAnimator.java b/services/core/java/com/android/server/wm/SurfaceAnimator.java
index 0143eb1abe03..0e5d7d910084 100644
--- a/services/core/java/com/android/server/wm/SurfaceAnimator.java
+++ b/services/core/java/com/android/server/wm/SurfaceAnimator.java
@@ -388,18 +388,15 @@ class SurfaceAnimator {
final SurfaceControl.Builder builder = animatable.makeAnimationLeash()
.setParent(animatable.getAnimationLeashParent())
.setName(surface + " - animation-leash")
- .setColorLayer();
+ // TODO(b/151665759) Defer reparent calls
+ // We want the leash to be visible immediately because the transaction which shows
+ // the leash may be deferred but the reparent will not. This will cause the leashed
+ // surface to be invisible until the deferred transaction is applied. If this
+ // doesn't work, you will can see the 2/3 button nav bar flicker during seamless
+ // rotation.
+ .setHidden(hidden)
+ .setEffectLayer();
final SurfaceControl leash = builder.build();
- if (!hidden) {
- // TODO(b/151665759) Defer reparent calls
- // We want the leash to be visible immediately but we want to set the effects on
- // the layer. Since the transaction used in this function may be deferred, we apply
- // another transaction immediately with the correct visibility and effects.
- // If this doesn't work, you will can see the 2/3 button nav bar flicker during
- // seamless rotation.
- transactionFactory.get().unsetColor(leash).show(leash).apply();
- }
- t.unsetColor(leash);
t.setWindowCrop(leash, width, height);
t.setPosition(leash, x, y);
t.show(leash);
@@ -431,16 +428,11 @@ class SurfaceAnimator {
void dump(PrintWriter pw, String prefix) {
pw.print(prefix); pw.print("mLeash="); pw.print(mLeash);
- if (mAnimationStartDelayed) {
- pw.print(" mAnimationStartDelayed="); pw.println(mAnimationStartDelayed);
- } else {
- pw.println();
- }
- pw.print(prefix); pw.println("Animation:");
+ pw.print(" mAnimationType=" + mAnimationType);
+ pw.println(mAnimationStartDelayed ? " mAnimationStartDelayed=true" : "");
+ pw.print(prefix); pw.print("Animation: "); pw.println(mAnimation);
if (mAnimation != null) {
mAnimation.dump(pw, prefix + " ");
- } else {
- pw.print(prefix); pw.println("null");
}
}
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index 345928e17768..3ee7ee7a4276 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -3164,6 +3164,11 @@ class Task extends WindowContainer<WindowContainer> {
}
@Override
+ public SurfaceControl.Builder makeAnimationLeash() {
+ return super.makeAnimationLeash().setMetadata(METADATA_TASK_ID, mTaskId);
+ }
+
+ @Override
public SurfaceControl getAnimationLeashParent() {
if (WindowManagerService.sHierarchicalAnimations) {
return super.getAnimationLeashParent();
@@ -3203,14 +3208,8 @@ class Task extends WindowContainer<WindowContainer> {
}
@Override
- void onSurfaceShown(SurfaceControl.Transaction t) {
- super.onSurfaceShown(t);
- t.unsetColor(mSurfaceControl);
- }
-
- @Override
void setInitialSurfaceControlProperties(SurfaceControl.Builder b) {
- b.setColorLayer().setMetadata(METADATA_TASK_ID, mTaskId);
+ b.setEffectLayer().setMetadata(METADATA_TASK_ID, mTaskId);
super.setInitialSurfaceControlProperties(b);
}
@@ -3510,7 +3509,7 @@ class Task extends WindowContainer<WindowContainer> {
ProtoLog.d(WM_DEBUG_RECENTS_ANIMATIONS,
"applyAnimationUnchecked, control: %s, task: %s, transit: %s",
control, asTask(), AppTransition.appTransitionToString(transit));
- control.addTaskToTargets(getRootTask(), finishedCallback);
+ control.addTaskToTargets(this, finishedCallback);
}
} else {
super.applyAnimationUnchecked(lp, enter, transit, isVoiceInteraction, finishedCallback);
@@ -3520,20 +3519,17 @@ class Task extends WindowContainer<WindowContainer> {
@Override
void dump(PrintWriter pw, String prefix, boolean dumpAll) {
super.dump(pw, prefix, dumpAll);
+ pw.println(prefix + "bounds=" + getBounds().toShortString());
final String doublePrefix = prefix + " ";
-
- pw.println(prefix + "taskId=" + mTaskId);
- pw.println(doublePrefix + "mBounds=" + getBounds().toShortString());
- pw.println(doublePrefix + "appTokens=" + mChildren);
-
- final String triplePrefix = doublePrefix + " ";
- final String quadruplePrefix = triplePrefix + " ";
-
- int[] index = { 0 };
- forAllActivities((r) -> {
- pw.println(triplePrefix + "Activity #" + index[0]++ + " " + r);
- r.dump(pw, quadruplePrefix, dumpAll);
- });
+ for (int i = mChildren.size() - 1; i >= 0; i--) {
+ final WindowContainer<?> child = mChildren.get(i);
+ pw.println(prefix + "* " + child);
+ // Only dump non-activity because full activity info is already printed by
+ // RootWindowContainer#dumpActivities.
+ if (child.asActivityRecord() == null) {
+ child.dump(pw, doublePrefix, dumpAll);
+ }
+ }
}
/**
diff --git a/services/core/java/com/android/server/wm/TaskChangeNotificationController.java b/services/core/java/com/android/server/wm/TaskChangeNotificationController.java
index df0fa9cc3272..2a241183ff1f 100644
--- a/services/core/java/com/android/server/wm/TaskChangeNotificationController.java
+++ b/services/core/java/com/android/server/wm/TaskChangeNotificationController.java
@@ -61,6 +61,7 @@ class TaskChangeNotificationController {
private static final int NOTIFY_TASK_LIST_FROZEN_UNFROZEN_MSG = 26;
private static final int NOTIFY_TASK_FOCUS_CHANGED_MSG = 27;
private static final int NOTIFY_TASK_REQUESTED_ORIENTATION_CHANGED_MSG = 28;
+ private static final int NOTIFY_ACTIVITY_ROTATED_MSG = 29;
// Delay in notifying task stack change listeners (in millis)
private static final int NOTIFY_TASK_STACK_CHANGE_LISTENERS_DELAY = 100;
@@ -183,6 +184,10 @@ class TaskChangeNotificationController {
l.onTaskRequestedOrientationChanged(m.arg1, m.arg2);
};
+ private final TaskStackConsumer mNotifyOnActivityRotation = (l, m) -> {
+ l.onActivityRotation(m.arg1);
+ };
+
@FunctionalInterface
public interface TaskStackConsumer {
void accept(ITaskStackListener t, Message m) throws RemoteException;
@@ -277,6 +282,9 @@ class TaskChangeNotificationController {
case NOTIFY_TASK_REQUESTED_ORIENTATION_CHANGED_MSG:
forAllRemoteListeners(mNotifyTaskRequestedOrientationChanged, msg);
break;
+ case NOTIFY_ACTIVITY_ROTATED_MSG:
+ forAllRemoteListeners(mNotifyOnActivityRotation, msg);
+ break;
}
if (msg.obj instanceof SomeArgs) {
((SomeArgs) msg.obj).recycle();
@@ -574,4 +582,12 @@ class TaskChangeNotificationController {
forAllLocalListeners(mNotifyTaskRequestedOrientationChanged, msg);
msg.sendToTarget();
}
+
+ /** @see android.app.ITaskStackListener#onActivityRotation(int) */
+ void notifyOnActivityRotation(int displayId) {
+ final Message msg = mHandler.obtainMessage(NOTIFY_ACTIVITY_ROTATED_MSG,
+ displayId, 0 /* unused */);
+ forAllLocalListeners(mNotifyOnActivityRotation, msg);
+ msg.sendToTarget();
+ }
}
diff --git a/services/core/java/com/android/server/wm/TaskDisplayArea.java b/services/core/java/com/android/server/wm/TaskDisplayArea.java
index 22054db20bbd..102c2a6364f4 100644
--- a/services/core/java/com/android/server/wm/TaskDisplayArea.java
+++ b/services/core/java/com/android/server/wm/TaskDisplayArea.java
@@ -1772,16 +1772,20 @@ final class TaskDisplayArea extends DisplayArea<ActivityStack> {
@Override
void dump(PrintWriter pw, String prefix, boolean dumpAll) {
pw.println(prefix + "TaskDisplayArea " + getName());
+ super.dump(pw, prefix, dumpAll);
if (mPreferredTopFocusableStack != null) {
pw.println(prefix + " mPreferredTopFocusableStack=" + mPreferredTopFocusableStack);
}
if (mLastFocusedStack != null) {
pw.println(prefix + " mLastFocusedStack=" + mLastFocusedStack);
}
- pw.println(prefix + " Application tokens in top down Z order:");
+ final String doublePrefix = prefix + " ";
+ final String triplePrefix = doublePrefix + " ";
+ pw.println(doublePrefix + "Application tokens in top down Z order:");
for (int stackNdx = getChildCount() - 1; stackNdx >= 0; --stackNdx) {
final ActivityStack stack = getChildAt(stackNdx);
- stack.dump(pw, prefix + " ", dumpAll);
+ pw.println(doublePrefix + "* " + stack);
+ stack.dump(pw, triplePrefix, dumpAll);
}
}
}
diff --git a/services/core/java/com/android/server/wm/TaskSnapshotSurface.java b/services/core/java/com/android/server/wm/TaskSnapshotSurface.java
index 392557045b4a..e26f1e1fe06f 100644
--- a/services/core/java/com/android/server/wm/TaskSnapshotSurface.java
+++ b/services/core/java/com/android/server/wm/TaskSnapshotSurface.java
@@ -391,6 +391,7 @@ class TaskSnapshotSurface implements StartingSurface {
frame = null;
mTmpSnapshotSize.set(0, 0, buffer.getWidth(), buffer.getHeight());
mTmpDstFrame.set(mFrame);
+ mTmpDstFrame.offsetTo(0, 0);
}
// Scale the mismatch dimensions to fill the task bounds
diff --git a/services/core/java/com/android/server/wm/WallpaperController.java b/services/core/java/com/android/server/wm/WallpaperController.java
index d1cb2105246a..aee5a1d7838b 100644
--- a/services/core/java/com/android/server/wm/WallpaperController.java
+++ b/services/core/java/com/android/server/wm/WallpaperController.java
@@ -106,6 +106,8 @@ class WallpaperController {
private static final int WALLPAPER_DRAW_TIMEOUT = 2;
private int mWallpaperDrawState = WALLPAPER_DRAW_NORMAL;
+ private boolean mShouldUpdateZoom;
+
/**
* Temporary storage for taking a screenshot of the wallpaper.
* @see #screenshotWallpaperLocked()
@@ -400,6 +402,7 @@ class WallpaperController {
void setWallpaperZoomOut(WindowState window, float zoom) {
if (Float.compare(window.mWallpaperZoomOut, zoom) != 0) {
window.mWallpaperZoomOut = zoom;
+ mShouldUpdateZoom = true;
updateWallpaperOffsetLocked(window, false);
}
}
@@ -623,9 +626,7 @@ class WallpaperController {
mLastWallpaperX = mWallpaperTarget.mWallpaperX;
mLastWallpaperXStep = mWallpaperTarget.mWallpaperXStep;
}
- if (mWallpaperTarget.mWallpaperZoomOut >= 0) {
- mLastWallpaperZoomOut = mWallpaperTarget.mWallpaperZoomOut;
- }
+ computeLastWallpaperZoomOut();
if (mWallpaperTarget.mWallpaperY >= 0) {
mLastWallpaperY = mWallpaperTarget.mWallpaperY;
mLastWallpaperYStep = mWallpaperTarget.mWallpaperYStep;
@@ -804,8 +805,11 @@ class WallpaperController {
* we'll have conflicts and break the "depth system" mental model.
*/
private void computeLastWallpaperZoomOut() {
- mLastWallpaperZoomOut = 0;
- mDisplayContent.forAllWindows(mComputeMaxZoomOutFunction, true);
+ if (mShouldUpdateZoom) {
+ mLastWallpaperZoomOut = 0;
+ mDisplayContent.forAllWindows(mComputeMaxZoomOutFunction, true);
+ mShouldUpdateZoom = false;
+ }
}
private float zoomOutToScale(float zoom) {
diff --git a/services/core/java/com/android/server/wm/Watermark.java b/services/core/java/com/android/server/wm/Watermark.java
index 4e1b2177c87c..3d49ebe306e6 100644
--- a/services/core/java/com/android/server/wm/Watermark.java
+++ b/services/core/java/com/android/server/wm/Watermark.java
@@ -29,6 +29,7 @@ import android.util.DisplayMetrics;
import android.util.Log;
import android.util.TypedValue;
import android.view.Display;
+import android.view.InputWindowHandle;
import android.view.Surface;
import android.view.Surface.OutOfResourcesException;
import android.view.SurfaceControl;
@@ -124,6 +125,8 @@ class Watermark {
t.setLayer(ctrl, WindowManagerService.TYPE_LAYER_MULTIPLIER * 100)
.setPosition(ctrl, 0, 0)
.show(ctrl);
+ // Ensure we aren't considered as obscuring for Input purposes.
+ InputMonitor.setTrustedOverlayInputInfo(ctrl, t, dc.getDisplayId(), "Watermark");
mSurface.copyFrom(ctrl);
} catch (OutOfResourcesException e) {
}
diff --git a/services/core/java/com/android/server/wm/WindowContainer.java b/services/core/java/com/android/server/wm/WindowContainer.java
index 46680662c030..90156fd4f475 100644
--- a/services/core/java/com/android/server/wm/WindowContainer.java
+++ b/services/core/java/com/android/server/wm/WindowContainer.java
@@ -1165,15 +1165,12 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer<
}
mOrientation = orientation;
- final int configOrientation = getRequestedConfigurationOrientation();
- if (getRequestedOverrideConfiguration().orientation != configOrientation) {
- mTmpConfig.setTo(getRequestedOverrideConfiguration());
- mTmpConfig.orientation = configOrientation;
- onRequestedOverrideConfigurationChanged(mTmpConfig);
- }
-
final WindowContainer parent = getParent();
if (parent != null) {
+ if (getConfiguration().orientation != getRequestedConfigurationOrientation()) {
+ // Resolve the requested orientation.
+ onConfigurationChanged(parent.getConfiguration());
+ }
onDescendantOrientationChanged(freezeDisplayToken, requestingContainer);
}
}
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index f34510e2104a..0590288a7f8b 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -3848,6 +3848,11 @@ public class WindowManagerService extends IWindowManager.Stub
final boolean rotationChanged = displayContent.updateRotationUnchecked();
Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
+ if (rotationChanged) {
+ mAtmService.getTaskChangeNotificationController()
+ .notifyOnActivityRotation(displayContent.mDisplayId);
+ }
+
if (!rotationChanged || forceRelayout) {
displayContent.setLayoutNeeded();
layoutNeeded = true;
@@ -5611,11 +5616,6 @@ public class WindowManagerService extends IWindowManager.Stub
mLatencyTracker.onActionStart(ACTION_ROTATE_SCREEN);
mExitAnimId = exitAnim;
mEnterAnimId = enterAnim;
- ScreenRotationAnimation screenRotationAnimation =
- displayContent.getRotationAnimation();
- if (screenRotationAnimation != null) {
- screenRotationAnimation.kill();
- }
displayContent.updateDisplayInfo();
final int originalRotation = overrideOriginalRotation != ROTATION_UNDEFINED
@@ -7623,8 +7623,12 @@ public class WindowManagerService extends IWindowManager.Stub
if (imeTarget == null) {
return;
}
- imeTarget = imeTarget.getImeControlTarget();
- imeTarget.getDisplayContent().getInsetsStateController().getImeSourceProvider()
+ imeTarget = imeTarget.getImeControlTarget().getWindow();
+ // If InsetsControlTarget doesn't have a window, its using remoteControlTarget which
+ // is controlled by default display
+ final DisplayContent dc = imeTarget != null
+ ? imeTarget.getDisplayContent() : getDefaultDisplayContentLocked();
+ dc.getInsetsStateController().getImeSourceProvider()
.scheduleShowImePostLayout(imeTarget);
}
}
@@ -7637,7 +7641,9 @@ public class WindowManagerService extends IWindowManager.Stub
// The target window no longer exists.
return;
}
- final DisplayContent dc = imeTarget.getImeControlTarget().getDisplayContent();
+ imeTarget = imeTarget.getImeControlTarget().getWindow();
+ final DisplayContent dc = imeTarget != null
+ ? imeTarget.getDisplayContent() : getDefaultDisplayContentLocked();
// If there was a pending IME show(), reset it as IME has been
// requested to be hidden.
dc.getInsetsStateController().getImeSourceProvider().abortShowImePostLayout();
diff --git a/services/core/java/com/android/server/wm/WindowProcessController.java b/services/core/java/com/android/server/wm/WindowProcessController.java
index 2ec6df5878ef..29cf1776df9c 100644
--- a/services/core/java/com/android/server/wm/WindowProcessController.java
+++ b/services/core/java/com/android/server/wm/WindowProcessController.java
@@ -1007,8 +1007,11 @@ public class WindowProcessController extends ConfigurationContainer<Configuratio
}
void updateProcessInfo(boolean updateServiceConnectionActivities, boolean activityChange,
- boolean updateOomAdj) {
+ boolean updateOomAdj, boolean addPendingTopUid) {
if (mListener == null) return;
+ if (addPendingTopUid) {
+ mAtm.mAmInternal.addPendingTopUid(mUid, mPid);
+ }
// Posting on handler so WM lock isn't held when we call into AM.
final Message m = PooledLambda.obtainMessage(WindowProcessListener::updateProcessInfo,
mListener, updateServiceConnectionActivities, activityChange, updateOomAdj);
@@ -1068,7 +1071,7 @@ public class WindowProcessController extends ConfigurationContainer<Configuratio
}
// update ActivityManagerService.PendingStartActivityUids list.
if (topProcessState == ActivityManager.PROCESS_STATE_TOP) {
- mAtm.mAmInternal.updatePendingTopUid(mUid, true);
+ mAtm.mAmInternal.addPendingTopUid(mUid, mPid);
}
// Posting the message at the front of queue so WM lock isn't held when we call into AM,
// and the process state of starting activity can be updated quicker which will give it a
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index 46d6009b9ab8..fe3ee50c34c5 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -21,6 +21,7 @@ import static android.app.AppOpsManager.MODE_ALLOWED;
import static android.app.AppOpsManager.MODE_DEFAULT;
import static android.app.AppOpsManager.OP_NONE;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_DREAM;
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
import static android.app.WindowConfiguration.isSplitScreenWindowingMode;
import static android.content.res.Configuration.ORIENTATION_LANDSCAPE;
import static android.os.PowerManager.DRAW_WAKE_LOCK;
@@ -3757,6 +3758,12 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
if (!inSplitScreenWindowingMode() && !inFreeformWindowingMode()) {
return false;
}
+ // TODO(157912944): formalize drag-resizing so that exceptions aren't hardcoded like this
+ if (task.getActivityType() == ACTIVITY_TYPE_HOME) {
+ // The current sys-ui implementations never live-resize home, so to prevent WSA from
+ // creating/destroying surfaces (which messes up sync-transactions), skip HOME tasks.
+ return false;
+ }
if (mAttrs.width != MATCH_PARENT || mAttrs.height != MATCH_PARENT) {
// Floating windows never enter drag resize mode.
return false;
@@ -5397,10 +5404,10 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
* {@link android.view.inputmethod.InputMethodManager#showSoftInput(View, int)} is unknown,
* use {@link DisplayContent#getImeControlTarget()} instead.
*
- * @return {@link WindowState} of host that controls the IME.
+ * @return {@link InsetsControlTarget} of host that controls the IME.
* When window is doesn't have a parent, it is returned as-is.
*/
- WindowState getImeControlTarget() {
+ InsetsControlTarget getImeControlTarget() {
final DisplayContent dc = getDisplayContent();
final WindowState parentWindow = dc.getParentWindow();
@@ -5783,10 +5790,10 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
// be invoked and we need to invoke it ourself.
if (mLocalSyncId >= 0) {
mBLASTSyncEngine.setReady(mLocalSyncId);
- } else {
- mWaitingListener.onTransactionReady(mWaitingSyncId, mBLASTSyncTransaction);
+ return mWinAnimator.finishDrawingLocked(null);
}
+ mWaitingListener.onTransactionReady(mWaitingSyncId, mBLASTSyncTransaction);
mUsingBLASTSyncTransaction = false;
mWaitingSyncId = 0;
diff --git a/services/core/java/com/android/server/wm/WindowStateAnimator.java b/services/core/java/com/android/server/wm/WindowStateAnimator.java
index 42c21930bdf7..c0252363a159 100644
--- a/services/core/java/com/android/server/wm/WindowStateAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowStateAnimator.java
@@ -418,25 +418,25 @@ class WindowStateAnimator {
if (!mDestroyPreservedSurfaceUponRedraw) {
return;
}
- if (mSurfaceController != null) {
- if (mPendingDestroySurface != null) {
- // If we are preserving a surface but we aren't relaunching that means
- // we are just doing an in-place switch. In that case any SurfaceFlinger side
- // child layers need to be reparented to the new surface to make this
- // transparent to the app.
- if (mWin.mActivityRecord == null || mWin.mActivityRecord.isRelaunching() == false) {
- mPostDrawTransaction.reparentChildren(
- mPendingDestroySurface.getClientViewRootSurface(),
- mSurfaceController.mSurfaceControl).apply();
- }
- }
+
+ // If we are preserving a surface but we aren't relaunching that means
+ // we are just doing an in-place switch. In that case any SurfaceFlinger side
+ // child layers need to be reparented to the new surface to make this
+ // transparent to the app.
+ // If the children are detached, we don't want to reparent them to the new surface.
+ // Instead let the children get removed when the old surface is deleted.
+ if (mSurfaceController != null && mPendingDestroySurface != null && !mChildrenDetached
+ && (mWin.mActivityRecord == null || !mWin.mActivityRecord.isRelaunching())) {
+ mPostDrawTransaction.reparentChildren(
+ mPendingDestroySurface.getClientViewRootSurface(),
+ mSurfaceController.mSurfaceControl).apply();
}
destroyDeferredSurfaceLocked();
mDestroyPreservedSurfaceUponRedraw = false;
}
- void markPreservedSurfaceForDestroy() {
+ private void markPreservedSurfaceForDestroy() {
if (mDestroyPreservedSurfaceUponRedraw
&& !mService.mDestroyPreservedSurface.contains(mWin)) {
mService.mDestroyPreservedSurface.add(mWin);
@@ -1363,9 +1363,13 @@ class WindowStateAnimator {
if (mPendingDestroySurface != null && mDestroyPreservedSurfaceUponRedraw) {
final SurfaceControl pendingSurfaceControl = mPendingDestroySurface.mSurfaceControl;
mPostDrawTransaction.reparent(pendingSurfaceControl, null);
- mPostDrawTransaction.reparentChildren(
- mPendingDestroySurface.getClientViewRootSurface(),
- mSurfaceController.mSurfaceControl);
+ // If the children are detached, we don't want to reparent them to the new surface.
+ // Instead let the children get removed when the old surface is deleted.
+ if (!mChildrenDetached) {
+ mPostDrawTransaction.reparentChildren(
+ mPendingDestroySurface.getClientViewRootSurface(),
+ mSurfaceController.mSurfaceControl);
+ }
}
SurfaceControl.mergeToGlobalTransaction(mPostDrawTransaction);
@@ -1593,6 +1597,12 @@ class WindowStateAnimator {
mSurfaceController.detachChildren();
}
mChildrenDetached = true;
+ // If the children are detached, it means the app is exiting. We don't want to tear the
+ // content down too early, otherwise we could end up with a flicker. By preserving the
+ // current surface, we ensure the content remains on screen until the window is completely
+ // removed. It also ensures that the old surface is cleaned up when started again since it
+ // forces mSurfaceController to be set to null.
+ preserveSurfaceLocked();
}
void setOffsetPositionForStackResize(boolean offsetPositionForStackResize) {
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index f1064d153814..10ad07cff847 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -2616,6 +2616,8 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
mSetupContentObserver = new SetupContentObserver(mHandler);
mUserManagerInternal.addUserRestrictionsListener(new RestrictionsListener(mContext));
+
+ loadOwners();
}
/**
@@ -2676,12 +2678,23 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
}
}
+ /**
+ * Load information about device and profile owners of the device, populating mOwners and
+ * pushing owner info to other system services. This is called at a fairly early stage of
+ * system server initialiation (via DevicePolicyManagerService's ctor), so care should to
+ * be taken to not interact with system services that are initialiated after DPMS.
+ * onLockSettingsReady() is a safer place to do initialization work not critical during
+ * the first boot stage.
+ * Note this only loads the list of owners, and not their actual policy (DevicePolicyData).
+ * The policy is normally loaded lazily when it's first accessed. In several occasions
+ * the list of owners is necessary for providing callers with aggregated policies across
+ * multiple owners, hence the owner list is loaded as part of DPMS's construction here.
+ */
void loadOwners() {
synchronized (getLockObject()) {
mOwners.load();
setDeviceOwnershipSystemPropertyLocked();
findOwnerComponentIfNecessaryLocked();
- migrateUserRestrictionsIfNecessaryLocked();
// TODO PO may not have a class name either due to b/17652534. Address that too.
updateDeviceOwnerLocked();
@@ -2742,7 +2755,8 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
Slog.i(LOG_TAG, "Giving the PO additional power...");
markProfileOwnerOnOrganizationOwnedDeviceUncheckedLocked(poAdminComponent, poUserId);
Slog.i(LOG_TAG, "Migrating DO policies to PO...");
- moveDoPoliciesToProfileParentAdmin(doAdmin, poAdmin.getParentActiveAdmin());
+ moveDoPoliciesToProfileParentAdminLocked(doAdmin, poAdmin.getParentActiveAdmin());
+ migratePersonalAppSuspensionLocked(doUserId, poUserId, poAdmin);
saveSettingsLocked(poUserId);
Slog.i(LOG_TAG, "Clearing the DO...");
final ComponentName doAdminReceiver = doAdmin.info.getComponent();
@@ -2762,6 +2776,25 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
.write();
}
+ @GuardedBy("getLockObject()")
+ private void migratePersonalAppSuspensionLocked(
+ int doUserId, int poUserId, ActiveAdmin poAdmin) {
+ final PackageManagerInternal pmi = mInjector.getPackageManagerInternal();
+ if (!pmi.isSuspendingAnyPackages(PLATFORM_PACKAGE_NAME, doUserId)) {
+ Slog.i(LOG_TAG, "DO is not suspending any apps.");
+ return;
+ }
+
+ if (getTargetSdk(poAdmin.info.getPackageName(), poUserId) >= Build.VERSION_CODES.R) {
+ Slog.i(LOG_TAG, "PO is targeting R+, keeping personal apps suspended.");
+ getUserData(doUserId).mAppsSuspended = true;
+ poAdmin.mSuspendPersonalApps = true;
+ } else {
+ Slog.i(LOG_TAG, "PO isn't targeting R+, unsuspending personal apps.");
+ pmi.unsuspendForSuspendingPackage(PLATFORM_PACKAGE_NAME, doUserId);
+ }
+ }
+
private void uninstallOrDisablePackage(String packageName, int userHandle) {
final ApplicationInfo appInfo;
try {
@@ -2803,7 +2836,9 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
pi.uninstall(packageName, 0 /* flags */, new IntentSender((IIntentSender) mLocalSender));
}
- private void moveDoPoliciesToProfileParentAdmin(ActiveAdmin doAdmin, ActiveAdmin parentAdmin) {
+ @GuardedBy("getLockObject()")
+ private void moveDoPoliciesToProfileParentAdminLocked(
+ ActiveAdmin doAdmin, ActiveAdmin parentAdmin) {
// The following policies can be already controlled via parent instance, skip if so.
if (parentAdmin.mPasswordPolicy.quality == PASSWORD_QUALITY_UNSPECIFIED) {
parentAdmin.mPasswordPolicy = doAdmin.mPasswordPolicy;
@@ -4104,8 +4139,10 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
}
private void onLockSettingsReady() {
+ synchronized (getLockObject()) {
+ migrateUserRestrictionsIfNecessaryLocked();
+ }
getUserData(UserHandle.USER_SYSTEM);
- loadOwners();
cleanUpOldUsers();
maybeSetDefaultProfileOwnerUserRestrictions();
handleStartUser(UserHandle.USER_SYSTEM);
@@ -16132,25 +16169,34 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
}
Slog.i(LOG_TAG, String.format("%s personal apps for user %d",
suspended ? "Suspending" : "Unsuspending", userId));
+
+ if (suspended) {
+ suspendPersonalAppsInPackageManager(userId);
+ } else {
+ mInjector.getPackageManagerInternal().unsuspendForSuspendingPackage(
+ PLATFORM_PACKAGE_NAME, userId);
+ }
+
+ synchronized (getLockObject()) {
+ getUserData(userId).mAppsSuspended = suspended;
+ saveSettingsLocked(userId);
+ }
+ }
+
+ private void suspendPersonalAppsInPackageManager(int userId) {
mInjector.binderWithCleanCallingIdentity(() -> {
try {
final String[] appsToSuspend = mInjector.getPersonalAppsForSuspension(userId);
- final String[] failedPackages = mIPackageManager.setPackagesSuspendedAsUser(
- appsToSuspend, suspended, null, null, null, PLATFORM_PACKAGE_NAME, userId);
- if (!ArrayUtils.isEmpty(failedPackages)) {
- Slog.wtf(LOG_TAG, String.format("Failed to %s packages: %s",
- suspended ? "suspend" : "unsuspend", String.join(",", failedPackages)));
+ final String[] failedApps = mIPackageManager.setPackagesSuspendedAsUser(
+ appsToSuspend, true, null, null, null, PLATFORM_PACKAGE_NAME, userId);
+ if (!ArrayUtils.isEmpty(failedApps)) {
+ Slog.wtf(LOG_TAG, "Failed to suspend apps: " + String.join(",", failedApps));
}
} catch (RemoteException re) {
// Shouldn't happen.
Slog.e(LOG_TAG, "Failed talking to the package manager", re);
}
});
-
- synchronized (getLockObject()) {
- getUserData(userId).mAppsSuspended = suspended;
- saveSettingsLocked(userId);
- }
}
@GuardedBy("getLockObject()")
diff --git a/services/tests/PackageManagerServiceTests/host/Android.bp b/services/tests/PackageManagerServiceTests/host/Android.bp
new file mode 100644
index 000000000000..dad001b52b15
--- /dev/null
+++ b/services/tests/PackageManagerServiceTests/host/Android.bp
@@ -0,0 +1,33 @@
+// 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.
+
+java_test_host {
+ name: "PackageManagerServiceHostTests",
+ srcs: ["src/**/*.kt"],
+ libs: [
+ "tradefed",
+ "junit",
+ "truth-prebuilt",
+ ],
+ static_libs: [
+ "frameworks-base-hostutils",
+ ],
+ test_suites: ["general-tests"],
+ java_resources: [
+ ":PackageManagerDummyAppVersion1",
+ ":PackageManagerDummyAppVersion2",
+ ":PackageManagerDummyAppVersion3",
+ ":PackageManagerDummyAppOriginalOverride",
+ ]
+}
diff --git a/services/tests/PackageManagerServiceTests/host/AndroidTest.xml b/services/tests/PackageManagerServiceTests/host/AndroidTest.xml
new file mode 100644
index 000000000000..dc8c8113fac2
--- /dev/null
+++ b/services/tests/PackageManagerServiceTests/host/AndroidTest.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ 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.
+ -->
+
+<configuration description="Test module config for PackageManagerServiceHostTests">
+ <option name="test-tag" value="PackageManagerServiceHostTests" />
+
+ <target_preparer class="com.android.tradefed.targetprep.RootTargetPreparer"/>
+
+ <test class="com.android.tradefed.testtype.HostTest">
+ <option name="jar" value="PackageManagerServiceHostTests.jar" />
+ </test>
+</configuration>
diff --git a/services/tests/PackageManagerServiceTests/host/src/com/android/server/pm/test/HostUtils.kt b/services/tests/PackageManagerServiceTests/host/src/com/android/server/pm/test/HostUtils.kt
new file mode 100644
index 000000000000..4927c45550b5
--- /dev/null
+++ b/services/tests/PackageManagerServiceTests/host/src/com/android/server/pm/test/HostUtils.kt
@@ -0,0 +1,46 @@
+/*
+ * 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.server.pm.test
+
+import com.android.internal.util.test.SystemPreparer
+import com.android.tradefed.device.ITestDevice
+import java.io.File
+
+internal fun SystemPreparer.pushApk(file: String, partition: Partition) =
+ pushResourceFile(file, HostUtils.makePathForApk(file, partition))
+
+internal fun SystemPreparer.deleteApk(file: String, partition: Partition) =
+ deleteFile(partition.baseFolder.resolve(file.removeSuffix(".apk")).toString())
+
+internal object HostUtils {
+
+ fun getDataDir(device: ITestDevice, pkgName: String) =
+ device.executeShellCommand("dumpsys package $pkgName")
+ .lineSequence()
+ .map(String::trim)
+ .single { it.startsWith("dataDir=") }
+ .removePrefix("dataDir=")
+
+ fun makePathForApk(fileName: String, partition: Partition) =
+ makePathForApk(File(fileName), partition)
+
+ fun makePathForApk(file: File, partition: Partition) =
+ partition.baseFolder
+ .resolve(file.nameWithoutExtension)
+ .resolve(file.name)
+ .toString()
+}
diff --git a/services/tests/PackageManagerServiceTests/host/src/com/android/server/pm/test/OriginalPackageMigrationTest.kt b/services/tests/PackageManagerServiceTests/host/src/com/android/server/pm/test/OriginalPackageMigrationTest.kt
new file mode 100644
index 000000000000..90494c591363
--- /dev/null
+++ b/services/tests/PackageManagerServiceTests/host/src/com/android/server/pm/test/OriginalPackageMigrationTest.kt
@@ -0,0 +1,98 @@
+/*
+ * 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.server.pm.test
+
+import com.android.internal.util.test.SystemPreparer
+import com.android.tradefed.testtype.DeviceJUnit4ClassRunner
+import com.android.tradefed.testtype.junit4.BaseHostJUnit4Test
+import com.google.common.truth.Truth.assertThat
+import org.junit.ClassRule
+import org.junit.Rule
+import org.junit.Test
+import org.junit.rules.RuleChain
+import org.junit.rules.TemporaryFolder
+import org.junit.runner.RunWith
+
+@RunWith(DeviceJUnit4ClassRunner::class)
+class OriginalPackageMigrationTest : BaseHostJUnit4Test() {
+
+ companion object {
+ private const val TEST_PKG_NAME = "com.android.server.pm.test.dummy_app"
+ private const val VERSION_ONE = "PackageManagerDummyAppVersion1.apk"
+ private const val VERSION_TWO = "PackageManagerDummyAppVersion2.apk"
+ private const val VERSION_THREE = "PackageManagerDummyAppVersion3.apk"
+ private const val NEW_PKG = "PackageManagerDummyAppOriginalOverride.apk"
+
+ @get:ClassRule
+ val deviceRebootRule = SystemPreparer.TestRuleDelegate(true)
+ }
+
+ private val tempFolder = TemporaryFolder()
+ private val preparer: SystemPreparer = SystemPreparer(tempFolder,
+ SystemPreparer.RebootStrategy.START_STOP, deviceRebootRule) { this.device }
+
+ @get:Rule
+ val rules = RuleChain.outerRule(tempFolder).around(preparer)!!
+
+ @Test
+ fun lowerVersion() {
+ runForApk(VERSION_ONE)
+ }
+
+ @Test
+ fun sameVersion() {
+ runForApk(VERSION_TWO)
+ }
+
+ @Test
+ fun higherVersion() {
+ runForApk(VERSION_THREE)
+ }
+
+ // A bug was found where renamed the package during parsing was leading to an invalid version
+ // code check at scan time. A lower version package was being dropped after reboot. To test
+ // this, the override APK is defined as versionCode 2 and the original package is given
+ // versionCode 1, 2, and 3 from the other methods.
+ private fun runForApk(apk: String) {
+ preparer.pushApk(apk, Partition.SYSTEM)
+ .reboot()
+
+ device.getAppPackageInfo(TEST_PKG_NAME).run {
+ assertThat(codePath).contains(apk.removeSuffix(".apk"))
+ }
+
+ // Ensure data is preserved by writing to the original dataDir
+ val file = tempFolder.newFile().apply { writeText("Test") }
+ device.pushFile(file, "${HostUtils.getDataDir(device, TEST_PKG_NAME)}/files/test.txt")
+
+ preparer.deleteApk(apk, Partition.SYSTEM)
+ .pushApk(NEW_PKG, Partition.SYSTEM)
+ .reboot()
+
+ device.getAppPackageInfo(TEST_PKG_NAME)
+ .run {
+ assertThat(this.toString()).isNotEmpty()
+ assertThat(codePath)
+ .contains(NEW_PKG.removeSuffix(".apk"))
+ }
+
+ // And then reading the data contents back
+ assertThat(device.pullFileContents(
+ "${HostUtils.getDataDir(device, TEST_PKG_NAME)}/files/test.txt"))
+ .isEqualTo("Test")
+ }
+}
diff --git a/services/tests/PackageManagerServiceTests/host/src/com/android/server/pm/test/Partition.kt b/services/tests/PackageManagerServiceTests/host/src/com/android/server/pm/test/Partition.kt
new file mode 100644
index 000000000000..35192a73ceda
--- /dev/null
+++ b/services/tests/PackageManagerServiceTests/host/src/com/android/server/pm/test/Partition.kt
@@ -0,0 +1,31 @@
+/*
+ * 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.server.pm.test
+
+import java.nio.file.Path
+import java.nio.file.Paths
+
+// Unfortunately no easy way to access PMS SystemPartitions, so mock them here
+internal enum class Partition(val baseFolder: Path) {
+ SYSTEM("/system/app"),
+ VENDOR("/vendor/app"),
+ PRODUCT("/product/app"),
+ SYSTEM_EXT("/system_ext/app")
+ ;
+
+ constructor(baseFolder: String) : this(Paths.get(baseFolder))
+}
diff --git a/services/tests/PackageManagerServiceTests/host/test-apps/Android.bp b/services/tests/PackageManagerServiceTests/host/test-apps/Android.bp
new file mode 100644
index 000000000000..9568faa7dfd0
--- /dev/null
+++ b/services/tests/PackageManagerServiceTests/host/test-apps/Android.bp
@@ -0,0 +1,33 @@
+// 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.
+
+android_test_helper_app {
+ name: "PackageManagerDummyAppVersion1",
+ manifest: "AndroidManifestVersion1.xml"
+}
+
+android_test_helper_app {
+ name: "PackageManagerDummyAppVersion2",
+ manifest: "AndroidManifestVersion2.xml"
+}
+
+android_test_helper_app {
+ name: "PackageManagerDummyAppVersion3",
+ manifest: "AndroidManifestVersion3.xml"
+}
+
+android_test_helper_app {
+ name: "PackageManagerDummyAppOriginalOverride",
+ manifest: "AndroidManifestOriginalOverride.xml"
+}
diff --git a/services/tests/PackageManagerServiceTests/host/test-apps/AndroidManifestOriginalOverride.xml b/services/tests/PackageManagerServiceTests/host/test-apps/AndroidManifestOriginalOverride.xml
new file mode 100644
index 000000000000..f16e1bc8a927
--- /dev/null
+++ b/services/tests/PackageManagerServiceTests/host/test-apps/AndroidManifestOriginalOverride.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ 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.
+ -->
+<manifest
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.server.pm.test.dummy_app.override"
+ android:versionCode="2"
+ >
+
+ <original-package android:name="com.android.server.pm.test.dummy_app"/>
+
+</manifest>
diff --git a/services/tests/PackageManagerServiceTests/host/test-apps/AndroidManifestVersion1.xml b/services/tests/PackageManagerServiceTests/host/test-apps/AndroidManifestVersion1.xml
new file mode 100644
index 000000000000..d772050d7fd0
--- /dev/null
+++ b/services/tests/PackageManagerServiceTests/host/test-apps/AndroidManifestVersion1.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ 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.
+ -->
+<manifest
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.server.pm.test.dummy_app"
+ android:versionCode="1"
+ />
diff --git a/services/tests/PackageManagerServiceTests/host/test-apps/AndroidManifestVersion2.xml b/services/tests/PackageManagerServiceTests/host/test-apps/AndroidManifestVersion2.xml
new file mode 100644
index 000000000000..53f836b222e6
--- /dev/null
+++ b/services/tests/PackageManagerServiceTests/host/test-apps/AndroidManifestVersion2.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ 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.
+ -->
+<manifest
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.server.pm.test.dummy_app"
+ android:versionCode="2"
+ />
diff --git a/services/tests/PackageManagerServiceTests/host/test-apps/AndroidManifestVersion3.xml b/services/tests/PackageManagerServiceTests/host/test-apps/AndroidManifestVersion3.xml
new file mode 100644
index 000000000000..90ca9d0ac02c
--- /dev/null
+++ b/services/tests/PackageManagerServiceTests/host/test-apps/AndroidManifestVersion3.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ 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.
+ -->
+<manifest
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.server.pm.test.dummy_app"
+ android:versionCode="3"
+ />
diff --git a/services/tests/mockingservicestests/Android.bp b/services/tests/mockingservicestests/Android.bp
index ff34ebd8aa9d..b4e0f10f14b0 100644
--- a/services/tests/mockingservicestests/Android.bp
+++ b/services/tests/mockingservicestests/Android.bp
@@ -21,7 +21,7 @@ android_test {
"services.core",
"services.net",
"service-jobscheduler",
- "service-permission",
+ "service-permission.impl",
"service-blobstore",
"androidx.test.runner",
"androidx.test.ext.truth",
diff --git a/services/tests/mockingservicestests/src/com/android/server/location/UserInfoHelperTest.java b/services/tests/mockingservicestests/src/com/android/server/location/UserInfoHelperTest.java
index 71e79b331cae..56727e81bda5 100644
--- a/services/tests/mockingservicestests/src/com/android/server/location/UserInfoHelperTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/location/UserInfoHelperTest.java
@@ -16,34 +16,23 @@
package com.android.server.location;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
-import static com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession;
import static com.google.common.truth.Truth.assertThat;
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.anyInt;
-import static org.mockito.ArgumentMatchers.isNull;
-import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.never;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
+import static org.mockito.MockitoAnnotations.initMocks;
-import android.app.ActivityManager;
-import android.content.BroadcastReceiver;
+import android.app.ActivityManagerInternal;
import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.content.pm.UserInfo;
-import android.os.Handler;
-import android.os.UserHandle;
import android.os.UserManager;
import android.platform.test.annotations.Presubmit;
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
-import com.android.dx.mockito.inline.extended.StaticMockitoSession;
+import com.android.server.LocalServices;
import com.android.server.location.UserInfoHelper.UserListener;
import org.junit.After;
@@ -51,16 +40,18 @@ import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
-import org.mockito.quality.Strictness;
-
-import java.util.ArrayList;
-import java.util.List;
@Presubmit
@SmallTest
@RunWith(AndroidJUnit4.class)
public class UserInfoHelperTest {
+ private static class TestUserInfoHelper extends UserInfoHelper {
+ TestUserInfoHelper(Context context) {
+ super(context);
+ }
+ }
+
private static final int USER1_ID = 1;
private static final int USER1_MANAGED_ID = 11;
private static final int[] USER1_PROFILES = new int[]{USER1_ID, USER1_MANAGED_ID};
@@ -70,69 +61,30 @@ public class UserInfoHelperTest {
@Mock private Context mContext;
@Mock private UserManager mUserManager;
+ @Mock private ActivityManagerInternal mActivityManagerInternal;
- private StaticMockitoSession mMockingSession;
- private List<BroadcastReceiver> mBroadcastReceivers = new ArrayList<>();
-
- private UserInfoHelper mHelper;
+ private TestUserInfoHelper mHelper;
@Before
public void setUp() {
- mMockingSession = mockitoSession()
- .initMocks(this)
- .spyStatic(ActivityManager.class)
- .strictness(Strictness.WARN)
- .startMocking();
+ initMocks(this);
+ LocalServices.addService(ActivityManagerInternal.class, mActivityManagerInternal);
doReturn(mUserManager).when(mContext).getSystemService(UserManager.class);
- doAnswer(invocation -> {
- mBroadcastReceivers.add(invocation.getArgument(0));
- return null;
- }).when(mContext).registerReceiverAsUser(any(BroadcastReceiver.class), any(
- UserHandle.class), any(IntentFilter.class), isNull(), any(Handler.class));
- doReturn(USER1_PROFILES).when(mUserManager).getProfileIdsWithDisabled(USER1_ID);
- doReturn(USER2_PROFILES).when(mUserManager).getProfileIdsWithDisabled(USER2_ID);
- doReturn(new UserInfo(USER1_ID, "", 0)).when(mUserManager).getProfileParent(
- USER1_MANAGED_ID);
- doReturn(new UserInfo(USER2_ID, "", 0)).when(mUserManager).getProfileParent(
- USER2_MANAGED_ID);
-
- doReturn(USER1_ID).when(ActivityManager::getCurrentUser);
-
- mHelper = new UserInfoHelper(mContext);
+
+ doReturn(USER1_PROFILES).when(mUserManager).getEnabledProfileIds(USER1_ID);
+ doReturn(USER2_PROFILES).when(mUserManager).getEnabledProfileIds(USER2_ID);
+ doReturn(true).when(mActivityManagerInternal).isCurrentProfile(USER1_ID);
+ doReturn(true).when(mActivityManagerInternal).isCurrentProfile(USER1_MANAGED_ID);
+ doReturn(USER1_PROFILES).when(mActivityManagerInternal).getCurrentProfileIds();
+
+ mHelper = new TestUserInfoHelper(mContext);
mHelper.onSystemReady();
}
@After
public void tearDown() {
- if (mMockingSession != null) {
- mMockingSession.finishMocking();
- }
- }
-
- private void switchUser(int userId) {
- doReturn(userId).when(ActivityManager::getCurrentUser);
- Intent intent = new Intent(Intent.ACTION_USER_SWITCHED).putExtra(Intent.EXTRA_USER_HANDLE,
- userId);
- for (BroadcastReceiver broadcastReceiver : mBroadcastReceivers) {
- broadcastReceiver.onReceive(mContext, intent);
- }
- }
-
- private void startUser(int userId) {
- Intent intent = new Intent(Intent.ACTION_USER_STARTED).putExtra(Intent.EXTRA_USER_HANDLE,
- userId);
- for (BroadcastReceiver broadcastReceiver : mBroadcastReceivers) {
- broadcastReceiver.onReceive(mContext, intent);
- }
- }
-
- private void stopUser(int userId) {
- Intent intent = new Intent(Intent.ACTION_USER_STOPPED).putExtra(Intent.EXTRA_USER_HANDLE,
- userId);
- for (BroadcastReceiver broadcastReceiver : mBroadcastReceivers) {
- broadcastReceiver.onReceive(mContext, intent);
- }
+ LocalServices.removeServiceForTest(ActivityManagerInternal.class);
}
@Test
@@ -140,16 +92,21 @@ public class UserInfoHelperTest {
UserListener listener = mock(UserListener.class);
mHelper.addListener(listener);
- switchUser(USER1_ID);
- verify(listener, never()).onUserChanged(anyInt(), anyInt());
-
- switchUser(USER2_ID);
- verify(listener, times(1)).onUserChanged(USER1_ID, UserListener.USER_SWITCHED);
- verify(listener, times(1)).onUserChanged(USER2_ID, UserListener.USER_SWITCHED);
-
- switchUser(USER1_ID);
- verify(listener, times(2)).onUserChanged(USER1_ID, UserListener.USER_SWITCHED);
- verify(listener, times(2)).onUserChanged(USER2_ID, UserListener.USER_SWITCHED);
+ mHelper.dispatchOnCurrentUserChanged(USER1_ID, USER2_ID);
+ verify(listener, times(1)).onUserChanged(USER1_ID, UserListener.CURRENT_USER_CHANGED);
+ verify(listener, times(1)).onUserChanged(USER1_MANAGED_ID,
+ UserListener.CURRENT_USER_CHANGED);
+ verify(listener, times(1)).onUserChanged(USER2_ID, UserListener.CURRENT_USER_CHANGED);
+ verify(listener, times(1)).onUserChanged(USER2_MANAGED_ID,
+ UserListener.CURRENT_USER_CHANGED);
+
+ mHelper.dispatchOnCurrentUserChanged(USER2_ID, USER1_ID);
+ verify(listener, times(2)).onUserChanged(USER2_ID, UserListener.CURRENT_USER_CHANGED);
+ verify(listener, times(2)).onUserChanged(USER2_MANAGED_ID,
+ UserListener.CURRENT_USER_CHANGED);
+ verify(listener, times(2)).onUserChanged(USER1_ID, UserListener.CURRENT_USER_CHANGED);
+ verify(listener, times(2)).onUserChanged(USER1_MANAGED_ID,
+ UserListener.CURRENT_USER_CHANGED);
}
@Test
@@ -157,11 +114,11 @@ public class UserInfoHelperTest {
UserListener listener = mock(UserListener.class);
mHelper.addListener(listener);
- startUser(USER1_ID);
+ mHelper.dispatchOnUserStarted(USER1_ID);
verify(listener).onUserChanged(USER1_ID, UserListener.USER_STARTED);
- startUser(USER2_ID);
- verify(listener).onUserChanged(USER2_ID, UserListener.USER_STARTED);
+ mHelper.dispatchOnUserStarted(USER1_MANAGED_ID);
+ verify(listener).onUserChanged(USER1_MANAGED_ID, UserListener.USER_STARTED);
}
@Test
@@ -169,24 +126,22 @@ public class UserInfoHelperTest {
UserListener listener = mock(UserListener.class);
mHelper.addListener(listener);
- stopUser(USER1_ID);
- verify(listener).onUserChanged(USER1_ID, UserListener.USER_STOPPED);
-
- stopUser(USER2_ID);
+ mHelper.dispatchOnUserStopped(USER2_ID);
verify(listener).onUserChanged(USER2_ID, UserListener.USER_STOPPED);
+
+ mHelper.dispatchOnUserStopped(USER2_MANAGED_ID);
+ verify(listener).onUserChanged(USER2_MANAGED_ID, UserListener.USER_STOPPED);
}
@Test
public void testCurrentUserIds() {
assertThat(mHelper.getCurrentUserIds()).isEqualTo(USER1_PROFILES);
- switchUser(USER2_ID);
+ doReturn(true).when(mActivityManagerInternal).isCurrentProfile(USER2_ID);
+ doReturn(true).when(mActivityManagerInternal).isCurrentProfile(USER2_MANAGED_ID);
+ doReturn(USER2_PROFILES).when(mActivityManagerInternal).getCurrentProfileIds();
assertThat(mHelper.getCurrentUserIds()).isEqualTo(USER2_PROFILES);
-
- switchUser(USER1_ID);
-
- assertThat(mHelper.getCurrentUserIds()).isEqualTo(USER1_PROFILES);
}
@Test
@@ -196,7 +151,11 @@ public class UserInfoHelperTest {
assertThat(mHelper.isCurrentUserId(USER2_ID)).isFalse();
assertThat(mHelper.isCurrentUserId(USER2_MANAGED_ID)).isFalse();
- switchUser(USER2_ID);
+ doReturn(false).when(mActivityManagerInternal).isCurrentProfile(USER1_ID);
+ doReturn(false).when(mActivityManagerInternal).isCurrentProfile(USER1_MANAGED_ID);
+ doReturn(true).when(mActivityManagerInternal).isCurrentProfile(USER2_ID);
+ doReturn(true).when(mActivityManagerInternal).isCurrentProfile(USER2_MANAGED_ID);
+ doReturn(USER2_PROFILES).when(mActivityManagerInternal).getCurrentProfileIds();
assertThat(mHelper.isCurrentUserId(USER1_ID)).isFalse();
assertThat(mHelper.isCurrentUserId(USER2_ID)).isTrue();
diff --git a/services/tests/servicestests/Android.bp b/services/tests/servicestests/Android.bp
index 40a17061c7f1..979f4e179e95 100644
--- a/services/tests/servicestests/Android.bp
+++ b/services/tests/servicestests/Android.bp
@@ -44,7 +44,7 @@ android_test {
"hamcrest-library",
"servicestests-utils",
"service-jobscheduler",
- "service-permission",
+ "service-permission.impl",
// TODO: remove once Android migrates to JUnit 4.12,
// which provides assertThrows
"testng",
diff --git a/services/tests/servicestests/assets/AppIntegrityManagerServiceImplTest/SourceStampTestApk.apk b/services/tests/servicestests/assets/AppIntegrityManagerServiceImplTest/SourceStampTestApk.apk
index 8056e0bf6e50..211e064399a8 100644
--- a/services/tests/servicestests/assets/AppIntegrityManagerServiceImplTest/SourceStampTestApk.apk
+++ b/services/tests/servicestests/assets/AppIntegrityManagerServiceImplTest/SourceStampTestApk.apk
Binary files differ
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceMigrationTest.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceMigrationTest.java
index a0b9d9d2a875..3167820f0a48 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceMigrationTest.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceMigrationTest.java
@@ -18,17 +18,24 @@ package com.android.server.devicepolicy;
import static android.os.UserHandle.USER_SYSTEM;
import static com.android.server.devicepolicy.DpmTestUtils.writeInputStreamToFile;
+import static com.android.server.pm.PackageManagerService.PLATFORM_PACKAGE_NAME;
import static org.junit.Assert.assertArrayEquals;
+import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.anyInt;
import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
+import android.app.admin.DevicePolicyManager;
import android.app.admin.DevicePolicyManagerInternal;
import android.content.ComponentName;
+import android.content.Intent;
import android.content.pm.PackageManager;
+import android.os.Build;
import android.os.Bundle;
import android.os.UserHandle;
import android.os.UserManager;
@@ -354,8 +361,7 @@ public class DevicePolicyManagerServiceMigrationTest extends DpmTestBase {
prepareAdmin1AsDo();
prepareAdminAnotherPackageAsPo(COPE_PROFILE_USER_ID);
- final DevicePolicyManagerServiceTestable dpms;
- dpms = bootDpmsUp();
+ final DevicePolicyManagerServiceTestable dpms = bootDpmsUp();
// DO should still be DO since no migration should happen.
assertTrue(dpms.mOwners.hasDeviceOwner());
@@ -364,13 +370,12 @@ public class DevicePolicyManagerServiceMigrationTest extends DpmTestBase {
@SmallTest
public void testCompMigrationAffiliated() throws Exception {
prepareAdmin1AsDo();
- prepareAdmin1AsPo(COPE_PROFILE_USER_ID);
+ prepareAdmin1AsPo(COPE_PROFILE_USER_ID, Build.VERSION_CODES.R);
// Secure lock screen is needed for password policy APIs to work.
when(getServices().lockPatternUtils.hasSecureLockScreen()).thenReturn(true);
- final DevicePolicyManagerServiceTestable dpms;
- dpms = bootDpmsUp();
+ final DevicePolicyManagerServiceTestable dpms = bootDpmsUp();
// DO should cease to be DO.
assertFalse(dpms.mOwners.hasDeviceOwner());
@@ -408,6 +413,66 @@ public class DevicePolicyManagerServiceMigrationTest extends DpmTestBase {
dpms.getProfileOwnerAdminLocked(COPE_PROFILE_USER_ID)
.getEffectiveRestrictions()
.containsKey(UserManager.DISALLOW_CONFIG_DATE_TIME));
+ assertEquals("Personal apps suspension wasn't migrated",
+ DevicePolicyManager.PERSONAL_APPS_NOT_SUSPENDED,
+ dpm.getPersonalAppsSuspendedReasons(admin1));
+ });
+ }
+
+ @SmallTest
+ public void testCompMigration_keepSuspendedAppsWhenDpcIsRPlus() throws Exception {
+ prepareAdmin1AsDo();
+ prepareAdmin1AsPo(COPE_PROFILE_USER_ID, Build.VERSION_CODES.R);
+
+ // Pretend some packages are suspended.
+ when(getServices().packageManagerInternal.isSuspendingAnyPackages(
+ PLATFORM_PACKAGE_NAME, USER_SYSTEM)).thenReturn(true);
+
+ final DevicePolicyManagerServiceTestable dpms = bootDpmsUp();
+
+ verify(getServices().packageManagerInternal, never())
+ .unsuspendForSuspendingPackage(PLATFORM_PACKAGE_NAME, USER_SYSTEM);
+
+ sendBroadcastWithUser(dpms, Intent.ACTION_USER_STARTED, USER_SYSTEM);
+
+ // Verify that actual package suspension state is not modified after user start
+ verify(getServices().packageManagerInternal, never())
+ .unsuspendForSuspendingPackage(PLATFORM_PACKAGE_NAME, USER_SYSTEM);
+ verify(getServices().ipackageManager, never()).setPackagesSuspendedAsUser(
+ any(), anyBoolean(), any(), any(), any(), any(), anyInt());
+
+ final DpmMockContext poContext = new DpmMockContext(getServices(), mRealTestContext);
+ poContext.binder.callingUid = UserHandle.getUid(COPE_PROFILE_USER_ID, COPE_ADMIN1_APP_ID);
+
+ runAsCaller(poContext, dpms, dpm -> {
+ assertEquals("Personal apps suspension wasn't migrated",
+ DevicePolicyManager.PERSONAL_APPS_SUSPENDED_EXPLICITLY,
+ dpm.getPersonalAppsSuspendedReasons(admin1));
+ });
+ }
+
+ @SmallTest
+ public void testCompMigration_unsuspendAppsWhenDpcNotRPlus() throws Exception {
+ prepareAdmin1AsDo();
+ prepareAdmin1AsPo(COPE_PROFILE_USER_ID, Build.VERSION_CODES.Q);
+
+ // Pretend some packages are suspended.
+ when(getServices().packageManagerInternal.isSuspendingAnyPackages(
+ PLATFORM_PACKAGE_NAME, USER_SYSTEM)).thenReturn(true);
+
+ final DevicePolicyManagerServiceTestable dpms = bootDpmsUp();
+
+ // Verify that apps get unsuspended.
+ verify(getServices().packageManagerInternal)
+ .unsuspendForSuspendingPackage(PLATFORM_PACKAGE_NAME, USER_SYSTEM);
+
+ final DpmMockContext poContext = new DpmMockContext(getServices(), mRealTestContext);
+ poContext.binder.callingUid = UserHandle.getUid(COPE_PROFILE_USER_ID, COPE_ADMIN1_APP_ID);
+
+ runAsCaller(poContext, dpms, dpm -> {
+ assertEquals("Personal apps weren't unsuspended",
+ DevicePolicyManager.PERSONAL_APPS_NOT_SUSPENDED,
+ dpm.getPersonalAppsSuspendedReasons(admin1));
});
}
@@ -439,22 +504,23 @@ public class DevicePolicyManagerServiceMigrationTest extends DpmTestBase {
.getAbsoluteFile());
}
- private void prepareAdmin1AsPo(int profileUserId) throws Exception {
+ private void prepareAdmin1AsPo(int profileUserId, int targetSdk) throws Exception {
preparePo(profileUserId, admin1, R.raw.comp_profile_owner_same_package,
- R.raw.comp_policies_profile_same_package, COPE_ADMIN1_APP_ID);
+ R.raw.comp_policies_profile_same_package, COPE_ADMIN1_APP_ID, targetSdk);
}
private void prepareAdminAnotherPackageAsPo(int profileUserId) throws Exception {
preparePo(profileUserId, adminAnotherPackage, R.raw.comp_profile_owner_another_package,
- R.raw.comp_policies_profile_another_package, COPE_ANOTHER_ADMIN_APP_ID);
+ R.raw.comp_policies_profile_another_package, COPE_ANOTHER_ADMIN_APP_ID,
+ Build.VERSION.SDK_INT);
}
private void preparePo(int profileUserId, ComponentName admin, int profileOwnerXmlResId,
- int policyXmlResId, int adminAppId) throws Exception {
+ int policyXmlResId, int adminAppId, int targetSdk) throws Exception {
final File profileDir = getServices().addUser(profileUserId, 0,
UserManager.USER_TYPE_PROFILE_MANAGED, USER_SYSTEM /* profile group */);
- setUpPackageManagerForFakeAdmin(
- admin, UserHandle.getUid(profileUserId, adminAppId), admin1);
+ setUpPackageManagerForFakeAdmin(admin, UserHandle.getUid(profileUserId, adminAppId),
+ /* enabledSetting =*/ null, targetSdk, admin1);
writeInputStreamToFile(getRawStream(policyXmlResId),
(new File(profileDir, "device_policies.xml")).getAbsoluteFile());
writeInputStreamToFile(getRawStream(profileOwnerXmlResId),
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 4a774898e1b5..daaabf8141ff 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
@@ -254,7 +254,7 @@ public class DevicePolicyManagerTest extends DpmTestBase {
@Override
protected void tearDown() throws Exception {
- flushTasks();
+ flushTasks(dpms);
getMockTransferMetadataManager().deleteMetadataFile();
super.tearDown();
}
@@ -4961,7 +4961,7 @@ public class DevicePolicyManagerTest extends DpmTestBase {
// CertificateMonitor.updateInstalledCertificates is called on the background thread,
// let it finish with system uid, otherwise it will throw and crash.
- flushTasks();
+ flushTasks(dpms);
mContext.binder.restoreCallingIdentity(ident);
}
@@ -5459,7 +5459,7 @@ public class DevicePolicyManagerTest extends DpmTestBase {
getServices().injectBroadcast(mServiceContext, new Intent(KeyChain.ACTION_TRUST_STORE_CHANGED)
.putExtra(Intent.EXTRA_USER_HANDLE, callerUser.getIdentifier()),
callerUser.getIdentifier());
- flushTasks();
+ flushTasks(dpms);
final List<String> ownerInstalledCaCerts = new ArrayList<>();
@@ -5486,7 +5486,7 @@ public class DevicePolicyManagerTest extends DpmTestBase {
getServices().injectBroadcast(mServiceContext, new Intent(KeyChain.ACTION_TRUST_STORE_CHANGED)
.putExtra(Intent.EXTRA_USER_HANDLE, callerUser.getIdentifier()),
callerUser.getIdentifier());
- flushTasks();
+ flushTasks(dpms);
// Verify that the CA cert is no longer reported as installed by the Device Owner / Profile
// Owner.
@@ -5530,7 +5530,7 @@ public class DevicePolicyManagerTest extends DpmTestBase {
getServices().injectBroadcast(mServiceContext, new Intent(KeyChain.ACTION_TRUST_STORE_CHANGED)
.putExtra(Intent.EXTRA_USER_HANDLE, callerUser.getIdentifier()),
callerUser.getIdentifier());
- flushTasks();
+ flushTasks(dpms);
// Removing the Profile Owner should clear the information on which CA certs were installed
runAsCaller(admin1Context, dpms, dpm -> dpm.clearProfileOwner(admin1));
@@ -6311,7 +6311,7 @@ public class DevicePolicyManagerTest extends DpmTestBase {
clearInvocations(getServices().alarmManager);
setUserUnlocked(CALLER_USER_HANDLE, false);
- sendBroadcastWithUser(Intent.ACTION_USER_STOPPED, CALLER_USER_HANDLE);
+ sendBroadcastWithUser(dpms, Intent.ACTION_USER_STOPPED, CALLER_USER_HANDLE);
// Verify the alarm was scheduled for time when the warning should be shown.
verify(getServices().alarmManager, times(1))
@@ -6325,7 +6325,7 @@ public class DevicePolicyManagerTest extends DpmTestBase {
// Pretend the alarm went off.
dpms.mMockInjector.setSystemCurrentTimeMillis(PROFILE_OFF_WARNING_TIME + 10);
- sendBroadcastWithUser(ACTION_PROFILE_OFF_DEADLINE, CALLER_USER_HANDLE);
+ sendBroadcastWithUser(dpms, ACTION_PROFILE_OFF_DEADLINE, CALLER_USER_HANDLE);
// Verify the alarm was scheduled for the actual deadline this time.
verify(getServices().alarmManager, times(1)).set(anyInt(), eq(PROFILE_OFF_DEADLINE), any());
@@ -6340,7 +6340,7 @@ public class DevicePolicyManagerTest extends DpmTestBase {
// Pretend the alarm went off.
dpms.mMockInjector.setSystemCurrentTimeMillis(PROFILE_OFF_DEADLINE + 10);
- sendBroadcastWithUser(ACTION_PROFILE_OFF_DEADLINE, CALLER_USER_HANDLE);
+ sendBroadcastWithUser(dpms, ACTION_PROFILE_OFF_DEADLINE, CALLER_USER_HANDLE);
// Verify the alarm was not set.
verifyZeroInteractions(getServices().alarmManager);
@@ -6364,10 +6364,10 @@ public class DevicePolicyManagerTest extends DpmTestBase {
mContext.binder.callingUid = DpmMockContext.SYSTEM_UID;
setUserUnlocked(CALLER_USER_HANDLE, false);
- sendBroadcastWithUser(Intent.ACTION_USER_STOPPED, CALLER_USER_HANDLE);
+ sendBroadcastWithUser(dpms, Intent.ACTION_USER_STOPPED, CALLER_USER_HANDLE);
clearInvocations(getServices().alarmManager);
setUserUnlocked(CALLER_USER_HANDLE, true);
- sendBroadcastWithUser(Intent.ACTION_USER_UNLOCKED, CALLER_USER_HANDLE);
+ sendBroadcastWithUser(dpms, Intent.ACTION_USER_UNLOCKED, CALLER_USER_HANDLE);
// Verify that the alarm got discharged.
verify(getServices().alarmManager, times(1)).cancel((PendingIntent) null);
@@ -6384,16 +6384,16 @@ public class DevicePolicyManagerTest extends DpmTestBase {
mContext.binder.callingUid = DpmMockContext.SYSTEM_UID;
setUserUnlocked(CALLER_USER_HANDLE, false);
- sendBroadcastWithUser(Intent.ACTION_USER_STOPPED, CALLER_USER_HANDLE);
+ sendBroadcastWithUser(dpms, Intent.ACTION_USER_STOPPED, CALLER_USER_HANDLE);
// Pretend the alarm went off.
dpms.mMockInjector.setSystemCurrentTimeMillis(PROFILE_OFF_WARNING_TIME + 10);
- sendBroadcastWithUser(ACTION_PROFILE_OFF_DEADLINE, CALLER_USER_HANDLE);
+ sendBroadcastWithUser(dpms, ACTION_PROFILE_OFF_DEADLINE, CALLER_USER_HANDLE);
clearInvocations(getServices().alarmManager);
clearInvocations(getServices().notificationManager);
setUserUnlocked(CALLER_USER_HANDLE, true);
- sendBroadcastWithUser(Intent.ACTION_USER_UNLOCKED, CALLER_USER_HANDLE);
+ sendBroadcastWithUser(dpms, Intent.ACTION_USER_UNLOCKED, CALLER_USER_HANDLE);
// Verify that the alarm got discharged.
verify(getServices().alarmManager, times(1)).cancel((PendingIntent) null);
@@ -6413,24 +6413,24 @@ public class DevicePolicyManagerTest extends DpmTestBase {
mContext.binder.callingUid = DpmMockContext.SYSTEM_UID;
setUserUnlocked(CALLER_USER_HANDLE, false);
- sendBroadcastWithUser(Intent.ACTION_USER_STOPPED, CALLER_USER_HANDLE);
+ sendBroadcastWithUser(dpms, Intent.ACTION_USER_STOPPED, CALLER_USER_HANDLE);
// Pretend the alarm went off after the deadline.
dpms.mMockInjector.setSystemCurrentTimeMillis(PROFILE_OFF_DEADLINE + 10);
- sendBroadcastWithUser(ACTION_PROFILE_OFF_DEADLINE, CALLER_USER_HANDLE);
+ sendBroadcastWithUser(dpms, ACTION_PROFILE_OFF_DEADLINE, CALLER_USER_HANDLE);
clearInvocations(getServices().alarmManager);
clearInvocations(getServices().notificationManager);
clearInvocations(getServices().ipackageManager);
// Pretend the user clicked on the "apps suspended" notification to turn the profile on.
- sendBroadcastWithUser(ACTION_TURN_PROFILE_ON_NOTIFICATION, CALLER_USER_HANDLE);
+ sendBroadcastWithUser(dpms, ACTION_TURN_PROFILE_ON_NOTIFICATION, CALLER_USER_HANDLE);
// Verify that the profile is turned on.
verify(getServices().userManager, times(1))
.requestQuietModeEnabled(eq(false), eq(UserHandle.of(CALLER_USER_HANDLE)));
setUserUnlocked(CALLER_USER_HANDLE, true);
- sendBroadcastWithUser(Intent.ACTION_USER_UNLOCKED, CALLER_USER_HANDLE);
+ sendBroadcastWithUser(dpms, Intent.ACTION_USER_UNLOCKED, CALLER_USER_HANDLE);
// Verify that the notification is removed (at this point DPC should show it).
verify(getServices().notificationManager, times(1))
@@ -6454,13 +6454,6 @@ public class DevicePolicyManagerTest extends DpmTestBase {
.isEqualTo(DevicePolicyManager.PERSONAL_APPS_SUSPENDED_PROFILE_TIMEOUT);
}
- private void sendBroadcastWithUser(String action, int userHandle) throws Exception {
- final Intent intent = new Intent(action);
- intent.putExtra(Intent.EXTRA_USER_HANDLE, userHandle);
- getServices().injectBroadcast(mServiceContext, intent, userHandle);
- flushTasks();
- }
-
private void setUserUnlocked(int userHandle, boolean unlocked) {
when(getServices().userManager.isUserUnlocked(eq(userHandle))).thenReturn(unlocked);
}
@@ -6471,10 +6464,6 @@ public class DevicePolicyManagerTest extends DpmTestBase {
when(getServices().userManager.isUserUnlocked()).thenReturn(true);
- // Pretend our admin handles CHECK_POLICY_COMPLIANCE intent.
- final Intent intent = new Intent(ACTION_CHECK_POLICY_COMPLIANCE);
- intent.setPackage(admin1.getPackageName());
-
doReturn(Collections.singletonList(new ResolveInfo()))
.when(getServices().packageManager).queryIntentActivitiesAsUser(
any(Intent.class), anyInt(), eq(CALLER_USER_HANDLE));
@@ -6674,12 +6663,4 @@ public class DevicePolicyManagerTest extends DpmTestBase {
return new StringParceledListSlice(Arrays.asList(s));
}
- private void flushTasks() throws Exception {
- dpms.mHandler.runWithScissors(() -> {}, 0 /*now*/);
- dpms.mBackgroundHandler.runWithScissors(() -> {}, 0 /*now*/);
-
- // We can't let exceptions happen on the background thread. Throw them here if they happen
- // so they still cause the test to fail despite being suppressed.
- getServices().rethrowBackgroundBroadcastExceptions();
- }
}
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DpmTestBase.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DpmTestBase.java
index 9a1a5fbfd186..41d54e9010d3 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DpmTestBase.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DpmTestBase.java
@@ -83,6 +83,23 @@ public abstract class DpmTestBase extends AndroidTestCase {
return mServices;
}
+ protected void sendBroadcastWithUser(DevicePolicyManagerServiceTestable dpms, String action,
+ int userHandle) throws Exception {
+ final Intent intent = new Intent(action);
+ intent.putExtra(Intent.EXTRA_USER_HANDLE, userHandle);
+ getServices().injectBroadcast(getContext(), intent, userHandle);
+ flushTasks(dpms);
+ }
+
+ protected void flushTasks(DevicePolicyManagerServiceTestable dpms) throws Exception {
+ dpms.mHandler.runWithScissors(() -> { }, 0 /*now*/);
+ dpms.mBackgroundHandler.runWithScissors(() -> { }, 0 /*now*/);
+
+ // We can't let exceptions happen on the background thread. Throw them here if they happen
+ // so they still cause the test to fail despite being suppressed.
+ getServices().rethrowBackgroundBroadcastExceptions();
+ }
+
protected interface DpmRunnable {
void run(DevicePolicyManager dpm) throws Exception;
}
@@ -180,7 +197,7 @@ public abstract class DpmTestBase extends AndroidTestCase {
* @param copyFromAdmin package information for {@code admin} will be built based on this
* component's information.
*/
- private void setUpPackageManagerForFakeAdmin(ComponentName admin, int packageUid,
+ protected void setUpPackageManagerForFakeAdmin(ComponentName admin, int packageUid,
Integer enabledSetting, Integer appTargetSdk, ComponentName copyFromAdmin)
throws Exception {
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDevicePlaybackTest.java b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDevicePlaybackTest.java
index 145e1ec56e4a..c44f12735fb5 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDevicePlaybackTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDevicePlaybackTest.java
@@ -15,6 +15,7 @@
*/
package com.android.server.hdmi;
+import static com.android.server.hdmi.Constants.ADDR_PLAYBACK_1;
import static com.android.server.hdmi.Constants.ADDR_TV;
import static com.android.server.hdmi.HdmiControlService.INITIATED_BY_ENABLE_CEC;
@@ -56,6 +57,7 @@ public class HdmiCecLocalDevicePlaybackTest {
private ArrayList<HdmiCecLocalDevice> mLocalDevices = new ArrayList<>();
private int mPlaybackPhysicalAddress;
private boolean mWokenUp;
+ private boolean mStandby;
@Mock private IPowerManager mIPowerManagerMock;
@Mock private IThermalService mIThermalServiceMock;
@@ -76,6 +78,11 @@ public class HdmiCecLocalDevicePlaybackTest {
}
@Override
+ void standby() {
+ mStandby = true;
+ }
+
+ @Override
boolean isControlEnabled() {
return true;
}
@@ -119,6 +126,132 @@ public class HdmiCecLocalDevicePlaybackTest {
mNativeWrapper.clearResultMessages();
}
+ @Test
+ public void handleRoutingChange_None() {
+ mHdmiCecLocalDevicePlayback.mPlaybackDeviceActionOnRoutingControl =
+ Constants.PLAYBACK_DEVICE_ACTION_ON_ROUTING_CONTROL_NONE;
+
+ mWokenUp = false;
+
+ HdmiCecMessage message =
+ HdmiCecMessageBuilder.buildRoutingChange(ADDR_TV, 0x0000,
+ mPlaybackPhysicalAddress);
+
+ HdmiCecMessage expectedMessage =
+ HdmiCecMessageBuilder.buildActiveSource(ADDR_PLAYBACK_1,
+ mPlaybackPhysicalAddress);
+
+ assertThat(mHdmiCecLocalDevicePlayback.handleRoutingChange(message)).isTrue();
+ mTestLooper.dispatchAll();
+ assertThat(mWokenUp).isFalse();
+ assertThat(mNativeWrapper.getResultMessages().contains(expectedMessage)).isFalse();
+ }
+
+ @Test
+ public void handleRoutingInformation_None() {
+ mHdmiCecLocalDevicePlayback.mPlaybackDeviceActionOnRoutingControl =
+ Constants.PLAYBACK_DEVICE_ACTION_ON_ROUTING_CONTROL_NONE;
+
+ mWokenUp = false;
+
+ HdmiCecMessage message =
+ HdmiCecMessageBuilder.buildRoutingInformation(ADDR_TV,
+ mPlaybackPhysicalAddress);
+
+ HdmiCecMessage expectedMessage =
+ HdmiCecMessageBuilder.buildActiveSource(ADDR_PLAYBACK_1,
+ mPlaybackPhysicalAddress);
+
+ assertThat(mHdmiCecLocalDevicePlayback.handleRoutingInformation(message)).isTrue();
+ mTestLooper.dispatchAll();
+ assertThat(mWokenUp).isFalse();
+ assertThat(mNativeWrapper.getResultMessages().contains(expectedMessage)).isFalse();
+ }
+
+ @Test
+ public void handleRoutingChange_WakeUpOnly() {
+ mHdmiCecLocalDevicePlayback.mPlaybackDeviceActionOnRoutingControl =
+ Constants.PLAYBACK_DEVICE_ACTION_ON_ROUTING_CONTROL_WAKE_UP_ONLY;
+
+ mWokenUp = false;
+
+ HdmiCecMessage message =
+ HdmiCecMessageBuilder.buildRoutingChange(ADDR_TV, 0x0000,
+ mPlaybackPhysicalAddress);
+
+ HdmiCecMessage expectedMessage =
+ HdmiCecMessageBuilder.buildActiveSource(ADDR_PLAYBACK_1,
+ mPlaybackPhysicalAddress);
+
+ assertThat(mHdmiCecLocalDevicePlayback.handleRoutingChange(message)).isTrue();
+ mTestLooper.dispatchAll();
+ assertThat(mWokenUp).isTrue();
+ assertThat(mNativeWrapper.getResultMessages().contains(expectedMessage)).isFalse();
+ }
+
+ @Test
+ public void handleRoutingInformation_WakeUpOnly() {
+ mHdmiCecLocalDevicePlayback.mPlaybackDeviceActionOnRoutingControl =
+ Constants.PLAYBACK_DEVICE_ACTION_ON_ROUTING_CONTROL_WAKE_UP_ONLY;
+
+ mWokenUp = false;
+
+ HdmiCecMessage message =
+ HdmiCecMessageBuilder.buildRoutingInformation(ADDR_TV,
+ mPlaybackPhysicalAddress);
+
+ HdmiCecMessage expectedMessage =
+ HdmiCecMessageBuilder.buildActiveSource(ADDR_PLAYBACK_1,
+ mPlaybackPhysicalAddress);
+
+ assertThat(mHdmiCecLocalDevicePlayback.handleRoutingInformation(message)).isTrue();
+ mTestLooper.dispatchAll();
+ assertThat(mWokenUp).isTrue();
+ assertThat(mNativeWrapper.getResultMessages().contains(expectedMessage)).isFalse();
+ }
+
+ @Test
+ public void handleRoutingChange_WakeUpAndSendActiveSource() {
+ mHdmiCecLocalDevicePlayback.mPlaybackDeviceActionOnRoutingControl =
+ Constants.PLAYBACK_DEVICE_ACTION_ON_ROUTING_CONTROL_WAKE_UP_AND_SEND_ACTIVE_SOURCE;
+
+ mWokenUp = false;
+
+ HdmiCecMessage message =
+ HdmiCecMessageBuilder.buildRoutingChange(ADDR_TV, 0x0000,
+ mPlaybackPhysicalAddress);
+
+ HdmiCecMessage expectedMessage =
+ HdmiCecMessageBuilder.buildActiveSource(ADDR_PLAYBACK_1,
+ mPlaybackPhysicalAddress);
+
+ assertThat(mHdmiCecLocalDevicePlayback.handleRoutingChange(message)).isTrue();
+ mTestLooper.dispatchAll();
+ assertThat(mWokenUp).isTrue();
+ assertThat(mNativeWrapper.getResultMessages()).contains(expectedMessage);
+ }
+
+ @Test
+ public void handleRoutingInformation_WakeUpAndSendActiveSource() {
+ mHdmiCecLocalDevicePlayback.mPlaybackDeviceActionOnRoutingControl =
+ Constants.PLAYBACK_DEVICE_ACTION_ON_ROUTING_CONTROL_WAKE_UP_AND_SEND_ACTIVE_SOURCE;
+
+ mWokenUp = false;
+
+ HdmiCecMessage message =
+ HdmiCecMessageBuilder.buildRoutingInformation(ADDR_TV,
+ mPlaybackPhysicalAddress);
+
+ HdmiCecMessage expectedMessage =
+ HdmiCecMessageBuilder.buildActiveSource(ADDR_PLAYBACK_1,
+ mPlaybackPhysicalAddress);
+
+ assertThat(mHdmiCecLocalDevicePlayback.handleRoutingInformation(message)).isTrue();
+ mTestLooper.dispatchAll();
+ assertThat(mWokenUp).isTrue();
+ assertThat(mNativeWrapper.getResultMessages()).contains(expectedMessage);
+ }
+
// Playback device does not handle routing control related feature right now
@Ignore("b/120845532")
@Test
@@ -184,6 +317,78 @@ public class HdmiCecLocalDevicePlaybackTest {
}
@Test
+ public void handleOnStandby_ScreenOff_NotActiveSource() {
+ mHdmiCecLocalDevicePlayback.setIsActiveSource(false);
+ mHdmiCecLocalDevicePlayback.setAutoDeviceOff(true);
+ mHdmiCecLocalDevicePlayback.onStandby(false, HdmiControlService.STANDBY_SCREEN_OFF);
+ mTestLooper.dispatchAll();
+
+ HdmiCecMessage standbyMessage = HdmiCecMessageBuilder.buildStandby(
+ mHdmiCecLocalDevicePlayback.mAddress, ADDR_TV);
+
+ assertThat(mNativeWrapper.getResultMessages()).doesNotContain(standbyMessage);
+ }
+
+ @Test
+ public void handleOnStandby_ScreenOff_ActiveSource() {
+ mHdmiCecLocalDevicePlayback.setIsActiveSource(true);
+ mHdmiCecLocalDevicePlayback.setAutoDeviceOff(true);
+ mHdmiCecLocalDevicePlayback.onStandby(false, HdmiControlService.STANDBY_SCREEN_OFF);
+ mTestLooper.dispatchAll();
+
+ HdmiCecMessage standbyMessage = HdmiCecMessageBuilder.buildStandby(
+ mHdmiCecLocalDevicePlayback.mAddress, ADDR_TV);
+
+ assertThat(mNativeWrapper.getResultMessages()).contains(standbyMessage);
+ }
+
+ @Test
+ public void handleActiveSource_ActiveSource_None() {
+ mHdmiCecLocalDevicePlayback.mPowerStateChangeOnActiveSourceLost =
+ Constants.POWER_STATE_CHANGE_ON_ACTIVE_SOURCE_LOST_NONE;
+ mStandby = false;
+ HdmiCecMessage message = HdmiCecMessageBuilder.buildActiveSource(ADDR_PLAYBACK_1,
+ mPlaybackPhysicalAddress);
+ assertThat(mHdmiCecLocalDevicePlayback.handleActiveSource(message)).isTrue();
+ mTestLooper.dispatchAll();
+ assertThat(mStandby).isFalse();
+ }
+
+ @Test
+ public void handleActiveSource_notActiveSource_None() {
+ mHdmiCecLocalDevicePlayback.mPowerStateChangeOnActiveSourceLost =
+ Constants.POWER_STATE_CHANGE_ON_ACTIVE_SOURCE_LOST_NONE;
+ mStandby = false;
+ HdmiCecMessage message = HdmiCecMessageBuilder.buildActiveSource(ADDR_TV, 0x0000);
+ assertThat(mHdmiCecLocalDevicePlayback.handleActiveSource(message)).isTrue();
+ mTestLooper.dispatchAll();
+ assertThat(mStandby).isFalse();
+ }
+
+ @Test
+ public void handleActiveSource_ActiveSource_StandbyNow() {
+ mHdmiCecLocalDevicePlayback.mPowerStateChangeOnActiveSourceLost =
+ Constants.POWER_STATE_CHANGE_ON_ACTIVE_SOURCE_LOST_STANDBY_NOW;
+ mStandby = false;
+ HdmiCecMessage message = HdmiCecMessageBuilder.buildActiveSource(ADDR_PLAYBACK_1,
+ mPlaybackPhysicalAddress);
+ assertThat(mHdmiCecLocalDevicePlayback.handleActiveSource(message)).isTrue();
+ mTestLooper.dispatchAll();
+ assertThat(mStandby).isFalse();
+ }
+
+ @Test
+ public void handleActiveSource_notActiveSource_StandbyNow() {
+ mHdmiCecLocalDevicePlayback.mPowerStateChangeOnActiveSourceLost =
+ Constants.POWER_STATE_CHANGE_ON_ACTIVE_SOURCE_LOST_STANDBY_NOW;
+ mStandby = false;
+ HdmiCecMessage message = HdmiCecMessageBuilder.buildActiveSource(ADDR_TV, 0x0000);
+ assertThat(mHdmiCecLocalDevicePlayback.handleActiveSource(message)).isTrue();
+ mTestLooper.dispatchAll();
+ assertThat(mStandby).isTrue();
+ }
+
+ @Test
public void sendVolumeKeyEvent_up_volumeEnabled() {
mHdmiControlService.setHdmiCecVolumeControlEnabled(true);
mHdmiCecLocalDevicePlayback.sendVolumeKeyEvent(KeyEvent.KEYCODE_VOLUME_UP, true);
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/HdmiControlServiceTest.java b/services/tests/servicestests/src/com/android/server/hdmi/HdmiControlServiceTest.java
index 7af7a23b1ef6..c34b8e19a41d 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/HdmiControlServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/HdmiControlServiceTest.java
@@ -33,6 +33,7 @@ import android.content.Context;
import android.content.ContextWrapper;
import android.hardware.hdmi.HdmiControlManager;
import android.hardware.hdmi.HdmiPortInfo;
+import android.hardware.hdmi.IHdmiCecVolumeControlFeatureListener;
import android.os.IPowerManager;
import android.os.IThermalService;
import android.os.Looper;
@@ -261,4 +262,89 @@ public class HdmiControlServiceTest {
mHdmiControlService.setHdmiCecVolumeControlEnabled(true);
assertThat(mHdmiControlService.isHdmiCecVolumeControlEnabled()).isTrue();
}
+
+ @Test
+ public void addHdmiCecVolumeControlFeatureListener_emitsCurrentState_enabled() {
+ mHdmiControlService.setHdmiCecVolumeControlEnabled(true);
+ VolumeControlFeatureCallback callback = new VolumeControlFeatureCallback();
+
+ mHdmiControlService.addHdmiCecVolumeControlFeatureListener(callback);
+ mTestLooper.dispatchAll();
+
+ assertThat(callback.mCallbackReceived).isTrue();
+ assertThat(callback.mVolumeControlEnabled).isTrue();
+ }
+
+ @Test
+ public void addHdmiCecVolumeControlFeatureListener_emitsCurrentState_disabled() {
+ mHdmiControlService.setHdmiCecVolumeControlEnabled(false);
+ VolumeControlFeatureCallback callback = new VolumeControlFeatureCallback();
+
+ mHdmiControlService.addHdmiCecVolumeControlFeatureListener(callback);
+ mTestLooper.dispatchAll();
+
+ assertThat(callback.mCallbackReceived).isTrue();
+ assertThat(callback.mVolumeControlEnabled).isFalse();
+ }
+
+ @Test
+ public void addHdmiCecVolumeControlFeatureListener_notifiesStateUpdate() {
+ mHdmiControlService.setHdmiCecVolumeControlEnabled(false);
+ VolumeControlFeatureCallback callback = new VolumeControlFeatureCallback();
+
+ mHdmiControlService.addHdmiCecVolumeControlFeatureListener(callback);
+
+ mHdmiControlService.setHdmiCecVolumeControlEnabled(true);
+ mTestLooper.dispatchAll();
+
+ assertThat(callback.mCallbackReceived).isTrue();
+ assertThat(callback.mVolumeControlEnabled).isTrue();
+ }
+
+ @Test
+ public void addHdmiCecVolumeControlFeatureListener_honorsUnregistration() {
+ mHdmiControlService.setHdmiCecVolumeControlEnabled(false);
+ VolumeControlFeatureCallback callback = new VolumeControlFeatureCallback();
+
+ mHdmiControlService.addHdmiCecVolumeControlFeatureListener(callback);
+ mTestLooper.dispatchAll();
+
+ mHdmiControlService.removeHdmiControlVolumeControlStatusChangeListener(callback);
+ mHdmiControlService.setHdmiCecVolumeControlEnabled(true);
+ mTestLooper.dispatchAll();
+
+ assertThat(callback.mCallbackReceived).isTrue();
+ assertThat(callback.mVolumeControlEnabled).isFalse();
+ }
+
+ @Test
+ public void addHdmiCecVolumeControlFeatureListener_notifiesStateUpdate_multiple() {
+ mHdmiControlService.setHdmiCecVolumeControlEnabled(false);
+ VolumeControlFeatureCallback callback1 = new VolumeControlFeatureCallback();
+ VolumeControlFeatureCallback callback2 = new VolumeControlFeatureCallback();
+
+ mHdmiControlService.addHdmiCecVolumeControlFeatureListener(callback1);
+ mHdmiControlService.addHdmiCecVolumeControlFeatureListener(callback2);
+
+
+ mHdmiControlService.setHdmiCecVolumeControlEnabled(true);
+ mTestLooper.dispatchAll();
+
+ assertThat(callback1.mCallbackReceived).isTrue();
+ assertThat(callback2.mCallbackReceived).isTrue();
+ assertThat(callback1.mVolumeControlEnabled).isTrue();
+ assertThat(callback2.mVolumeControlEnabled).isTrue();
+ }
+
+ private static class VolumeControlFeatureCallback extends
+ IHdmiCecVolumeControlFeatureListener.Stub {
+ boolean mCallbackReceived = false;
+ boolean mVolumeControlEnabled = false;
+
+ @Override
+ public void onHdmiCecVolumeControlFeature(boolean enabled) throws RemoteException {
+ this.mCallbackReceived = true;
+ this.mVolumeControlEnabled = enabled;
+ }
+ }
}
diff --git a/services/tests/servicestests/src/com/android/server/integrity/AppIntegrityManagerServiceImplTest.java b/services/tests/servicestests/src/com/android/server/integrity/AppIntegrityManagerServiceImplTest.java
index 53c9bb22e752..9ca84d33998c 100644
--- a/services/tests/servicestests/src/com/android/server/integrity/AppIntegrityManagerServiceImplTest.java
+++ b/services/tests/servicestests/src/com/android/server/integrity/AppIntegrityManagerServiceImplTest.java
@@ -121,7 +121,7 @@ public class AppIntegrityManagerServiceImplTest {
private static final String INSTALLER_SHA256 =
"30F41A7CBF96EE736A54DD6DF759B50ED3CC126ABCEF694E167C324F5976C227";
private static final String SOURCE_STAMP_CERTIFICATE_HASH =
- "681B0E56A796350C08647352A4DB800CC44B2ADC8F4C72FA350BD05D4D50264D";
+ "C6E737809CEF2B08CC6694892215F82A5E8FBC3C2A0F6212770310B90622D2D9";
private static final String DUMMY_APP_TWO_CERTS_CERT_1 =
"C0369C2A1096632429DFA8433068AECEAD00BAC337CA92A175036D39CC9AFE94";
diff --git a/services/tests/servicestests/src/com/android/server/om/OverlayManagerServiceImplTests.java b/services/tests/servicestests/src/com/android/server/om/OverlayManagerServiceImplTests.java
index 8774ab020202..f4c5506c7001 100644
--- a/services/tests/servicestests/src/com/android/server/om/OverlayManagerServiceImplTests.java
+++ b/services/tests/servicestests/src/com/android/server/om/OverlayManagerServiceImplTests.java
@@ -26,7 +26,6 @@ import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import android.content.om.OverlayInfo;
-import android.os.OverlayablePolicy;
import androidx.test.runner.AndroidJUnit4;
@@ -205,138 +204,4 @@ public class OverlayManagerServiceImplTests extends OverlayManagerServiceImplTes
impl.setEnabled(OVERLAY, true, USER);
assertEquals(0, listener.count);
}
-
- @Test
- public void testConfigurator() {
- mOverlayableConfigurator = "actor";
- mOverlayableConfiguratorTargets = new String[]{TARGET};
- reinitializeImpl();
-
- installNewPackage(target("actor").setCertificate("one"), USER);
- installNewPackage(target(TARGET).addOverlayable("TestResources").setCertificate("two"),
- USER);
-
- DummyDeviceState.PackageBuilder overlay = overlay(OVERLAY, TARGET, "TestResources")
- .setCertificate("one");
- installNewPackage(overlay, USER);
-
- DummyIdmapDaemon.IdmapHeader idmap = getIdmapDaemon().getIdmap(overlay.build().apkPath);
- assertNotNull(idmap);
- assertEquals(OverlayablePolicy.ACTOR_SIGNATURE,
- idmap.policies & OverlayablePolicy.ACTOR_SIGNATURE);
- }
-
- @Test
- public void testConfiguratorWithoutOverlayable() {
- mOverlayableConfigurator = "actor";
- mOverlayableConfiguratorTargets = new String[]{TARGET};
- reinitializeImpl();
-
- installNewPackage(target("actor").setCertificate("one"), USER);
- installNewPackage(target(TARGET).setCertificate("two"), USER);
-
- DummyDeviceState.PackageBuilder overlay = overlay(OVERLAY, TARGET).setCertificate("one");
- installNewPackage(overlay, USER);
-
- DummyIdmapDaemon.IdmapHeader idmap = getIdmapDaemon().getIdmap(overlay.build().apkPath);
- assertNotNull(idmap);
- assertEquals(OverlayablePolicy.ACTOR_SIGNATURE,
- idmap.policies & OverlayablePolicy.ACTOR_SIGNATURE);
- }
-
- @Test
- public void testConfiguratorDifferentTargets() {
- // The target package is not listed in the configurator target list, so the actor policy
- // should not be granted.
- mOverlayableConfigurator = "actor";
- mOverlayableConfiguratorTargets = new String[]{"somethingElse"};
- reinitializeImpl();
-
- installNewPackage(target("actor").setCertificate("one"), USER);
- installNewPackage(target(TARGET).setCertificate("two"), USER);
-
- DummyDeviceState.PackageBuilder overlay = overlay(OVERLAY, TARGET).setCertificate("one");
- installNewPackage(overlay, USER);
-
- DummyIdmapDaemon.IdmapHeader idmap = getIdmapDaemon().getIdmap(overlay.build().apkPath);
- assertNotNull(idmap);
- assertEquals(0, idmap.policies & OverlayablePolicy.ACTOR_SIGNATURE);
- }
-
- @Test
- public void testConfiguratorDifferentSignatures() {
- mOverlayableConfigurator = "actor";
- mOverlayableConfiguratorTargets = new String[]{TARGET};
- reinitializeImpl();
-
- installNewPackage(target("actor").setCertificate("one"), USER);
- installNewPackage(target(TARGET).addOverlayable("TestResources").setCertificate("two"),
- USER);
-
- DummyDeviceState.PackageBuilder overlay = overlay(OVERLAY, TARGET, "TestResources")
- .setCertificate("two");
- installNewPackage(overlay, USER);
-
- DummyIdmapDaemon.IdmapHeader idmap = getIdmapDaemon().getIdmap(overlay.build().apkPath);
- assertNotNull(idmap);
- assertEquals(0, idmap.policies & OverlayablePolicy.ACTOR_SIGNATURE);
- }
-
- @Test
- public void testConfiguratorWithoutOverlayableDifferentSignatures() {
- mOverlayableConfigurator = "actor";
- mOverlayableConfiguratorTargets = new String[]{TARGET};
- reinitializeImpl();
-
- installNewPackage(target("actor").setCertificate("one"), USER);
- installNewPackage(target(TARGET).setCertificate("two"), USER);
-
- DummyDeviceState.PackageBuilder overlay = overlay(OVERLAY, TARGET).setCertificate("two");
- installNewPackage(overlay, USER);
-
- DummyIdmapDaemon.IdmapHeader idmap = getIdmapDaemon().getIdmap(overlay.build().apkPath);
- assertNotNull(idmap);
- assertEquals(0, idmap.policies & OverlayablePolicy.ACTOR_SIGNATURE);
- }
-
- @Test
- public void testConfiguratorChanges() {
- mOverlayableConfigurator = "actor";
- mOverlayableConfiguratorTargets = new String[]{TARGET};
- reinitializeImpl();
-
- installNewPackage(target("actor").setCertificate("one"), USER);
- installNewPackage(target(TARGET).addOverlayable("TestResources").setCertificate("two"),
- USER);
-
- DummyDeviceState.PackageBuilder overlay = overlay(OVERLAY, TARGET, "TestResources")
- .setCertificate("one");
- installNewPackage(overlay, USER);
-
- DummyIdmapDaemon.IdmapHeader idmap = getIdmapDaemon().getIdmap(overlay.build().apkPath);
- assertNotNull(idmap);
- assertEquals(OverlayablePolicy.ACTOR_SIGNATURE,
- idmap.policies & OverlayablePolicy.ACTOR_SIGNATURE);
-
- // Change the configurator to a different package. The overlay should still be granted the
- // actor policy.
- mOverlayableConfigurator = "differentActor";
- OverlayManagerServiceImpl impl = reinitializeImpl();
- impl.updateOverlaysForUser(USER);
-
- idmap = getIdmapDaemon().getIdmap(overlay.build().apkPath);
- assertNotNull(idmap);
- assertEquals(OverlayablePolicy.ACTOR_SIGNATURE,
- idmap.policies & OverlayablePolicy.ACTOR_SIGNATURE);
-
- // Reset the setting persisting that the overlay once fulfilled the actor policy implicitly
- // through the configurator. The overlay should lose the actor policy.
- impl = reinitializeImpl();
- getSettings().setHasConfiguratorActorPolicy(OVERLAY, USER, false);
- impl.updateOverlaysForUser(USER);
-
- idmap = getIdmapDaemon().getIdmap(overlay.build().apkPath);
- assertNotNull(idmap);
- assertEquals(0, idmap.policies & OverlayablePolicy.ACTOR_SIGNATURE);
- }
}
diff --git a/services/tests/servicestests/src/com/android/server/om/OverlayManagerServiceImplTestsBase.java b/services/tests/servicestests/src/com/android/server/om/OverlayManagerServiceImplTestsBase.java
index 52a58907ea5a..733310b2508a 100644
--- a/services/tests/servicestests/src/com/android/server/om/OverlayManagerServiceImplTestsBase.java
+++ b/services/tests/servicestests/src/com/android/server/om/OverlayManagerServiceImplTestsBase.java
@@ -52,9 +52,6 @@ class OverlayManagerServiceImplTestsBase {
private DummyPackageManagerHelper mPackageManager;
private DummyIdmapDaemon mIdmapDaemon;
private OverlayConfig mOverlayConfig;
- private OverlayManagerSettings mSettings;
- String mOverlayableConfigurator;
- String[] mOverlayableConfiguratorTargets;
@Before
public void setUp() {
@@ -62,26 +59,20 @@ class OverlayManagerServiceImplTestsBase {
mListener = new DummyListener();
mPackageManager = new DummyPackageManagerHelper(mState);
mIdmapDaemon = new DummyIdmapDaemon(mState);
- mSettings = new OverlayManagerSettings();
mOverlayConfig = mock(OverlayConfig.class);
when(mOverlayConfig.getPriority(any())).thenReturn(OverlayConfig.DEFAULT_PRIORITY);
when(mOverlayConfig.isEnabled(any())).thenReturn(false);
when(mOverlayConfig.isMutable(any())).thenReturn(true);
- mOverlayableConfigurator = null;
- mOverlayableConfiguratorTargets = null;
reinitializeImpl();
}
- OverlayManagerServiceImpl reinitializeImpl() {
+ void reinitializeImpl() {
mImpl = new OverlayManagerServiceImpl(mPackageManager,
new IdmapManager(mIdmapDaemon, mPackageManager),
- mSettings,
+ new OverlayManagerSettings(),
mOverlayConfig,
new String[0],
- mListener,
- mOverlayableConfigurator,
- mOverlayableConfiguratorTargets);
- return mImpl;
+ mListener);
}
OverlayManagerServiceImpl getImpl() {
@@ -92,14 +83,6 @@ class OverlayManagerServiceImplTestsBase {
return mListener;
}
- DummyIdmapDaemon getIdmapDaemon() {
- return mIdmapDaemon;
- }
-
- OverlayManagerSettings getSettings() {
- return mSettings;
- }
-
void assertState(@State int expected, final String overlayPackageName, int userId) {
final OverlayInfo info = mImpl.getOverlayInfo(overlayPackageName, userId);
if (info == null) {
diff --git a/services/tests/servicestests/src/com/android/server/om/OverlayManagerSettingsTests.java b/services/tests/servicestests/src/com/android/server/om/OverlayManagerSettingsTests.java
index e2cedb5e1a62..146f60aff724 100644
--- a/services/tests/servicestests/src/com/android/server/om/OverlayManagerSettingsTests.java
+++ b/services/tests/servicestests/src/com/android/server/om/OverlayManagerSettingsTests.java
@@ -367,8 +367,7 @@ public class OverlayManagerSettingsTests {
+ " isEnabled='false'\n"
+ " category='dummy-category'\n"
+ " isStatic='false'\n"
- + " priority='0'"
- + " hasConfiguratorActorPolicy='true' />\n"
+ + " priority='0' />\n"
+ "</overlays>\n";
ByteArrayInputStream is = new ByteArrayInputStream(xml.getBytes("utf-8"));
@@ -381,7 +380,6 @@ public class OverlayManagerSettingsTests {
assertEquals(1234, oi.userId);
assertEquals(STATE_DISABLED, oi.state);
assertFalse(mSettings.getEnabled("com.dummy.overlay", 1234));
- assertTrue(mSettings.hasConfiguratorActorPolicy("com.dummy.overlay", 1234));
}
@Test
diff --git a/services/tests/servicestests/src/com/android/server/pm/UserSystemPackageInstallerTest.java b/services/tests/servicestests/src/com/android/server/pm/UserSystemPackageInstallerTest.java
index c55df512bd1e..87979fb00021 100644
--- a/services/tests/servicestests/src/com/android/server/pm/UserSystemPackageInstallerTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/UserSystemPackageInstallerTest.java
@@ -366,9 +366,75 @@ public class UserSystemPackageInstallerTest {
for (PackageInfo p : packageInfos) {
actualPackages.add(p.packageName);
}
+
+ // Add auto-generated RRO package to expectedPackages since they are not (supposed to be)
+ // in the whitelist but they should be installed.
+ for (PackageInfo p : packageInfos) {
+ if (p.isOverlayPackage()
+ && UserSystemPackageInstaller.hasAutoGeneratedRROSuffix(p.packageName)
+ && expectedPackages.contains(p.overlayTarget)) {
+ expectedPackages.add(p.packageName);
+ }
+ }
checkPackageDifferences(expectedPackages, actualPackages);
}
+ @Test
+ public void testAutoGeneratedRROMatchesSuffix() {
+ final List<PackageInfo> packageInfos = mContext.getPackageManager()
+ .getInstalledPackages(PackageManager.GET_UNINSTALLED_PACKAGES);
+
+ Log.v(TAG, "Found total packages: " + packageInfos.size());
+
+ for (PackageInfo p : packageInfos) {
+ if (p.packageName.contains(".auto_generated_rro_")) {
+ assertTrue("Auto-generated RRO package name does not match the suffix: "
+ + p.packageName,
+ UserSystemPackageInstaller.hasAutoGeneratedRROSuffix(p.packageName));
+ }
+ }
+ }
+
+ /**
+ * Test that overlay package not in whitelist should be installed for all user at Explicit mode.
+ */
+ @Test
+ public void testInstallOverlayPackagesExplicitMode() {
+ setUserTypePackageWhitelistMode(USER_TYPE_PACKAGE_WHITELIST_MODE_ENFORCE);
+
+ final String[] userTypes = new String[]{"type"};
+ final long maskOfType = 0b0001L;
+
+ final String packageName1 = "whitelistedPkg";
+ final String packageName2 = "nonWhitelistedPkg";
+ final String overlayName1 = String.format("%s.auto_generated_rro_product__", packageName1);
+ final String overlayName2 = String.format("%s.auto_generated_rro_product__", packageName2);
+
+ final AndroidPackage overlayPackage1 = ((ParsedPackage) PackageImpl.forTesting(overlayName1)
+ .setOverlay(true)
+ .setOverlayTarget(packageName1)
+ .hideAsParsed())
+ .hideAsFinal();
+
+ final AndroidPackage overlayPackage2 = ((ParsedPackage) PackageImpl.forTesting(overlayName2)
+ .setOverlay(true)
+ .setOverlayTarget(packageName2)
+ .hideAsParsed())
+ .hideAsFinal();
+
+ final ArrayMap<String, Long> userTypeWhitelist = new ArrayMap<>();
+ userTypeWhitelist.put(packageName1, maskOfType);
+
+ final Set<String> userWhitelist = new ArraySet<>();
+ userWhitelist.add(packageName1);
+
+ boolean implicit = false;
+ assertTrue("Overlay for package1 should be installed", UserSystemPackageInstaller
+ .shouldInstallPackage(overlayPackage1, userTypeWhitelist, userWhitelist, implicit));
+ assertFalse("Overlay for package2 should not be installed", UserSystemPackageInstaller
+ .shouldInstallPackage(overlayPackage2, userTypeWhitelist, userWhitelist, implicit));
+ }
+
/** Asserts that actual is a subset of expected. */
private void checkPackageDifferences(Set<String> expected, Set<String> actual) {
final Set<String> uniqueToExpected = new ArraySet<>(expected);
diff --git a/services/tests/servicestests/src/com/android/server/pm/parsing/AndroidPackageParsingEquivalenceTest.kt b/services/tests/servicestests/src/com/android/server/pm/parsing/AndroidPackageParsingEquivalenceTest.kt
index 5412bb5106ff..74b4d122cbc0 100644
--- a/services/tests/servicestests/src/com/android/server/pm/parsing/AndroidPackageParsingEquivalenceTest.kt
+++ b/services/tests/servicestests/src/com/android/server/pm/parsing/AndroidPackageParsingEquivalenceTest.kt
@@ -18,8 +18,8 @@ package com.android.server.pm.parsing
import android.content.pm.PackageManager
import android.platform.test.annotations.Presubmit
+import androidx.test.filters.LargeTest
import com.google.common.truth.Expect
-import com.google.common.truth.Truth.assertWithMessage
import org.junit.Rule
import org.junit.Test
@@ -52,6 +52,7 @@ class AndroidPackageParsingEquivalenceTest : AndroidPackageParsingTestBase() {
}
}
+ @LargeTest
@Test
fun packageInfoEquality() {
val flags = PackageManager.GET_ACTIVITIES or
@@ -65,7 +66,9 @@ class AndroidPackageParsingEquivalenceTest : AndroidPackageParsingTestBase() {
PackageManager.GET_SERVICES or
PackageManager.GET_SHARED_LIBRARY_FILES or
PackageManager.GET_SIGNATURES or
- PackageManager.GET_SIGNING_CERTIFICATES
+ PackageManager.GET_SIGNING_CERTIFICATES or
+ PackageManager.MATCH_DIRECT_BOOT_UNAWARE or
+ PackageManager.MATCH_DIRECT_BOOT_AWARE
val oldPackageInfo = oldPackages.asSequence().map { oldPackageInfo(it, flags) }
val newPackageInfo = newPackages.asSequence().map { newPackageInfo(it, flags) }
@@ -77,11 +80,79 @@ class AndroidPackageParsingEquivalenceTest : AndroidPackageParsingTestBase() {
} else {
"$firstName | $secondName"
}
- expect.withMessage("${it.first?.applicationInfo?.sourceDir} $packageName")
- .that(it.first?.dumpToString())
- .isEqualTo(it.second?.dumpToString())
+
+ // Main components are asserted independently to separate the failures. Otherwise the
+ // comparison would include every component in one massive string.
+
+ val prefix = "${it.first?.applicationInfo?.sourceDir} $packageName"
+
+ expect.withMessage("$prefix PackageInfo")
+ .that(it.second?.dumpToString())
+ .isEqualTo(it.first?.dumpToString())
+
+ expect.withMessage("$prefix ApplicationInfo")
+ .that(it.second?.applicationInfo?.dumpToString())
+ .isEqualTo(it.first?.applicationInfo?.dumpToString())
+
+ val firstActivityNames = it.first?.activities?.map { it.name } ?: emptyList()
+ val secondActivityNames = it.second?.activities?.map { it.name } ?: emptyList()
+ expect.withMessage("$prefix activities")
+ .that(secondActivityNames)
+ .containsExactlyElementsIn(firstActivityNames)
+ .inOrder()
+
+ if (!it.first?.activities.isNullOrEmpty() && !it.second?.activities.isNullOrEmpty()) {
+ it.first?.activities?.zip(it.second?.activities!!)?.forEach {
+ expect.withMessage("$prefix ${it.first.name}")
+ .that(it.second.dumpToString())
+ .isEqualTo(it.first.dumpToString())
+ }
+ }
+
+ val firstReceiverNames = it.first?.receivers?.map { it.name } ?: emptyList()
+ val secondReceiverNames = it.second?.receivers?.map { it.name } ?: emptyList()
+ expect.withMessage("$prefix receivers")
+ .that(secondReceiverNames)
+ .containsExactlyElementsIn(firstReceiverNames)
+ .inOrder()
+
+ if (!it.first?.receivers.isNullOrEmpty() && !it.second?.receivers.isNullOrEmpty()) {
+ it.first?.receivers?.zip(it.second?.receivers!!)?.forEach {
+ expect.withMessage("$prefix ${it.first.name}")
+ .that(it.second.dumpToString())
+ .isEqualTo(it.first.dumpToString())
+ }
+ }
+
+ val firstProviderNames = it.first?.providers?.map { it.name } ?: emptyList()
+ val secondProviderNames = it.second?.providers?.map { it.name } ?: emptyList()
+ expect.withMessage("$prefix providers")
+ .that(secondProviderNames)
+ .containsExactlyElementsIn(firstProviderNames)
+ .inOrder()
+
+ if (!it.first?.providers.isNullOrEmpty() && !it.second?.providers.isNullOrEmpty()) {
+ it.first?.providers?.zip(it.second?.providers!!)?.forEach {
+ expect.withMessage("$prefix ${it.first.name}")
+ .that(it.second.dumpToString())
+ .isEqualTo(it.first.dumpToString())
+ }
+ }
+
+ val firstServiceNames = it.first?.services?.map { it.name } ?: emptyList()
+ val secondServiceNames = it.second?.services?.map { it.name } ?: emptyList()
+ expect.withMessage("$prefix services")
+ .that(secondServiceNames)
+ .containsExactlyElementsIn(firstServiceNames)
+ .inOrder()
+
+ if (!it.first?.services.isNullOrEmpty() && !it.second?.services.isNullOrEmpty()) {
+ it.first?.services?.zip(it.second?.services!!)?.forEach {
+ expect.withMessage("$prefix ${it.first.name}")
+ .that(it.second.dumpToString())
+ .isEqualTo(it.first.dumpToString())
+ }
+ }
}
}
}
-
-
diff --git a/services/tests/servicestests/src/com/android/server/pm/parsing/AndroidPackageParsingTestBase.kt b/services/tests/servicestests/src/com/android/server/pm/parsing/AndroidPackageParsingTestBase.kt
index 0f028f05d514..420ff19aab74 100644
--- a/services/tests/servicestests/src/com/android/server/pm/parsing/AndroidPackageParsingTestBase.kt
+++ b/services/tests/servicestests/src/com/android/server/pm/parsing/AndroidPackageParsingTestBase.kt
@@ -19,6 +19,7 @@ package com.android.server.pm.parsing
import android.content.Context
import android.content.pm.ActivityInfo
import android.content.pm.ApplicationInfo
+import android.content.pm.ComponentInfo
import android.content.pm.ConfigurationInfo
import android.content.pm.FeatureInfo
import android.content.pm.InstrumentationInfo
@@ -27,6 +28,8 @@ import android.content.pm.PackageParser
import android.content.pm.PackageUserState
import android.content.pm.PermissionInfo
import android.content.pm.ProviderInfo
+import android.content.pm.ServiceInfo
+import android.os.Bundle
import android.os.Debug
import android.os.Environment
import android.util.SparseArray
@@ -38,8 +41,10 @@ import com.android.server.pm.pkg.PackageStateUnserialized
import com.android.server.testutils.mockThrowOnUnmocked
import com.android.server.testutils.whenever
import org.junit.BeforeClass
-import org.mockito.Mockito
+import org.mockito.Mockito.any
+import org.mockito.Mockito.anyBoolean
import org.mockito.Mockito.anyInt
+import org.mockito.Mockito.anyString
import org.mockito.Mockito.mock
import java.io.File
@@ -47,7 +52,7 @@ open class AndroidPackageParsingTestBase {
companion object {
- private const val VERIFY_ALL_APKS = false
+ private const val VERIFY_ALL_APKS = true
/** For auditing memory usage differences */
private const val DUMP_HPROF_TO_EXTERNAL = false
@@ -81,10 +86,14 @@ open class AndroidPackageParsingTestBase {
.filter { file -> file.name.endsWith(".apk") }
.toList()
}
+ .distinct()
private val dummyUserState = mock(PackageUserState::class.java).apply {
installed = true
- Mockito.`when`(isAvailable(anyInt())).thenReturn(true)
+ whenever(isAvailable(anyInt())) { true }
+ whenever(isMatch(any<ComponentInfo>(), anyInt())) { true }
+ whenever(isMatch(anyBoolean(), anyBoolean(), anyBoolean(), anyBoolean(),
+ anyString(), anyInt())) { true }
}
lateinit var oldPackages: List<PackageParser.Package>
@@ -145,6 +154,7 @@ open class AndroidPackageParsingTestBase {
private fun mockPkgSetting(aPkg: AndroidPackage) = mockThrowOnUnmocked<PackageSetting> {
this.pkg = aPkg
whenever(pkgState) { PackageStateUnserialized() }
+ whenever(readUserState(anyInt())) { dummyUserState }
}
}
@@ -156,19 +166,10 @@ open class AndroidPackageParsingTestBase {
// The following methods prepend "this." because @hide APIs can cause an IDE to auto-import
// the R.attr constant instead of referencing the field in an attempt to fix the error.
- /**
- * Known exclusions:
- * - [ApplicationInfo.credentialProtectedDataDir]
- * - [ApplicationInfo.dataDir]
- * - [ApplicationInfo.deviceProtectedDataDir]
- * - [ApplicationInfo.processName]
- * - [ApplicationInfo.publicSourceDir]
- * - [ApplicationInfo.scanPublicSourceDir]
- * - [ApplicationInfo.scanSourceDir]
- * - [ApplicationInfo.sourceDir]
- * These attributes used to be assigned post-package-parsing as part of another component,
- * but are now adjusted directly inside [PackageImpl].
- */
+ // It's difficult to comment out a line in a triple quoted string, so this is used instead
+ // to ignore specific fields. A comment is required to explain why a field was ignored.
+ private fun Any?.ignored(comment: String): String = "IGNORED"
+
protected fun ApplicationInfo.dumpToString() = """
appComponentFactory=${this.appComponentFactory}
backupAgentName=${this.backupAgentName}
@@ -179,22 +180,31 @@ open class AndroidPackageParsingTestBase {
compatibleWidthLimitDp=${this.compatibleWidthLimitDp}
compileSdkVersion=${this.compileSdkVersion}
compileSdkVersionCodename=${this.compileSdkVersionCodename}
+ credentialProtectedDataDir=${this.credentialProtectedDataDir
+ .ignored("Deferred pre-R, but assigned immediately in R")}
+ crossProfile=${this.crossProfile.ignored("Added in R")}
+ dataDir=${this.dataDir.ignored("Deferred pre-R, but assigned immediately in R")}
descriptionRes=${this.descriptionRes}
+ deviceProtectedDataDir=${this.deviceProtectedDataDir
+ .ignored("Deferred pre-R, but assigned immediately in R")}
enabled=${this.enabled}
enabledSetting=${this.enabledSetting}
flags=${Integer.toBinaryString(this.flags)}
fullBackupContent=${this.fullBackupContent}
+ gwpAsanMode=${this.gwpAsanMode.ignored("Added in R")}
hiddenUntilInstalled=${this.hiddenUntilInstalled}
icon=${this.icon}
iconRes=${this.iconRes}
installLocation=${this.installLocation}
+ labelRes=${this.labelRes}
largestWidthLimitDp=${this.largestWidthLimitDp}
logo=${this.logo}
longVersionCode=${this.longVersionCode}
+ ${"".ignored("mHiddenApiPolicy is a private field")}
manageSpaceActivityName=${this.manageSpaceActivityName}
- maxAspectRatio.compareTo(that.maxAspectRatio)=${this.maxAspectRatio}
- metaData=${this.metaData}
- minAspectRatio.compareTo(that.minAspectRatio)=${this.minAspectRatio}
+ maxAspectRatio=${this.maxAspectRatio}
+ metaData=${this.metaData.dumpToString()}
+ minAspectRatio=${this.minAspectRatio}
minSdkVersion=${this.minSdkVersion}
name=${this.name}
nativeLibraryDir=${this.nativeLibraryDir}
@@ -206,18 +216,27 @@ open class AndroidPackageParsingTestBase {
permission=${this.permission}
primaryCpuAbi=${this.primaryCpuAbi}
privateFlags=${Integer.toBinaryString(this.privateFlags)}
+ processName=${this.processName.ignored("Deferred pre-R, but assigned immediately in R")}
+ publicSourceDir=${this.publicSourceDir
+ .ignored("Deferred pre-R, but assigned immediately in R")}
requiresSmallestWidthDp=${this.requiresSmallestWidthDp}
resourceDirs=${this.resourceDirs?.contentToString()}
roundIconRes=${this.roundIconRes}
- secondaryCpuAbi=${this.secondaryCpuAbi}
- secondaryNativeLibraryDir=${this.secondaryNativeLibraryDir}
+ scanPublicSourceDir=${this.scanPublicSourceDir
+ .ignored("Deferred pre-R, but assigned immediately in R")}
+ scanSourceDir=${this.scanSourceDir
+ .ignored("Deferred pre-R, but assigned immediately in R")}
seInfo=${this.seInfo}
seInfoUser=${this.seInfoUser}
+ secondaryCpuAbi=${this.secondaryCpuAbi}
+ secondaryNativeLibraryDir=${this.secondaryNativeLibraryDir}
sharedLibraryFiles=${this.sharedLibraryFiles?.contentToString()}
sharedLibraryInfos=${this.sharedLibraryInfos}
showUserIcon=${this.showUserIcon}
+ sourceDir=${this.sourceDir
+ .ignored("Deferred pre-R, but assigned immediately in R")}
splitClassLoaderNames=${this.splitClassLoaderNames?.contentToString()}
- splitDependencies=${this.splitDependencies}
+ splitDependencies=${this.splitDependencies.dumpToString()}
splitNames=${this.splitNames?.contentToString()}
splitPublicSourceDirs=${this.splitPublicSourceDirs?.contentToString()}
splitSourceDirs=${this.splitSourceDirs?.contentToString()}
@@ -226,8 +245,8 @@ open class AndroidPackageParsingTestBase {
targetSdkVersion=${this.targetSdkVersion}
taskAffinity=${this.taskAffinity}
theme=${this.theme}
- uid=${this.uid}
uiOptions=${this.uiOptions}
+ uid=${this.uid}
versionCode=${this.versionCode}
volumeUuid=${this.volumeUuid}
zygotePreloadName=${this.zygotePreloadName}
@@ -241,19 +260,27 @@ open class AndroidPackageParsingTestBase {
""".trimIndent()
protected fun InstrumentationInfo.dumpToString() = """
+ banner=${this.banner}
credentialProtectedDataDir=${this.credentialProtectedDataDir}
dataDir=${this.dataDir}
deviceProtectedDataDir=${this.deviceProtectedDataDir}
functionalTest=${this.functionalTest}
handleProfiling=${this.handleProfiling}
+ icon=${this.icon}
+ labelRes=${this.labelRes}
+ logo=${this.logo}
+ metaData=${this.metaData}
+ name=${this.name}
nativeLibraryDir=${this.nativeLibraryDir}
+ nonLocalizedLabel=${this.nonLocalizedLabel}
+ packageName=${this.packageName}
primaryCpuAbi=${this.primaryCpuAbi}
publicSourceDir=${this.publicSourceDir}
secondaryCpuAbi=${this.secondaryCpuAbi}
secondaryNativeLibraryDir=${this.secondaryNativeLibraryDir}
+ showUserIcon=${this.showUserIcon}
sourceDir=${this.sourceDir}
- splitDependencies=${this.splitDependencies.sequence()
- .map { it.first to it.second?.contentToString() }.joinToString()}
+ splitDependencies=${this.splitDependencies.dumpToString()}
splitNames=${this.splitNames?.contentToString()}
splitPublicSourceDirs=${this.splitPublicSourceDirs?.contentToString()}
splitSourceDirs=${this.splitSourceDirs?.contentToString()}
@@ -262,25 +289,40 @@ open class AndroidPackageParsingTestBase {
""".trimIndent()
protected fun ActivityInfo.dumpToString() = """
+ banner=${this.banner}
colorMode=${this.colorMode}
configChanges=${this.configChanges}
+ descriptionRes=${this.descriptionRes}
+ directBootAware=${this.directBootAware}
documentLaunchMode=${this.documentLaunchMode}
+ enabled=${this.enabled}
+ exported=${this.exported}
flags=${Integer.toBinaryString(this.flags)}
+ icon=${this.icon}
+ labelRes=${this.labelRes}
launchMode=${this.launchMode}
launchToken=${this.launchToken}
lockTaskLaunchMode=${this.lockTaskLaunchMode}
+ logo=${this.logo}
maxAspectRatio=${this.maxAspectRatio}
maxRecents=${this.maxRecents}
+ metaData=${this.metaData.dumpToString()}
minAspectRatio=${this.minAspectRatio}
+ name=${this.name}
+ nonLocalizedLabel=${this.nonLocalizedLabel}
+ packageName=${this.packageName}
parentActivityName=${this.parentActivityName}
permission=${this.permission}
- persistableMode=${this.persistableMode}
- privateFlags=${Integer.toBinaryString(this.privateFlags)}
+ persistableMode=${this.persistableMode.ignored("Could be dropped pre-R, fixed in R")}
+ privateFlags=${this.privateFlags}
+ processName=${this.processName.ignored("Deferred pre-R, but assigned immediately in R")}
requestedVrComponent=${this.requestedVrComponent}
resizeMode=${this.resizeMode}
rotationAnimation=${this.rotationAnimation}
screenOrientation=${this.screenOrientation}
+ showUserIcon=${this.showUserIcon}
softInputMode=${this.softInputMode}
+ splitName=${this.splitName}
targetActivity=${this.targetActivity}
taskAffinity=${this.taskAffinity}
theme=${this.theme}
@@ -300,30 +342,77 @@ open class AndroidPackageParsingTestBase {
protected fun PermissionInfo.dumpToString() = """
backgroundPermission=${this.backgroundPermission}
+ banner=${this.banner}
descriptionRes=${this.descriptionRes}
flags=${Integer.toBinaryString(this.flags)}
group=${this.group}
+ icon=${this.icon}
+ labelRes=${this.labelRes}
+ logo=${this.logo}
+ metaData=${this.metaData.dumpToString()}
+ name=${this.name}
nonLocalizedDescription=${this.nonLocalizedDescription}
+ nonLocalizedLabel=${this.nonLocalizedLabel}
+ packageName=${this.packageName}
protectionLevel=${this.protectionLevel}
requestRes=${this.requestRes}
+ showUserIcon=${this.showUserIcon}
""".trimIndent()
protected fun ProviderInfo.dumpToString() = """
+ applicationInfo=${this.applicationInfo.ignored("Already checked")}
authority=${this.authority}
+ banner=${this.banner}
+ descriptionRes=${this.descriptionRes}
+ directBootAware=${this.directBootAware}
+ enabled=${this.enabled}
+ exported=${this.exported}
flags=${Integer.toBinaryString(this.flags)}
forceUriPermissions=${this.forceUriPermissions}
grantUriPermissions=${this.grantUriPermissions}
+ icon=${this.icon}
initOrder=${this.initOrder}
isSyncable=${this.isSyncable}
+ labelRes=${this.labelRes}
+ logo=${this.logo}
+ metaData=${this.metaData.dumpToString()}
multiprocess=${this.multiprocess}
+ name=${this.name}
+ nonLocalizedLabel=${this.nonLocalizedLabel}
+ packageName=${this.packageName}
pathPermissions=${this.pathPermissions?.joinToString {
"readPermission=${it.readPermission}\nwritePermission=${it.writePermission}"
}}
+ processName=${this.processName.ignored("Deferred pre-R, but assigned immediately in R")}
readPermission=${this.readPermission}
+ showUserIcon=${this.showUserIcon}
+ splitName=${this.splitName}
uriPermissionPatterns=${this.uriPermissionPatterns?.contentToString()}
writePermission=${this.writePermission}
""".trimIndent()
+ protected fun ServiceInfo.dumpToString() = """
+ applicationInfo=${this.applicationInfo.ignored("Already checked")}
+ banner=${this.banner}
+ descriptionRes=${this.descriptionRes}
+ directBootAware=${this.directBootAware}
+ enabled=${this.enabled}
+ exported=${this.exported}
+ flags=${Integer.toBinaryString(this.flags)}
+ icon=${this.icon}
+ labelRes=${this.labelRes}
+ logo=${this.logo}
+ mForegroundServiceType"${this.mForegroundServiceType}
+ metaData=${this.metaData.dumpToString()}
+ name=${this.name}
+ nonLocalizedLabel=${this.nonLocalizedLabel}
+ packageName=${this.packageName}
+ permission=${this.permission}
+ processName=${this.processName.ignored("Deferred pre-R, but assigned immediately in R")}
+ showUserIcon=${this.showUserIcon}
+ splitName=${this.splitName}
+ """.trimIndent()
+
protected fun ConfigurationInfo.dumpToString() = """
reqGlEsVersion=${this.reqGlEsVersion}
reqInputFeatures=${this.reqInputFeatures}
@@ -333,8 +422,10 @@ open class AndroidPackageParsingTestBase {
""".trimIndent()
protected fun PackageInfo.dumpToString() = """
- activities=${this.activities?.joinToString { it.dumpToString() }}
- applicationInfo=${this.applicationInfo.dumpToString()}
+ activities=${this.activities?.joinToString { it.dumpToString() }
+ .ignored("Checked separately in test")}
+ applicationInfo=${this.applicationInfo.dumpToString()
+ .ignored("Checked separately in test")}
baseRevisionCode=${this.baseRevisionCode}
compileSdkVersion=${this.compileSdkVersion}
compileSdkVersionCodename=${this.compileSdkVersionCodename}
@@ -356,15 +447,18 @@ open class AndroidPackageParsingTestBase {
overlayTarget=${this.overlayTarget}
packageName=${this.packageName}
permissions=${this.permissions?.joinToString { it.dumpToString() }}
- providers=${this.providers?.joinToString { it.dumpToString() }}
- receivers=${this.receivers?.joinToString { it.dumpToString() }}
+ providers=${this.providers?.joinToString { it.dumpToString() }
+ .ignored("Checked separately in test")}
+ receivers=${this.receivers?.joinToString { it.dumpToString() }
+ .ignored("Checked separately in test")}
reqFeatures=${this.reqFeatures?.joinToString { it.dumpToString() }}
requestedPermissions=${this.requestedPermissions?.contentToString()}
requestedPermissionsFlags=${this.requestedPermissionsFlags?.contentToString()}
requiredAccountType=${this.requiredAccountType}
requiredForAllUsers=${this.requiredForAllUsers}
restrictedAccountType=${this.restrictedAccountType}
- services=${this.services?.contentToString()}
+ services=${this.services?.joinToString { it.dumpToString() }
+ .ignored("Checked separately in test")}
sharedUserId=${this.sharedUserId}
sharedUserLabel=${this.sharedUserLabel}
signatures=${this.signatures?.joinToString { it.toCharsString() }}
@@ -378,11 +472,17 @@ open class AndroidPackageParsingTestBase {
versionName=${this.versionName}
""".trimIndent()
- @Suppress("unused")
- private fun <T> SparseArray<T>.sequence(): Sequence<Pair<Int, T>> {
- var index = 0
- return generateSequence {
- index++.takeIf { it < size() }?.let { keyAt(it) to valueAt(index) }
+ private fun Bundle?.dumpToString() = this?.keySet()?.associateWith { get(it) }?.toString()
+
+ private fun <T> SparseArray<T>?.dumpToString(): String {
+ if (this == null) {
+ return "EMPTY"
+ }
+
+ val list = mutableListOf<Pair<Int, T>>()
+ for (index in (0 until size())) {
+ list += keyAt(index) to valueAt(index)
}
+ return list.toString()
}
}
diff --git a/services/tests/servicestests/src/com/android/server/power/PreRebootLoggerTest.java b/services/tests/servicestests/src/com/android/server/power/PreRebootLoggerTest.java
index a13823441665..45574fc29ddc 100644
--- a/services/tests/servicestests/src/com/android/server/power/PreRebootLoggerTest.java
+++ b/services/tests/servicestests/src/com/android/server/power/PreRebootLoggerTest.java
@@ -23,6 +23,9 @@ import static com.google.common.truth.Truth.assertThat;
import static org.mockito.Mockito.when;
import android.content.Context;
+import android.content.pm.PackageInstaller;
+import android.content.pm.PackageInstaller.SessionInfo;
+import android.content.pm.PackageManager;
import android.provider.Settings;
import android.test.mock.MockContentResolver;
@@ -36,12 +39,15 @@ import com.google.common.io.Files;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
+import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
+import org.mockito.junit.MockitoJUnit;
+import org.mockito.junit.MockitoRule;
import java.io.File;
+import java.util.List;
/**
* Tests for {@link PreRebootLogger}
@@ -49,7 +55,11 @@ import java.io.File;
@SmallTest
@RunWith(AndroidJUnit4.class)
public class PreRebootLoggerTest {
+ @Rule public final MockitoRule mocks = MockitoJUnit.rule();
@Mock Context mContext;
+ @Mock PackageManager mPackageManager;
+ @Mock PackageInstaller mPackageInstaller;
+ @Mock List<SessionInfo> mSessions;
private MockContentResolver mContentResolver;
private File mDumpDir;
@@ -64,29 +74,53 @@ public class PreRebootLoggerTest {
}
@Before
- public void setup() {
- MockitoAnnotations.initMocks(this);
+ public void enableAdbConfig() {
mContentResolver = new MockContentResolver(getInstrumentation().getTargetContext());
when(mContext.getContentResolver()).thenReturn(mContentResolver);
mContentResolver.addProvider(Settings.AUTHORITY, new FakeSettingsProvider());
+ Settings.Global.putInt(mContentResolver, Settings.Global.ADB_ENABLED, 1);
+ }
+
+ @Before
+ public void prepareActiveStagedSessions() {
+ when(mContext.getPackageManager()).thenReturn(mPackageManager);
+ when(mPackageManager.getPackageInstaller()).thenReturn(mPackageInstaller);
+ when(mPackageInstaller.getActiveStagedSessions()).thenReturn(mSessions);
+ when(mSessions.isEmpty()).thenReturn(false);
+ }
+ @Before
+ public void setupDumpDir() {
mDumpDir = Files.createTempDir();
- mDumpDir.mkdir();
mDumpDir.deleteOnExit();
}
@Test
- public void log_adbEnabled_dumpsInformationProperly() {
- Settings.Global.putInt(mContentResolver, Settings.Global.ADB_ENABLED, 1);
-
+ public void log_dumpsInformationProperly() {
PreRebootLogger.log(mContext, mDumpDir);
assertThat(mDumpDir.list()).asList().containsExactly("system", "package", "rollback");
}
@Test
+ public void dump_exceedTimeout_wontBlockCurrentThread() {
+ PreRebootLogger.dump(mDumpDir, 1 /* maxWaitTime */);
+
+ assertThat(mDumpDir.listFiles()).asList().containsNoneOf("system", "package", "rollback");
+ }
+
+ @Test
+ public void log_noActiveStagedSession_wipesDumpedInformation() {
+ PreRebootLogger.log(mContext, mDumpDir);
+ when(mSessions.isEmpty()).thenReturn(true);
+
+ PreRebootLogger.log(mContext, mDumpDir);
+
+ assertThat(mDumpDir.listFiles()).isEmpty();
+ }
+
+ @Test
public void log_adbDisabled_wipesDumpedInformation() {
- Settings.Global.putInt(mContentResolver, Settings.Global.ADB_ENABLED, 1);
PreRebootLogger.log(mContext, mDumpDir);
Settings.Global.putInt(mContentResolver, Settings.Global.ADB_ENABLED, 0);
diff --git a/services/tests/servicestests/src/com/android/server/textclassifier/FixedSizeQueueTest.java b/services/tests/servicestests/src/com/android/server/textclassifier/FixedSizeQueueTest.java
new file mode 100644
index 000000000000..90527b82c2c3
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/textclassifier/FixedSizeQueueTest.java
@@ -0,0 +1,109 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.textclassifier;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import org.junit.Test;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class FixedSizeQueueTest {
+
+ @Test
+ public void add_belowMaxCapacity() {
+ FixedSizeQueue<Integer> queue = new FixedSizeQueue<>(1, /* onEntryEvictedListener= */ null);
+ assertThat(queue.size()).isEqualTo(0);
+
+ queue.add(1);
+
+ assertThat(queue.size()).isEqualTo(1);
+ assertThat(queue.poll()).isEqualTo(1);
+ }
+
+ @Test
+ public void add_exceedMaxCapacity() {
+ FixedSizeQueue<Integer> queue = new FixedSizeQueue<>(2, /* onEntryEvictedListener= */ null);
+
+ queue.add(1);
+ queue.add(2);
+ queue.add(3);
+
+ assertThat(queue.size()).isEqualTo(2);
+ assertThat(queue.poll()).isEqualTo(2);
+ assertThat(queue.poll()).isEqualTo(3);
+ }
+
+ @Test
+ public void poll() {
+ FixedSizeQueue<Integer> queue = new FixedSizeQueue<>(1, /* onEntryEvictedListener= */ null);
+
+ queue.add(1);
+
+ assertThat(queue.poll()).isEqualTo(1);
+ assertThat(queue.poll()).isNull();
+ }
+
+ @Test
+ public void remove() {
+ FixedSizeQueue<Integer> queue = new FixedSizeQueue<>(1, /* onEntryEvictedListener= */ null);
+
+ queue.add(1);
+
+ assertThat(queue.remove(1)).isTrue();
+ assertThat(queue.isEmpty()).isTrue();
+ }
+
+ @Test
+ public void remove_noSuchElement() {
+ FixedSizeQueue<Integer> queue = new FixedSizeQueue<>(1, /* onEntryEvictedListener= */ null);
+
+ queue.add(1);
+
+ assertThat(queue.remove(2)).isFalse();
+ }
+
+ @Test
+ public void isEmpty_true() {
+ FixedSizeQueue<Integer> queue = new FixedSizeQueue<>(1, /* onEntryEvictedListener= */ null);
+
+ assertThat(queue.isEmpty()).isTrue();
+ }
+
+ @Test
+ public void isEmpty_false() {
+ FixedSizeQueue<Integer> queue = new FixedSizeQueue<>(1, /* onEntryEvictedListener= */ null);
+
+ queue.add(1);
+
+ assertThat(queue.isEmpty()).isFalse();
+ }
+
+ @Test
+ public void onEntryEvicted() {
+ List<Integer> onEntryEvictedElements = new ArrayList<>();
+ FixedSizeQueue<Integer> queue =
+ new FixedSizeQueue<>(1, onEntryEvictedElements::add);
+
+ queue.add(1);
+ queue.add(2);
+ queue.add(3);
+
+ assertThat(onEntryEvictedElements).containsExactly(1, 2).inOrder();
+ }
+}
diff --git a/services/tests/servicestests/src/com/android/server/uri/UriGrantsManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/uri/UriGrantsManagerServiceTest.java
index e86399e1a631..62b6a65cc6cb 100644
--- a/services/tests/servicestests/src/com/android/server/uri/UriGrantsManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/uri/UriGrantsManagerServiceTest.java
@@ -60,14 +60,12 @@ import java.util.Set;
public class UriGrantsManagerServiceTest {
private UriGrantsMockContext mContext;
- private UriGrantsManagerService mService;
- private UriGrantsManagerInternal mLocalService;
+ private UriGrantsManagerInternal mService;
@Before
public void setUp() throws Exception {
mContext = new UriGrantsMockContext(InstrumentationRegistry.getContext());
- mService = UriGrantsManagerService.createForTest(mContext.getFilesDir());
- mLocalService = mService.getLocalService();
+ mService = UriGrantsManagerService.createForTest(mContext.getFilesDir()).getLocalService();
}
/**
@@ -80,8 +78,7 @@ public class UriGrantsManagerServiceTest {
final GrantUri expectedGrant = new GrantUri(USER_PRIMARY, URI_PHOTO_1, FLAG_READ);
final NeededUriGrants needed = mService.checkGrantUriPermissionFromIntent(
- UID_PRIMARY_CAMERA, PKG_SOCIAL, intent, intent.getFlags(), null,
- USER_PRIMARY);
+ intent, UID_PRIMARY_CAMERA, PKG_SOCIAL, USER_PRIMARY);
assertEquals(PKG_SOCIAL, needed.targetPkg);
assertEquals(UID_PRIMARY_SOCIAL, needed.targetUid);
assertEquals(FLAG_READ, needed.flags);
@@ -98,8 +95,7 @@ public class UriGrantsManagerServiceTest {
final GrantUri expectedGrant = new GrantUri(USER_PRIMARY, URI_PHOTO_1, FLAG_READ);
final NeededUriGrants needed = mService.checkGrantUriPermissionFromIntent(
- UID_PRIMARY_CAMERA, PKG_SOCIAL, intent, intent.getFlags(), null,
- USER_SECONDARY);
+ intent, UID_PRIMARY_CAMERA, PKG_SOCIAL, USER_SECONDARY);
assertEquals(PKG_SOCIAL, needed.targetPkg);
assertEquals(UID_SECONDARY_SOCIAL, needed.targetUid);
assertEquals(FLAG_READ, needed.flags);
@@ -113,8 +109,7 @@ public class UriGrantsManagerServiceTest {
public void testNeeded_public() {
final Intent intent = new Intent(Intent.ACTION_VIEW, URI_PUBLIC).addFlags(FLAG_READ);
final NeededUriGrants needed = mService.checkGrantUriPermissionFromIntent(
- UID_PRIMARY_PUBLIC, PKG_SOCIAL, intent, intent.getFlags(), null,
- USER_PRIMARY);
+ intent, UID_PRIMARY_PUBLIC, PKG_SOCIAL, USER_PRIMARY);
assertNull(needed);
}
@@ -128,7 +123,7 @@ public class UriGrantsManagerServiceTest {
final GrantUri expectedGrant = new GrantUri(USER_PRIMARY, URI_PUBLIC, FLAG_READ);
final NeededUriGrants needed = mService.checkGrantUriPermissionFromIntent(
- UID_PRIMARY_PUBLIC, PKG_SOCIAL, intent, intent.getFlags(), null, USER_SECONDARY);
+ intent, UID_PRIMARY_PUBLIC, PKG_SOCIAL, USER_SECONDARY);
assertEquals(PKG_SOCIAL, needed.targetPkg);
assertEquals(UID_SECONDARY_SOCIAL, needed.targetUid);
assertEquals(FLAG_READ, needed.flags);
@@ -143,7 +138,7 @@ public class UriGrantsManagerServiceTest {
final Intent intent = new Intent(Intent.ACTION_VIEW, URI_PRIVATE).addFlags(FLAG_READ);
try {
mService.checkGrantUriPermissionFromIntent(
- UID_PRIMARY_PRIVATE, PKG_SOCIAL, intent, intent.getFlags(), null, USER_PRIMARY);
+ intent, UID_PRIMARY_PRIVATE, PKG_SOCIAL, USER_PRIMARY);
fail();
} catch (SecurityException expected) {
}
@@ -158,7 +153,7 @@ public class UriGrantsManagerServiceTest {
final Intent intent = new Intent(Intent.ACTION_VIEW, URI_FORCE)
.addFlags(FLAG_READ);
final NeededUriGrants needed = mService.checkGrantUriPermissionFromIntent(
- UID_PRIMARY_FORCE, PKG_FORCE, intent, intent.getFlags(), null, USER_PRIMARY);
+ intent, UID_PRIMARY_FORCE, PKG_FORCE, USER_PRIMARY);
assertEquals(asSet(new GrantUri(USER_PRIMARY, URI_FORCE, 0)), needed.uris);
}
@@ -172,15 +167,15 @@ public class UriGrantsManagerServiceTest {
{
final Intent intent = new Intent(Intent.ACTION_VIEW, uri)
.addFlags(FLAG_READ | Intent.FLAG_ACTIVITY_CLEAR_TASK);
- assertNull(mService.checkGrantUriPermissionFromIntent(UID_PRIMARY_COMPLEX, PKG_SOCIAL,
- intent, intent.getFlags(), null, USER_PRIMARY));
+ assertNull(mService.checkGrantUriPermissionFromIntent(
+ intent, UID_PRIMARY_COMPLEX, PKG_SOCIAL, USER_PRIMARY));
}
{
final Intent intent = new Intent(Intent.ACTION_VIEW, uri)
.addFlags(FLAG_READ | FLAG_PREFIX);
try {
- mService.checkGrantUriPermissionFromIntent(UID_PRIMARY_COMPLEX, PKG_SOCIAL,
- intent, intent.getFlags(), null, USER_PRIMARY);
+ mService.checkGrantUriPermissionFromIntent(
+ intent, UID_PRIMARY_COMPLEX, PKG_SOCIAL, USER_PRIMARY);
fail();
} catch (SecurityException expected) {
}
@@ -189,8 +184,8 @@ public class UriGrantsManagerServiceTest {
final Intent intent = new Intent(Intent.ACTION_VIEW, uri)
.addFlags(FLAG_READ | FLAG_PERSISTABLE);
try {
- mService.checkGrantUriPermissionFromIntent(UID_PRIMARY_COMPLEX, PKG_SOCIAL,
- intent, intent.getFlags(), null, USER_PRIMARY);
+ mService.checkGrantUriPermissionFromIntent(
+ intent, UID_PRIMARY_COMPLEX, PKG_SOCIAL, USER_PRIMARY);
fail();
} catch (SecurityException expected) {
}
@@ -209,8 +204,7 @@ public class UriGrantsManagerServiceTest {
final Intent intent = new Intent(Intent.ACTION_VIEW, uri)
.addFlags(FLAG_READ);
final NeededUriGrants needed = mService.checkGrantUriPermissionFromIntent(
- UID_PRIMARY_COMPLEX, PKG_SOCIAL, intent, intent.getFlags(), null,
- USER_SECONDARY);
+ intent, UID_PRIMARY_COMPLEX, PKG_SOCIAL, USER_SECONDARY);
assertEquals(FLAG_READ, needed.flags);
}
{
@@ -218,8 +212,7 @@ public class UriGrantsManagerServiceTest {
.addFlags(FLAG_READ | FLAG_PREFIX);
try {
mService.checkGrantUriPermissionFromIntent(
- UID_PRIMARY_COMPLEX, PKG_SOCIAL, intent, intent.getFlags(), null,
- USER_SECONDARY);
+ intent, UID_PRIMARY_COMPLEX, PKG_SOCIAL, USER_SECONDARY);
fail();
} catch (SecurityException expected) {
}
@@ -229,8 +222,7 @@ public class UriGrantsManagerServiceTest {
.addFlags(FLAG_READ | FLAG_PERSISTABLE);
try {
mService.checkGrantUriPermissionFromIntent(
- UID_PRIMARY_COMPLEX, PKG_SOCIAL, intent, intent.getFlags(), null,
- USER_SECONDARY);
+ intent, UID_PRIMARY_COMPLEX, PKG_SOCIAL, USER_SECONDARY);
fail();
} catch (SecurityException expected) {
}
@@ -248,21 +240,21 @@ public class UriGrantsManagerServiceTest {
final Intent intent = new Intent(Intent.ACTION_VIEW, uri)
.addFlags(FLAG_READ);
final NeededUriGrants needed = mService.checkGrantUriPermissionFromIntent(
- UID_PRIMARY_COMPLEX, PKG_SOCIAL, intent, intent.getFlags(), null, USER_PRIMARY);
+ intent, UID_PRIMARY_COMPLEX, PKG_SOCIAL, USER_PRIMARY);
assertEquals(asSet(new GrantUri(USER_PRIMARY, uri, 0)), needed.uris);
}
{
final Intent intent = new Intent(Intent.ACTION_VIEW, uri)
.addFlags(FLAG_READ | FLAG_PREFIX);
final NeededUriGrants needed = mService.checkGrantUriPermissionFromIntent(
- UID_PRIMARY_COMPLEX, PKG_SOCIAL, intent, intent.getFlags(), null, USER_PRIMARY);
+ intent, UID_PRIMARY_COMPLEX, PKG_SOCIAL, USER_PRIMARY);
assertEquals(asSet(new GrantUri(USER_PRIMARY, uri, FLAG_PREFIX)), needed.uris);
}
{
final Intent intent = new Intent(Intent.ACTION_VIEW, uri)
.addFlags(FLAG_READ | FLAG_PERSISTABLE);
final NeededUriGrants needed = mService.checkGrantUriPermissionFromIntent(
- UID_PRIMARY_COMPLEX, PKG_SOCIAL, intent, intent.getFlags(), null, USER_PRIMARY);
+ intent, UID_PRIMARY_COMPLEX, PKG_SOCIAL, USER_PRIMARY);
assertEquals(asSet(new GrantUri(USER_PRIMARY, uri, 0)), needed.uris);
}
}
@@ -284,8 +276,8 @@ public class UriGrantsManagerServiceTest {
// When granting towards primary, persistable can't be honored so
// the entire grant fails
try {
- mService.checkGrantUriPermissionFromIntent(UID_PRIMARY_CAMERA, PKG_SOCIAL, intent,
- intent.getFlags(), null, USER_PRIMARY);
+ mService.checkGrantUriPermissionFromIntent(
+ intent, UID_PRIMARY_CAMERA, PKG_SOCIAL, USER_PRIMARY);
fail();
} catch (SecurityException expected) {
}
@@ -294,8 +286,8 @@ public class UriGrantsManagerServiceTest {
// When granting towards secondary, persistable can't be honored so
// the entire grant fails
try {
- mService.checkGrantUriPermissionFromIntent(UID_PRIMARY_CAMERA, PKG_SOCIAL, intent,
- intent.getFlags(), null, USER_SECONDARY);
+ mService.checkGrantUriPermissionFromIntent(
+ intent, UID_PRIMARY_CAMERA, PKG_SOCIAL, USER_SECONDARY);
fail();
} catch (SecurityException expected) {
}
@@ -310,18 +302,16 @@ public class UriGrantsManagerServiceTest {
public void testGrant_overlap() {
final Intent intent = new Intent(Intent.ACTION_VIEW, URI_PHOTO_1).addFlags(FLAG_READ);
- final UriPermissionOwner activity = new UriPermissionOwner(mLocalService, "activity");
- final UriPermissionOwner service = new UriPermissionOwner(mLocalService, "service");
+ final UriPermissionOwner activity = new UriPermissionOwner(mService, "activity");
+ final UriPermissionOwner service = new UriPermissionOwner(mService, "service");
final GrantUri expectedGrant = new GrantUri(USER_PRIMARY, URI_PHOTO_1, FLAG_READ);
// Grant read via activity and write via service
mService.grantUriPermissionUncheckedFromIntent(mService.checkGrantUriPermissionFromIntent(
- UID_PRIMARY_CAMERA, PKG_SOCIAL, intent, intent.getFlags(), null, USER_PRIMARY),
- activity);
+ intent, UID_PRIMARY_CAMERA, PKG_SOCIAL, USER_PRIMARY), activity);
mService.grantUriPermissionUncheckedFromIntent(mService.checkGrantUriPermissionFromIntent(
- UID_PRIMARY_CAMERA, PKG_SOCIAL, intent, intent.getFlags(), null, USER_PRIMARY),
- service);
+ intent, UID_PRIMARY_CAMERA, PKG_SOCIAL, USER_PRIMARY), service);
// Verify that everything is good with the world
assertTrue(mService.checkUriPermission(expectedGrant, UID_PRIMARY_SOCIAL, FLAG_READ));
@@ -338,7 +328,7 @@ public class UriGrantsManagerServiceTest {
@Test
public void testCheckAuthorityGrants() {
final Intent intent = new Intent(Intent.ACTION_VIEW, URI_PHOTO_1).addFlags(FLAG_READ);
- final UriPermissionOwner owner = new UriPermissionOwner(mLocalService, "primary");
+ final UriPermissionOwner owner = new UriPermissionOwner(mService, "primary");
final ProviderInfo cameraInfo = mContext.mPmInternal.resolveContentProvider(
PKG_CAMERA, 0, USER_PRIMARY);
@@ -355,8 +345,7 @@ public class UriGrantsManagerServiceTest {
// Granting primary camera to primary social
mService.grantUriPermissionUncheckedFromIntent(mService.checkGrantUriPermissionFromIntent(
- UID_PRIMARY_CAMERA, PKG_SOCIAL, intent, intent.getFlags(), null, USER_PRIMARY),
- owner);
+ intent, UID_PRIMARY_CAMERA, PKG_SOCIAL, USER_PRIMARY), owner);
assertTrue(mService.checkAuthorityGrants(UID_PRIMARY_SOCIAL,
cameraInfo, USER_PRIMARY, true));
assertFalse(mService.checkAuthorityGrants(UID_PRIMARY_SOCIAL,
@@ -368,8 +357,7 @@ public class UriGrantsManagerServiceTest {
// Granting secondary camera to primary social
mService.grantUriPermissionUncheckedFromIntent(mService.checkGrantUriPermissionFromIntent(
- UID_SECONDARY_CAMERA, PKG_SOCIAL, intent, intent.getFlags(), null, USER_PRIMARY),
- owner);
+ intent, UID_SECONDARY_CAMERA, PKG_SOCIAL, USER_PRIMARY), owner);
assertTrue(mService.checkAuthorityGrants(UID_PRIMARY_SOCIAL,
cameraInfo, USER_PRIMARY, true));
assertTrue(mService.checkAuthorityGrants(UID_PRIMARY_SOCIAL,
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/BadgeExtractorTest.java b/services/tests/uiservicestests/src/com/android/server/notification/BadgeExtractorTest.java
index e1f39137e618..c9c31bfcde08 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/BadgeExtractorTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/BadgeExtractorTest.java
@@ -29,6 +29,10 @@ import android.app.ActivityManager;
import android.app.Notification;
import android.app.Notification.Builder;
import android.app.NotificationChannel;
+import android.app.PendingIntent;
+import android.content.Intent;
+import android.graphics.drawable.Icon;
+
import android.os.UserHandle;
import android.service.notification.StatusBarNotification;
import android.test.suitebuilder.annotation.SmallTest;
@@ -79,6 +83,37 @@ public class BadgeExtractorTest extends UiServiceTestCase {
return r;
}
+ private NotificationRecord getNotificationRecordWithBubble(boolean suppressNotif) {
+ NotificationChannel channel = new NotificationChannel("a", "a", IMPORTANCE_UNSPECIFIED);
+ channel.setShowBadge(/* showBadge */ true);
+ when(mConfig.getNotificationChannel(mPkg, mUid, "a", false)).thenReturn(channel);
+
+ Notification.BubbleMetadata metadata = new Notification.BubbleMetadata.Builder(
+ PendingIntent.getActivity(mContext, 0, new Intent(), 0),
+ Icon.createWithResource("", 0)).build();
+
+ int flags = metadata.getFlags();
+ if (suppressNotif) {
+ flags |= Notification.BubbleMetadata.FLAG_SUPPRESS_NOTIFICATION;
+ } else {
+ flags &= ~Notification.BubbleMetadata.FLAG_SUPPRESS_NOTIFICATION;
+ }
+ metadata.setFlags(flags);
+
+ final Builder builder = new Builder(getContext())
+ .setContentTitle("foo")
+ .setSmallIcon(android.R.drawable.sym_def_app_icon)
+ .setPriority(Notification.PRIORITY_HIGH)
+ .setDefaults(Notification.DEFAULT_SOUND)
+ .setBubbleMetadata(metadata);
+
+ Notification n = builder.build();
+ StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, mId, mTag, mUid,
+ mPid, n, mUser, null, System.currentTimeMillis());
+ NotificationRecord r = new NotificationRecord(getContext(), sbn, channel);
+ return r;
+ }
+
//
// Tests
//
@@ -154,6 +189,20 @@ public class BadgeExtractorTest extends UiServiceTestCase {
}
@Test
+ public void testHideNotifOverridesYes() throws Exception {
+ BadgeExtractor extractor = new BadgeExtractor();
+ extractor.setConfig(mConfig);
+
+ when(mConfig.badgingEnabled(mUser)).thenReturn(true);
+ when(mConfig.canShowBadge(mPkg, mUid)).thenReturn(true);
+ NotificationRecord r = getNotificationRecordWithBubble(/* suppressNotif */ true);
+
+ extractor.process(r);
+
+ assertFalse(r.canShowBadge());
+ }
+
+ @Test
public void testDndOverridesYes() {
BadgeExtractor extractor = new BadgeExtractor();
extractor.setConfig(mConfig);
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationHistoryDatabaseTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationHistoryDatabaseTest.java
index 80b474ff7128..6991c18ceb82 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationHistoryDatabaseTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationHistoryDatabaseTest.java
@@ -360,13 +360,12 @@ public class NotificationHistoryDatabaseTest extends UiServiceTestCase {
mDataBase.new WriteBufferRunnable();
mDataBase.mBuffer = nh;
- wbr.currentTime = 5;
- wbr.latestNotificationsFile = mock(AtomicFile.class);
+ AtomicFile af = mock(AtomicFile.class);
File file = mock(File.class);
when(file.getName()).thenReturn("5");
- when(wbr.latestNotificationsFile.getBaseFile()).thenReturn(file);
+ when(af.getBaseFile()).thenReturn(file);
- wbr.run();
+ wbr.run(5, af);
assertThat(mDataBase.mHistoryFiles.size()).isEqualTo(1);
assertThat(mDataBase.mBuffer).isNotEqualTo(nh);
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 de9b77c68336..ef4d5db2f32f 100755
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
@@ -178,6 +178,7 @@ import com.android.server.wm.WindowManagerInternal;
import org.junit.After;
import org.junit.Before;
+import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
@@ -347,6 +348,11 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
super.setNotificationAssistantAccessGrantedForUserInternal(assistant, userId, granted);
}
+ @Override
+ protected String[] getStringArrayResource(int key) {
+ return new String[] {PKG_O};
+ }
+
private void setNotificationAssistantAccessGrantedCallback(
@Nullable NotificationAssistantAccessGrantedCallback callback) {
this.mNotificationAssistantAccessGrantedCallback = callback;
@@ -434,7 +440,8 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
// Setup managed services
mListener = mListeners.new ManagedServiceInfo(
- null, new ComponentName(PKG, "test_class"), mUid, true, null, 0);
+ null, new ComponentName(PKG, "test_class"),
+ UserHandle.getUserId(mUid), true, null, 0);
ComponentName defaultComponent = ComponentName.unflattenFromString("config/device");
ArraySet<ComponentName> components = new ArraySet<>();
components.add(defaultComponent);
@@ -444,7 +451,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
when(mAssistants.getDefaultComponents()).thenReturn(components);
when(mAssistants.queryPackageForServices(
anyString(), anyInt(), anyInt())).thenReturn(components);
- when(mListeners.checkServiceTokenLocked(any())).thenReturn(mListener);
+ when(mListeners.checkServiceTokenLocked(null)).thenReturn(mListener);
ManagedServices.Config listenerConfig = new ManagedServices.Config();
listenerConfig.xmlTag = NotificationListeners.TAG_ENABLED_NOTIFICATION_LISTENERS;
when(mListeners.getConfig()).thenReturn(listenerConfig);
@@ -497,6 +504,10 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
mBinderService.createNotificationChannels(
PKG, new ParceledListSlice(Arrays.asList(mTestNotificationChannel)));
+ mBinderService.createNotificationChannels(
+ PKG_P, new ParceledListSlice(Arrays.asList(mTestNotificationChannel)));
+ mBinderService.createNotificationChannels(
+ PKG_O, new ParceledListSlice(Arrays.asList(mTestNotificationChannel)));
assertNotNull(mBinderService.getNotificationChannel(
PKG, mContext.getUserId(), PKG, TEST_CHANNEL_ID));
clearInvocations(mRankingHandler);
@@ -583,7 +594,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
.setGroupSummary(isSummary);
StatusBarNotification sbn = new StatusBarNotification(PKG, PKG, id,
"tag" + System.currentTimeMillis(), mUid, 0,
- nb.build(), new UserHandle(mUid), null, 0);
+ nb.build(), UserHandle.getUserHandleForUid(mUid), null, 0);
return new NotificationRecord(mContext, sbn, channel);
}
@@ -603,7 +614,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
nb.extend(extender);
}
StatusBarNotification sbn = new StatusBarNotification(PKG, PKG, 8, "tag", mUid, 0,
- nb.build(), new UserHandle(mUid), null, 0);
+ nb.build(), UserHandle.getUserHandleForUid(mUid), null, 0);
return new NotificationRecord(mContext, sbn, channel);
}
@@ -635,7 +646,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
Notification.Builder nb = getMessageStyleNotifBuilder(addMetadata, groupKey, isSummary);
StatusBarNotification sbn = new StatusBarNotification(PKG, PKG, id,
tag, mUid, 0,
- nb.build(), new UserHandle(mUid), null, 0);
+ nb.build(), UserHandle.getUserHandleForUid(mUid), null, 0);
return new NotificationRecord(mContext, sbn, channel);
}
@@ -1328,6 +1339,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
}
@Test
+ @Ignore
public void testPostCancelPostNotifiesListeners() throws Exception {
// WHEN a notification is posted
final StatusBarNotification sbn = generateNotificationRecord(null).getSbn();
@@ -1687,7 +1699,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
.setSmallIcon(android.R.drawable.sym_def_app_icon)
.build();
StatusBarNotification sbn = new StatusBarNotification("a", "a", 0, null, mUid, 0,
- n, new UserHandle(mUid), null, 0);
+ n, UserHandle.getUserHandleForUid(mUid), null, 0);
sbn.getNotification().flags |= FLAG_FOREGROUND_SERVICE;
mBinderService.enqueueNotificationWithTag(PKG, PKG, null,
sbn.getId(), sbn.getNotification(), sbn.getUserId());
@@ -2191,7 +2203,8 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
public void testCreateChannelNotifyListener() throws Exception {
List<String> associations = new ArrayList<>();
associations.add("a");
- when(mCompanionMgr.getAssociations(PKG, mUid)).thenReturn(associations);
+ when(mCompanionMgr.getAssociations(PKG, UserHandle.getUserId(mUid)))
+ .thenReturn(associations);
mService.setPreferencesHelper(mPreferencesHelper);
when(mPreferencesHelper.getNotificationChannel(eq(PKG), anyInt(),
eq(mTestNotificationChannel.getId()), anyBoolean()))
@@ -2219,7 +2232,8 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
public void testCreateChannelGroupNotifyListener() throws Exception {
List<String> associations = new ArrayList<>();
associations.add("a");
- when(mCompanionMgr.getAssociations(PKG, mUid)).thenReturn(associations);
+ when(mCompanionMgr.getAssociations(PKG, UserHandle.getUserId(mUid)))
+ .thenReturn(associations);
mService.setPreferencesHelper(mPreferencesHelper);
NotificationChannelGroup group1 = new NotificationChannelGroup("a", "b");
NotificationChannelGroup group2 = new NotificationChannelGroup("n", "m");
@@ -2239,7 +2253,8 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
public void testUpdateChannelNotifyListener() throws Exception {
List<String> associations = new ArrayList<>();
associations.add("a");
- when(mCompanionMgr.getAssociations(PKG, mUid)).thenReturn(associations);
+ when(mCompanionMgr.getAssociations(PKG, UserHandle.getUserId(mUid)))
+ .thenReturn(associations);
mService.setPreferencesHelper(mPreferencesHelper);
mTestNotificationChannel.setLightColor(Color.CYAN);
when(mPreferencesHelper.getNotificationChannel(eq(PKG), anyInt(),
@@ -2257,7 +2272,8 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
public void testDeleteChannelNotifyListener() throws Exception {
List<String> associations = new ArrayList<>();
associations.add("a");
- when(mCompanionMgr.getAssociations(PKG, mUid)).thenReturn(associations);
+ when(mCompanionMgr.getAssociations(PKG, UserHandle.getUserId(mUid)))
+ .thenReturn(associations);
mService.setPreferencesHelper(mPreferencesHelper);
when(mPreferencesHelper.getNotificationChannel(eq(PKG), anyInt(),
eq(mTestNotificationChannel.getId()), anyBoolean()))
@@ -2273,7 +2289,8 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
public void testDeleteChannelGroupNotifyListener() throws Exception {
List<String> associations = new ArrayList<>();
associations.add("a");
- when(mCompanionMgr.getAssociations(PKG, mUid)).thenReturn(associations);
+ when(mCompanionMgr.getAssociations(PKG, UserHandle.getUserId(mUid)))
+ .thenReturn(associations);
NotificationChannelGroup ncg = new NotificationChannelGroup("a", "b/c");
mService.setPreferencesHelper(mPreferencesHelper);
when(mPreferencesHelper.getNotificationChannelGroup(eq(ncg.getId()), eq(PKG), anyInt()))
@@ -2290,7 +2307,8 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
mService.setPreferencesHelper(mPreferencesHelper);
List<String> associations = new ArrayList<>();
associations.add("a");
- when(mCompanionMgr.getAssociations(PKG, mUid)).thenReturn(associations);
+ when(mCompanionMgr.getAssociations(PKG, UserHandle.getUserId(mUid)))
+ .thenReturn(associations);
when(mPreferencesHelper.getNotificationChannel(eq(PKG), anyInt(),
eq(mTestNotificationChannel.getId()), anyBoolean()))
.thenReturn(mTestNotificationChannel);
@@ -2310,7 +2328,8 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
public void testUpdateNotificationChannelFromPrivilegedListener_noAccess() throws Exception {
mService.setPreferencesHelper(mPreferencesHelper);
List<String> associations = new ArrayList<>();
- when(mCompanionMgr.getAssociations(PKG, mUid)).thenReturn(associations);
+ when(mCompanionMgr.getAssociations(PKG, UserHandle.getUserId(mUid)))
+ .thenReturn(associations);
try {
mBinderService.updateNotificationChannelFromPrivilegedListener(
@@ -2333,7 +2352,8 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
mService.setPreferencesHelper(mPreferencesHelper);
List<String> associations = new ArrayList<>();
associations.add("a");
- when(mCompanionMgr.getAssociations(PKG, mUid)).thenReturn(associations);
+ when(mCompanionMgr.getAssociations(PKG, UserHandle.getUserId(mUid)))
+ .thenReturn(associations);
mListener = mock(ManagedServices.ManagedServiceInfo.class);
mListener.component = new ComponentName(PKG, PKG);
when(mListener.enabledAndUserMatches(anyInt())).thenReturn(false);
@@ -2360,7 +2380,8 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
mService.setPreferencesHelper(mPreferencesHelper);
List<String> associations = new ArrayList<>();
associations.add("a");
- when(mCompanionMgr.getAssociations(PKG, mUid)).thenReturn(associations);
+ when(mCompanionMgr.getAssociations(PKG, UserHandle.getUserId(mUid)))
+ .thenReturn(associations);
mBinderService.getNotificationChannelsFromPrivilegedListener(
null, PKG, Process.myUserHandle());
@@ -2373,7 +2394,8 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
public void testGetNotificationChannelFromPrivilegedListener_cdm_noAccess() throws Exception {
mService.setPreferencesHelper(mPreferencesHelper);
List<String> associations = new ArrayList<>();
- when(mCompanionMgr.getAssociations(PKG, mUid)).thenReturn(associations);
+ when(mCompanionMgr.getAssociations(PKG, UserHandle.getUserId(mUid)))
+ .thenReturn(associations);
try {
mBinderService.getNotificationChannelsFromPrivilegedListener(
@@ -2391,7 +2413,8 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
public void testGetNotificationChannelFromPrivilegedListener_assistant_success()
throws Exception {
mService.setPreferencesHelper(mPreferencesHelper);
- when(mCompanionMgr.getAssociations(PKG, mUid)).thenReturn(new ArrayList<>());
+ when(mCompanionMgr.getAssociations(PKG, UserHandle.getUserId(mUid)))
+ .thenReturn(new ArrayList<>());
when(mAssistants.isServiceTokenValidLocked(any())).thenReturn(true);
mBinderService.getNotificationChannelsFromPrivilegedListener(
@@ -2405,7 +2428,8 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
public void testGetNotificationChannelFromPrivilegedListener_assistant_noAccess()
throws Exception {
mService.setPreferencesHelper(mPreferencesHelper);
- when(mCompanionMgr.getAssociations(PKG, mUid)).thenReturn(new ArrayList<>());
+ when(mCompanionMgr.getAssociations(PKG, UserHandle.getUserId(mUid)))
+ .thenReturn(new ArrayList<>());
when(mAssistants.isServiceTokenValidLocked(any())).thenReturn(false);
try {
@@ -2425,7 +2449,8 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
mService.setPreferencesHelper(mPreferencesHelper);
List<String> associations = new ArrayList<>();
associations.add("a");
- when(mCompanionMgr.getAssociations(PKG, mUid)).thenReturn(associations);
+ when(mCompanionMgr.getAssociations(PKG, UserHandle.getUserId(mUid)))
+ .thenReturn(associations);
mListener = mock(ManagedServices.ManagedServiceInfo.class);
when(mListener.enabledAndUserMatches(anyInt())).thenReturn(false);
when(mListeners.checkServiceTokenLocked(any())).thenReturn(mListener);
@@ -2447,7 +2472,8 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
mService.setPreferencesHelper(mPreferencesHelper);
List<String> associations = new ArrayList<>();
associations.add("a");
- when(mCompanionMgr.getAssociations(PKG, mUid)).thenReturn(associations);
+ when(mCompanionMgr.getAssociations(PKG, UserHandle.getUserId(mUid)))
+ .thenReturn(associations);
mBinderService.getNotificationChannelGroupsFromPrivilegedListener(
null, PKG, Process.myUserHandle());
@@ -2459,7 +2485,8 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
public void testGetNotificationChannelGroupsFromPrivilegedListener_noAccess() throws Exception {
mService.setPreferencesHelper(mPreferencesHelper);
List<String> associations = new ArrayList<>();
- when(mCompanionMgr.getAssociations(PKG, mUid)).thenReturn(associations);
+ when(mCompanionMgr.getAssociations(PKG, UserHandle.getUserId(mUid)))
+ .thenReturn(associations);
try {
mBinderService.getNotificationChannelGroupsFromPrivilegedListener(
@@ -2476,7 +2503,8 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
public void testGetNotificationChannelGroupsFromPrivilegedListener_badUser() throws Exception {
mService.setPreferencesHelper(mPreferencesHelper);
List<String> associations = new ArrayList<>();
- when(mCompanionMgr.getAssociations(PKG, mUid)).thenReturn(associations);
+ when(mCompanionMgr.getAssociations(PKG, UserHandle.getUserId(mUid)))
+ .thenReturn(associations);
mListener = mock(ManagedServices.ManagedServiceInfo.class);
when(mListener.enabledAndUserMatches(anyInt())).thenReturn(false);
when(mListeners.checkServiceTokenLocked(any())).thenReturn(mListener);
@@ -3026,8 +3054,6 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
mBinderService.setNotificationAssistantAccessGranted(c, true);
verify(mListeners).migrateToXml();
- verify(mListeners).notifyNotificationChannelChanged(anyString(), any(), any(),
- anyInt());
verify(mConditionProviders).setPackageOrComponentEnabled(
anyString(), anyInt(), anyBoolean(), anyBoolean());
verify(mAssistants).migrateToXml();
@@ -3041,8 +3067,6 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
mBinderService.setNotificationPolicyAccessGranted(c.getPackageName(), true);
verify(mListeners).migrateToXml();
- verify(mListeners).notifyNotificationChannelChanged(anyString(), any(), any(),
- anyInt());
verify(mConditionProviders).setPackageOrComponentEnabled(
anyString(), anyInt(), anyBoolean(), anyBoolean());
verify(mAssistants).migrateToXml();
@@ -3178,7 +3202,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
.setSmallIcon(android.R.drawable.sym_def_app_icon);
StatusBarNotification sbn = new StatusBarNotification(PKG, PKG, 1,
"testNoFakeColorizedPermission", mUid, 0,
- nb.build(), new UserHandle(mUid), null, 0);
+ nb.build(), UserHandle.getUserHandleForUid(mUid), null, 0);
NotificationRecord nr = new NotificationRecord(mContext, sbn, mTestNotificationChannel);
mBinderService.enqueueNotificationWithTag(PKG, PKG, sbn.getTag(),
@@ -3216,7 +3240,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
.build();
StatusBarNotification sbn = new StatusBarNotification("a", "a", 0, "tag", mUid, 0,
- n, new UserHandle(mUid), null, 0);
+ n, UserHandle.getUserHandleForUid(mUid), null, 0);
NotificationRecord otherPackage =
new NotificationRecord(mContext, sbn, mTestNotificationChannel);
mService.addEnqueuedNotification(otherPackage);
@@ -3224,7 +3248,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
// Same notifications are enqueued as posted, everything counts b/c id and tag don't match
// anything that's currently enqueued or posted
- int userId = new UserHandle(mUid).getIdentifier();
+ int userId = UserHandle.getUserId(mUid);
assertEquals(40,
mService.getNotificationCountLocked(PKG, userId, 0, null));
assertEquals(40,
@@ -3441,8 +3465,8 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
StatusBarNotification sbn = new StatusBarNotification(preOPkg, preOPkg, 9,
"testBumpFGImportance_noChannelChangePreOApp",
- Binder.getCallingUid(), 0, nb.build(), new UserHandle(Binder.getCallingUid()), null,
- 0);
+ Binder.getCallingUid(), 0, nb.build(),
+ UserHandle.getUserHandleForUid(Binder.getCallingUid()), null, 0);
mBinderService.enqueueNotificationWithTag(sbn.getPackageName(), sbn.getOpPkg(),
sbn.getTag(), sbn.getId(), sbn.getNotification(), sbn.getUserId());
@@ -3459,7 +3483,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
sbn = new StatusBarNotification(preOPkg, preOPkg, 9,
"testBumpFGImportance_noChannelChangePreOApp", Binder.getCallingUid(),
- 0, nb.build(), new UserHandle(Binder.getCallingUid()), null, 0);
+ 0, nb.build(), UserHandle.getUserHandleForUid(Binder.getCallingUid()), null, 0);
mBinderService.enqueueNotificationWithTag(preOPkg, preOPkg,
"testBumpFGImportance_noChannelChangePreOApp",
@@ -3813,7 +3837,8 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
.addMessage(message1)
.addMessage(message2));
NotificationRecord recordA = new NotificationRecord(mContext, new StatusBarNotification(
- PKG, PKG, 0, "tag", mUid, 0, nbA.build(), new UserHandle(mUid), null, 0), c);
+ PKG, PKG, 0, "tag", mUid, 0, nbA.build(), UserHandle.getUserHandleForUid(mUid),
+ null, 0), c);
// First post means we grant access to both
reset(mUgm);
@@ -3831,7 +3856,8 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
.setSmallIcon(android.R.drawable.sym_def_app_icon)
.setStyle(new Notification.MessagingStyle("").addMessage(message2));
NotificationRecord recordB = new NotificationRecord(mContext, new StatusBarNotification(PKG,
- PKG, 0, "tag", mUid, 0, nbB.build(), new UserHandle(mUid), null, 0), c);
+ PKG, 0, "tag", mUid, 0, nbB.build(), UserHandle.getUserHandleForUid(mUid), null, 0),
+ c);
// Update means we drop access to first
reset(mUgmInternal);
@@ -3870,7 +3896,8 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
.setStyle(new Notification.MessagingStyle("")
.addMessage(message1));
NotificationRecord recordA = new NotificationRecord(mContext, new StatusBarNotification(
- PKG, PKG, 0, "tag", mUid, 0, nbA.build(), new UserHandle(mUid), null, 0), c);
+ PKG, PKG, 0, "tag", mUid, 0, nbA.build(), UserHandle.getUserHandleForUid(mUid),
+ null, 0), c);
doThrow(new SecurityException("no access")).when(mUgm)
.grantUriPermissionFromOwner(
@@ -4029,7 +4056,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
Notification.Builder nb1 = new Notification.Builder(mContext, "")
.setContentTitle("foo");
StatusBarNotification sbn1 = new StatusBarNotification(PKG, PKG, 0, "tag", mUid, 0,
- nb1.build(), new UserHandle(mUid), null, 0);
+ nb1.build(), UserHandle.getUserHandleForUid(mUid), null, 0);
NotificationRecord r1 =
new NotificationRecord(mContext, sbn1, mock(NotificationChannel.class));
@@ -4037,7 +4064,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
.setFlag(FLAG_FOREGROUND_SERVICE, true)
.setContentTitle("bar");
StatusBarNotification sbn2 = new StatusBarNotification(PKG, PKG, 0, "tag", mUid, 0,
- nb2.build(), new UserHandle(mUid), null, 0);
+ nb2.build(), UserHandle.getUserHandleForUid(mUid), null, 0);
NotificationRecord r2 =
new NotificationRecord(mContext, sbn2, mock(NotificationChannel.class));
@@ -4049,14 +4076,14 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
Notification.Builder nb1 = new Notification.Builder(mContext, "")
.setContentTitle("foo");
StatusBarNotification sbn1 = new StatusBarNotification(PKG, PKG, 0, "tag", mUid, 0,
- nb1.build(), new UserHandle(mUid), null, 0);
+ nb1.build(), UserHandle.getUserHandleForUid(mUid), null, 0);
NotificationRecord r1 =
new NotificationRecord(mContext, sbn1, mock(NotificationChannel.class));
Notification.Builder nb2 = new Notification.Builder(mContext, "")
.setContentTitle("bar");
StatusBarNotification sbn2 = new StatusBarNotification(PKG, PKG, 0, "tag", mUid, 0,
- nb2.build(), new UserHandle(mUid), null, 0);
+ nb2.build(), UserHandle.getUserHandleForUid(mUid), null, 0);
NotificationRecord r2 =
new NotificationRecord(mContext, sbn2, mock(NotificationChannel.class));
@@ -4069,7 +4096,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
.setStyle(new Notification.InboxStyle()
.addLine("line1").addLine("line2"));
StatusBarNotification sbn1 = new StatusBarNotification(PKG, PKG, 0, "tag", mUid, 0,
- nb1.build(), new UserHandle(mUid), null, 0);
+ nb1.build(), UserHandle.getUserHandleForUid(mUid), null, 0);
NotificationRecord r1 =
new NotificationRecord(mContext, sbn1, mock(NotificationChannel.class));
@@ -4077,7 +4104,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
.setStyle(new Notification.InboxStyle()
.addLine("line1").addLine("line2_changed"));
StatusBarNotification sbn2 = new StatusBarNotification(PKG, PKG, 0, "tag", mUid, 0,
- nb2.build(), new UserHandle(mUid), null, 0);
+ nb2.build(), UserHandle.getUserHandleForUid(mUid), null, 0);
NotificationRecord r2 =
new NotificationRecord(mContext, sbn2, mock(NotificationChannel.class));
@@ -4087,7 +4114,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
.setStyle(new Notification.InboxStyle()
.addLine("line1"));
StatusBarNotification sbn3 = new StatusBarNotification(PKG, PKG, 0, "tag", mUid, 0,
- nb3.build(), new UserHandle(mUid), null, 0);
+ nb3.build(), UserHandle.getUserHandleForUid(mUid), null, 0);
NotificationRecord r3 =
new NotificationRecord(mContext, sbn3, mock(NotificationChannel.class));
@@ -4097,7 +4124,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
.setStyle(new Notification.InboxStyle()
.addLine("line1").addLine("line2").addLine("line3"));
StatusBarNotification sbn4 = new StatusBarNotification(PKG, PKG, 0, "tag", mUid, 0,
- nb4.build(), new UserHandle(mUid), null, 0);
+ nb4.build(), UserHandle.getUserHandleForUid(mUid), null, 0);
NotificationRecord r4 =
new NotificationRecord(mContext, sbn4, mock(NotificationChannel.class));
@@ -4106,7 +4133,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
Notification.Builder nb5 = new Notification.Builder(mContext, "")
.setContentText("not an inbox");
StatusBarNotification sbn5 = new StatusBarNotification(PKG, PKG, 0, "tag", mUid, 0,
- nb5.build(), new UserHandle(mUid), null, 0);
+ nb5.build(), UserHandle.getUserHandleForUid(mUid), null, 0);
NotificationRecord r5 =
new NotificationRecord(mContext, sbn5, mock(NotificationChannel.class));
@@ -4118,14 +4145,14 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
Notification.Builder nb1 = new Notification.Builder(mContext, "")
.setContentText("foo");
StatusBarNotification sbn1 = new StatusBarNotification(PKG, PKG, 0, "tag", mUid, 0,
- nb1.build(), new UserHandle(mUid), null, 0);
+ nb1.build(), UserHandle.getUserHandleForUid(mUid), null, 0);
NotificationRecord r1 =
new NotificationRecord(mContext, sbn1, mock(NotificationChannel.class));
Notification.Builder nb2 = new Notification.Builder(mContext, "")
.setContentText("bar");
StatusBarNotification sbn2 = new StatusBarNotification(PKG, PKG, 0, "tag", mUid, 0,
- nb2.build(), new UserHandle(mUid), null, 0);
+ nb2.build(), UserHandle.getUserHandleForUid(mUid), null, 0);
NotificationRecord r2 =
new NotificationRecord(mContext, sbn2, mock(NotificationChannel.class));
@@ -4137,14 +4164,14 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
Notification.Builder nb1 = new Notification.Builder(mContext, "")
.setContentText("foo");
StatusBarNotification sbn1 = new StatusBarNotification(PKG, PKG, 0, "tag", mUid, 0,
- nb1.build(), new UserHandle(mUid), null, 0);
+ nb1.build(), UserHandle.getUserHandleForUid(mUid), null, 0);
NotificationRecord r1 =
new NotificationRecord(mContext, sbn1, mock(NotificationChannel.class));
Notification.Builder nb2 = new Notification.Builder(mContext, "")
.setContentText("foo");
StatusBarNotification sbn2 = new StatusBarNotification(PKG, PKG, 0, "tag", mUid, 0,
- nb2.build(), new UserHandle(mUid), null, 0);
+ nb2.build(), UserHandle.getUserHandleForUid(mUid), null, 0);
NotificationRecord r2 =
new NotificationRecord(mContext, sbn2, mock(NotificationChannel.class));
@@ -4156,14 +4183,14 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
Notification.Builder nb1 = new Notification.Builder(mContext, "")
.setContentText(Html.fromHtml("<b>foo</b>"));
StatusBarNotification sbn1 = new StatusBarNotification(PKG, PKG, 0, "tag", mUid, 0,
- nb1.build(), new UserHandle(mUid), null, 0);
+ nb1.build(), UserHandle.getUserHandleForUid(mUid), null, 0);
NotificationRecord r1 =
new NotificationRecord(mContext, sbn1, mock(NotificationChannel.class));
Notification.Builder nb2 = new Notification.Builder(mContext, "")
.setContentText(Html.fromHtml("<b>foo</b>"));
StatusBarNotification sbn2 = new StatusBarNotification(PKG, PKG, 0, "tag", mUid, 0,
- nb2.build(), new UserHandle(mUid), null, 0);
+ nb2.build(), UserHandle.getUserHandleForUid(mUid), null, 0);
NotificationRecord r2 =
new NotificationRecord(mContext, sbn2, mock(NotificationChannel.class));
@@ -4175,14 +4202,14 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
Notification.Builder nb1 = new Notification.Builder(mContext, "")
.setContentText(Html.fromHtml("<b>foo</b>"));
StatusBarNotification sbn1 = new StatusBarNotification(PKG, PKG, 0, "tag", mUid, 0,
- nb1.build(), new UserHandle(mUid), null, 0);
+ nb1.build(), UserHandle.getUserHandleForUid(mUid), null, 0);
NotificationRecord r1 =
new NotificationRecord(mContext, sbn1, mock(NotificationChannel.class));
Notification.Builder nb2 = new Notification.Builder(mContext, "")
.setContentText(Html.fromHtml("<b>bar</b>"));
StatusBarNotification sbn2 = new StatusBarNotification(PKG, PKG, 0, "tag", mUid, 0,
- nb2.build(), new UserHandle(mUid), null, 0);
+ nb2.build(), UserHandle.getUserHandleForUid(mUid), null, 0);
NotificationRecord r2 =
new NotificationRecord(mContext, sbn2, mock(NotificationChannel.class));
@@ -4194,14 +4221,14 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
Notification.Builder nb1 = new Notification.Builder(mContext, "")
.setProgress(100, 90, false);
StatusBarNotification sbn1 = new StatusBarNotification(PKG, PKG, 0, "tag", mUid, 0,
- nb1.build(), new UserHandle(mUid), null, 0);
+ nb1.build(), UserHandle.getUserHandleForUid(mUid), null, 0);
NotificationRecord r1 =
new NotificationRecord(mContext, sbn1, mock(NotificationChannel.class));
Notification.Builder nb2 = new Notification.Builder(mContext, "")
.setProgress(100, 100, false);
StatusBarNotification sbn2 = new StatusBarNotification(PKG, PKG, 0, "tag", mUid, 0,
- nb2.build(), new UserHandle(mUid), null, 0);
+ nb2.build(), UserHandle.getUserHandleForUid(mUid), null, 0);
NotificationRecord r2 =
new NotificationRecord(mContext, sbn2, mock(NotificationChannel.class));
@@ -4213,14 +4240,14 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
Notification.Builder nb1 = new Notification.Builder(mContext, "")
.setProgress(100, 90, false);
StatusBarNotification sbn1 = new StatusBarNotification(PKG, PKG, 0, "tag", mUid, 0,
- nb1.build(), new UserHandle(mUid), null, 0);
+ nb1.build(), UserHandle.getUserHandleForUid(mUid), null, 0);
NotificationRecord r1 =
new NotificationRecord(mContext, sbn1, mock(NotificationChannel.class));
Notification.Builder nb2 = new Notification.Builder(mContext, "")
.setProgress(100, 91, false);
StatusBarNotification sbn2 = new StatusBarNotification(PKG, PKG, 0, "tag", mUid, 0,
- nb2.build(), new UserHandle(mUid), null, 0);
+ nb2.build(), UserHandle.getUserHandleForUid(mUid), null, 0);
NotificationRecord r2 =
new NotificationRecord(mContext, sbn2, mock(NotificationChannel.class));
@@ -4232,14 +4259,14 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
Notification.Builder nb1 = new Notification.Builder(mContext, "")
.setProgress(100, 100, false);
StatusBarNotification sbn1 = new StatusBarNotification(PKG, PKG, 0, "tag", mUid, 0,
- nb1.build(), new UserHandle(mUid), null, 0);
+ nb1.build(), UserHandle.getUserHandleForUid(mUid), null, 0);
NotificationRecord r1 =
new NotificationRecord(mContext, sbn1, mock(NotificationChannel.class));
Notification.Builder nb2 = new Notification.Builder(mContext, "")
.setProgress(100, 100, false);
StatusBarNotification sbn2 = new StatusBarNotification(PKG, PKG, 0, "tag", mUid, 0,
- nb2.build(), new UserHandle(mUid), null, 0);
+ nb2.build(), UserHandle.getUserHandleForUid(mUid), null, 0);
NotificationRecord r2 =
new NotificationRecord(mContext, sbn2, mock(NotificationChannel.class));
@@ -4253,7 +4280,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
.setFlag(Notification.FLAG_GROUP_SUMMARY, true)
.setContentText("foo");
StatusBarNotification sbn1 = new StatusBarNotification(PKG, PKG, 0, "tag", mUid, 0,
- nb1.build(), new UserHandle(mUid), null, 0);
+ nb1.build(), UserHandle.getUserHandleForUid(mUid), null, 0);
NotificationRecord r1 =
new NotificationRecord(mContext, sbn1, mock(NotificationChannel.class));
@@ -4262,7 +4289,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
.setFlag(Notification.FLAG_GROUP_SUMMARY, true)
.setContentText("bar");
StatusBarNotification sbn2 = new StatusBarNotification(PKG, PKG, 0, "tag", mUid, 0,
- nb2.build(), new UserHandle(mUid), null, 0);
+ nb2.build(), UserHandle.getUserHandleForUid(mUid), null, 0);
NotificationRecord r2 =
new NotificationRecord(mContext, sbn2, mock(NotificationChannel.class));
@@ -4276,7 +4303,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
.setFlag(Notification.FLAG_GROUP_SUMMARY, true)
.setContentText("bar");
StatusBarNotification sbn2 = new StatusBarNotification(PKG, PKG, 0, "tag", mUid, 0,
- nb2.build(), new UserHandle(mUid), null, 0);
+ nb2.build(), UserHandle.getUserHandleForUid(mUid), null, 0);
NotificationRecord r2 =
new NotificationRecord(mContext, sbn2, mock(NotificationChannel.class));
@@ -4694,7 +4721,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
n.flags |= FLAG_FOREGROUND_SERVICE;
StatusBarNotification sbn = new StatusBarNotification(PKG, PKG, 9, null, mUid, 0,
- n, new UserHandle(mUid), null, 0);
+ n, UserHandle.getUserHandleForUid(mUid), null, 0);
NotificationRecord r = new NotificationRecord(mContext, sbn, mTestNotificationChannel);
mService.addEnqueuedNotification(r);
@@ -4713,7 +4740,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
n.flags |= FLAG_FOREGROUND_SERVICE;
StatusBarNotification sbn = new StatusBarNotification(PKG, PKG, 9, null, mUid, 0,
- n, new UserHandle(mUid), null, 0);
+ n, UserHandle.getUserHandleForUid(mUid), null, 0);
NotificationRecord r = new NotificationRecord(mContext, sbn, mTestNotificationChannel);
mService.addNotification(r);
@@ -5026,7 +5053,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
.setSmallIcon(android.R.drawable.sym_def_app_icon);
StatusBarNotification sbn = new StatusBarNotification(PKG, "opPkg", 0, "tag", mUid, 0,
- nb.build(), new UserHandle(mUid), null, 0);
+ nb.build(), UserHandle.getUserHandleForUid(mUid), null, 0);
NotificationRecord r = new NotificationRecord(mContext, sbn, mTestNotificationChannel);
mService.reportSeen(r);
@@ -5050,7 +5077,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
StatusBarNotification sbn = new StatusBarNotification(PKG, PKG, r.getSbn().getId(),
r.getSbn().getTag(), mUid, 0,
new Notification.Builder(mContext, mTestNotificationChannel.getId()).build(),
- new UserHandle(mUid), null, 0);
+ UserHandle.getUserHandleForUid(mUid), null, 0);
NotificationRecord update = new NotificationRecord(mContext, sbn, mTestNotificationChannel);
mService.addEnqueuedNotification(update);
assertNull(update.getSbn().getNotification().getSmallIcon());
@@ -5084,7 +5111,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
}
@Test
- public void testgetNotificationChannels_crossUser() throws Exception {
+ public void testGetNotificationChannels_crossUser() throws Exception {
// same user no problem
mBinderService.getNotificationChannels("src", "target", mContext.getUserId());
@@ -5273,7 +5300,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
.setSmallIcon(android.R.drawable.sym_def_app_icon)
.setBubbleMetadata(getBubbleMetadata());
StatusBarNotification sbn = new StatusBarNotification(PKG, PKG, 1, "tag", mUid, 0,
- nb.build(), new UserHandle(mUid), null, 0);
+ nb.build(), UserHandle.getUserHandleForUid(mUid), null, 0);
NotificationRecord nr = new NotificationRecord(mContext, sbn, mTestNotificationChannel);
// Say we're foreground
@@ -5319,7 +5346,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
nb.setShortcutId(null);
StatusBarNotification sbn = new StatusBarNotification(PKG, PKG, 1,
null, mUid, 0,
- nb.build(), new UserHandle(mUid), null, 0);
+ nb.build(), UserHandle.getUserHandleForUid(mUid), null, 0);
mBinderService.enqueueNotificationWithTag(PKG, PKG, sbn.getTag(),
sbn.getId(), sbn.getNotification(), sbn.getUserId());
@@ -5363,7 +5390,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
StatusBarNotification sbn = new StatusBarNotification(PKG, PKG, 1,
"testFlagBubbleNotifs_noFlag_notBubble", mUid, 0,
- nb.build(), new UserHandle(mUid), null, 0);
+ nb.build(), UserHandle.getUserHandleForUid(mUid), null, 0);
NotificationRecord nr = new NotificationRecord(mContext, sbn, mTestNotificationChannel);
// Post the notification
@@ -5455,25 +5482,49 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
}
@Test
- public void testCancelNotificationsFromListener_ignoresBubbles() throws Exception {
- final NotificationRecord nrNormal = generateNotificationRecord(mTestNotificationChannel);
- final NotificationRecord nrBubble = generateNotificationRecord(mTestNotificationChannel);
- nrBubble.getSbn().getNotification().flags |= FLAG_BUBBLE;
+ public void testCancelNotificationsFromListener_cancelsNonBubble() throws Exception {
+ // Add non-bubble notif
+ final NotificationRecord nr = generateNotificationRecord(mTestNotificationChannel);
+ mService.addNotification(nr);
- mService.addNotification(nrNormal);
- mService.addNotification(nrBubble);
+ // Cancel via listener
+ String[] keys = {nr.getSbn().getKey()};
+ mService.getBinderService().cancelNotificationsFromListener(null, keys);
+ waitForIdle();
+
+ // Notif not active anymore
+ StatusBarNotification[] notifs = mBinderService.getActiveNotifications(PKG);
+ assertEquals(0, notifs.length);
+ assertEquals(0, mService.getNotificationRecordCount());
+ // Cancel event is logged
+ assertEquals(1, mNotificationRecordLogger.numCalls());
+ assertEquals(NotificationRecordLogger.NotificationCancelledEvent
+ .NOTIFICATION_CANCEL_LISTENER_CANCEL, mNotificationRecordLogger.event(0));
+ }
+
+ @Test
+ public void testCancelNotificationsFromListener_suppressesBubble() throws Exception {
+ // Add bubble notif
+ setUpPrefsForBubbles(PKG, mUid,
+ true /* global */,
+ BUBBLE_PREFERENCE_ALL /* app */,
+ true /* channel */);
+ NotificationRecord nr = generateMessageBubbleNotifRecord(mTestNotificationChannel, "tag");
+
+ mBinderService.enqueueNotificationWithTag(PKG, PKG, nr.getSbn().getTag(),
+ nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId());
+ waitForIdle();
- String[] keys = {nrNormal.getSbn().getKey(), nrBubble.getSbn().getKey()};
+ // Cancel via listener
+ String[] keys = {nr.getSbn().getKey()};
mService.getBinderService().cancelNotificationsFromListener(null, keys);
waitForIdle();
+ // Bubble notif active and suppressed
StatusBarNotification[] notifs = mBinderService.getActiveNotifications(PKG);
assertEquals(1, notifs.length);
assertEquals(1, mService.getNotificationRecordCount());
-
- assertEquals(1, mNotificationRecordLogger.numCalls());
- assertEquals(NotificationRecordLogger.NotificationCancelledEvent
- .NOTIFICATION_CANCEL_LISTENER_CANCEL, mNotificationRecordLogger.event(0));
+ assertTrue(notifs[0].getNotification().getBubbleMetadata().isNotificationSuppressed());
}
@Test
@@ -6154,7 +6205,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
nb.setShortcutId(VALID_CONVO_SHORTCUT_ID);
nb.setBubbleMetadata(metadata);
StatusBarNotification sbn = new StatusBarNotification(PKG, PKG, 1,
- "tag", mUid, 0, nb.build(), new UserHandle(mUid), null, 0);
+ "tag", mUid, 0, nb.build(), UserHandle.getUserHandleForUid(mUid), null, 0);
NotificationRecord nr = new NotificationRecord(mContext, sbn, mTestNotificationChannel);
// Test: Send the bubble notification
@@ -6179,7 +6230,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
// Test: Remove the shortcut
when(mLauncherApps.getShortcuts(any(), any())).thenReturn(null);
launcherAppsCallback.getValue().onShortcutsChanged(PKG, Collections.emptyList(),
- new UserHandle(mUid));
+ UserHandle.getUserHandleForUid(mUid));
waitForIdle();
// Verify:
@@ -6214,7 +6265,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
nb.setShortcutId(shortcutId);
nb.setBubbleMetadata(metadata);
StatusBarNotification sbn = new StatusBarNotification(PKG, PKG, 1,
- "tag", mUid, 0, nb.build(), new UserHandle(mUid), null, 0);
+ "tag", mUid, 0, nb.build(), UserHandle.getUserHandleForUid(mUid), null, 0);
NotificationRecord nr = new NotificationRecord(mContext, sbn, mTestNotificationChannel);
// Pretend the shortcut exists
@@ -6662,15 +6713,43 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
@Test
public void testRecordMessages_invalidMsg() throws RemoteException {
- NotificationRecord nr =
- generateMessageBubbleNotifRecord(mTestNotificationChannel,
- "testRecordMessages_invalidMsg");
+ Notification.Builder nb = getMessageStyleNotifBuilder(false /* addDefaultMetadata */,
+ null /* groupKey */, false /* isSummary */);
+ nb.setShortcutId(null);
+ StatusBarNotification sbn = new StatusBarNotification(PKG_P, PKG_P, 1,
+ "testRecordMessages_invalidMsg", mUid, 0, nb.build(),
+ UserHandle.getUserHandleForUid(mUid), null, 0);
+ NotificationRecord nr = new NotificationRecord(mContext, sbn, mTestNotificationChannel);
+
when(mLauncherApps.getShortcuts(any(), any())).thenReturn(null);
- mBinderService.enqueueNotificationWithTag(PKG, PKG, nr.getSbn().getTag(),
+ mBinderService.enqueueNotificationWithTag(PKG_P, PKG_P, nr.getSbn().getTag(),
nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId());
waitForIdle();
- assertTrue(mBinderService.isInInvalidMsgState(PKG, mUid));
+ assertTrue(mBinderService.isInInvalidMsgState(PKG_P, mUid));
+ }
+
+ @Test
+ public void testRecordMessages_invalidMsg_notMessageStyle() throws RemoteException {
+ Notification.Builder nb = new Notification.Builder(mContext,
+ mTestNotificationChannel.getId())
+ .setContentTitle("foo")
+ .setShortcutId(null)
+ .setSmallIcon(android.R.drawable.sym_def_app_icon)
+ .setCategory(Notification.CATEGORY_MESSAGE);
+ StatusBarNotification sbn = new StatusBarNotification(PKG_O, PKG_O, 1,
+ "testRecordMessages_invalidMsg_notMessageStyle", mUid, 0, nb.build(),
+ UserHandle.getUserHandleForUid(mUid), null, 0);
+ NotificationRecord nr = new NotificationRecord(mContext, sbn, mTestNotificationChannel);
+
+ when(mLauncherApps.getShortcuts(any(), any())).thenReturn(null);
+ mBinderService.enqueueNotificationWithTag(PKG_O, PKG_O, nr.getSbn().getTag(),
+ nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId());
+ waitForIdle();
+
+ // PKG_O is allowed to be in conversation space b/c of override in
+ // TestableNotificationManagerService
+ assertTrue(mBinderService.isInInvalidMsgState(PKG_O, mUid));
}
@Test
@@ -6678,24 +6757,25 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
Notification.Builder nb = getMessageStyleNotifBuilder(false /* addDefaultMetadata */,
null /* groupKey */, false /* isSummary */);
nb.setShortcutId(null);
- StatusBarNotification sbn = new StatusBarNotification(PKG, PKG, 1,
- "testRecordMessages_validMsg", mUid, 0, nb.build(), new UserHandle(mUid), null, 0);
+ StatusBarNotification sbn = new StatusBarNotification(PKG_P, PKG_P, 1,
+ "testRecordMessages_validMsg", mUid, 0, nb.build(),
+ UserHandle.getUserHandleForUid(mUid), null, 0);
NotificationRecord nr = new NotificationRecord(mContext, sbn, mTestNotificationChannel);
- mBinderService.enqueueNotificationWithTag(PKG, PKG, nr.getSbn().getTag(),
+ mBinderService.enqueueNotificationWithTag(PKG_P, PKG_P, nr.getSbn().getTag(),
nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId());
waitForIdle();
- assertTrue(mBinderService.isInInvalidMsgState(PKG, mUid));
+ assertTrue(mBinderService.isInInvalidMsgState(PKG_P, mUid));
nr = generateMessageBubbleNotifRecord(mTestNotificationChannel,
"testRecordMessages_validMsg");
- mBinderService.enqueueNotificationWithTag(PKG, PKG, nr.getSbn().getTag(),
+ mBinderService.enqueueNotificationWithTag(PKG_P, PKG_P, nr.getSbn().getTag(),
nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId());
waitForIdle();
- assertFalse(mBinderService.isInInvalidMsgState(PKG, mUid));
+ assertFalse(mBinderService.isInInvalidMsgState(PKG_P, mUid));
}
@Test
@@ -6715,7 +6795,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
nb.setShortcutId(null);
StatusBarNotification sbn = new StatusBarNotification(PKG, PKG, 1,
"testRecordMessages_invalidMsg_afterValidMsg_2", mUid, 0, nb.build(),
- new UserHandle(mUid), null, 0);
+ UserHandle.getUserHandleForUid(mUid), null, 0);
nr = new NotificationRecord(mContext, sbn, mTestNotificationChannel);
mBinderService.enqueueNotificationWithTag(PKG, PKG, nr.getSbn().getTag(),
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/WrappedSysUiStatsEvent.java b/services/tests/uiservicestests/src/com/android/server/notification/WrappedSysUiStatsEvent.java
index f4f64d779d30..89adc724f600 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/WrappedSysUiStatsEvent.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/WrappedSysUiStatsEvent.java
@@ -88,11 +88,21 @@ public class WrappedSysUiStatsEvent {
return index < mValues.size() ? mValues.get(index) : null;
}
- /** useful to make assertTrue() statemetns more readable. */
+ /** useful to make assertTrue() statements more readable. */
public boolean getBoolean(int index) {
return (Boolean) mValues.get(index);
}
+ /** useful to make assertTrue() statements more readable. */
+ public int getInt(int index) {
+ return (Integer) mValues.get(index);
+ }
+
+ /** useful to make assertTrue() statements more readable. */
+ public String getString(int index) {
+ return (String) mValues.get(index);
+ }
+
private void addValue(Object value) {
mLastIndex = mValues.size();
mValues.add(value);
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 f7b435ed937b..013a99433041 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/ZenModeConfigTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/ZenModeConfigTest.java
@@ -101,11 +101,39 @@ public class ZenModeConfigTest extends UiServiceTestCase {
Policy expectedPolicy = new Policy(priorityCategories, priorityCallSenders,
priorityMessageSenders, suppressedVisualEffects, 0, priorityConversationsSenders);
-
assertEquals(expectedPolicy, config.toNotificationPolicy(zenPolicy));
}
@Test
+ public void testZenConfigToZenPolicy() {
+ ZenPolicy expected = new ZenPolicy.Builder()
+ .allowAlarms(true)
+ .allowReminders(true)
+ .allowEvents(true)
+ .showLights(false)
+ .showBadges(false)
+ .showInAmbientDisplay(false)
+ .build();
+
+ ZenModeConfig config = getMutedAllConfig();
+ config.allowAlarms = true;
+ config.allowReminders = true;
+ config.allowEvents = true;
+ config.suppressedVisualEffects |= Policy.SUPPRESSED_EFFECT_BADGE;
+ config.suppressedVisualEffects |= Policy.SUPPRESSED_EFFECT_LIGHTS;
+ config.suppressedVisualEffects |= Policy.SUPPRESSED_EFFECT_AMBIENT;
+ ZenPolicy actual = config.toZenPolicy();
+
+ assertEquals(expected.getVisualEffectBadge(), actual.getVisualEffectBadge());
+ assertEquals(expected.getPriorityCategoryAlarms(), actual.getPriorityCategoryAlarms());
+ assertEquals(expected.getPriorityCategoryReminders(),
+ actual.getPriorityCategoryReminders());
+ assertEquals(expected.getPriorityCategoryEvents(), actual.getPriorityCategoryEvents());
+ assertEquals(expected.getVisualEffectLights(), actual.getVisualEffectLights());
+ assertEquals(expected.getVisualEffectAmbient(), actual.getVisualEffectAmbient());
+ }
+
+ @Test
public void testPriorityOnlyMutingAll() {
ZenModeConfig config = getMutedAllConfig();
assertTrue(ZenModeConfig.areAllPriorityOnlyRingerSoundsMuted(config));
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 108af892c7dd..3c7206fee9d1 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java
@@ -27,16 +27,25 @@ import static android.app.NotificationManager.Policy.PRIORITY_CATEGORY_REMINDERS
import static android.app.NotificationManager.Policy.PRIORITY_CATEGORY_REPEAT_CALLERS;
import static android.app.NotificationManager.Policy.PRIORITY_CATEGORY_SYSTEM;
import static android.app.NotificationManager.Policy.PRIORITY_SENDERS_ANY;
-import static android.app.NotificationManager.Policy.PRIORITY_SENDERS_CONTACTS;
import static android.app.NotificationManager.Policy.PRIORITY_SENDERS_STARRED;
import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_BADGE;
import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_FULL_SCREEN_INTENT;
import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_LIGHTS;
import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_PEEK;
+import static android.provider.Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS;
+
+import static com.android.internal.util.FrameworkStatsLog.ANNOTATION_ID_IS_UID;
+import static com.android.internal.util.FrameworkStatsLog.DND_MODE_RULE;
+import static com.android.os.AtomsProto.DNDModeProto.CHANNELS_BYPASSING_FIELD_NUMBER;
+import static com.android.os.AtomsProto.DNDModeProto.ENABLED_FIELD_NUMBER;
+import static com.android.os.AtomsProto.DNDModeProto.ID_FIELD_NUMBER;
+import static com.android.os.AtomsProto.DNDModeProto.UID_FIELD_NUMBER;
+import static com.android.os.AtomsProto.DNDModeProto.ZEN_MODE_FIELD_NUMBER;
import static junit.framework.Assert.assertEquals;
import static junit.framework.Assert.assertFalse;
import static junit.framework.TestCase.assertTrue;
+import static junit.framework.TestCase.fail;
import static org.junit.Assert.assertNotEquals;
import static org.mockito.ArgumentMatchers.any;
@@ -70,10 +79,12 @@ import android.media.AudioManagerInternal;
import android.media.AudioSystem;
import android.media.VolumePolicy;
import android.net.Uri;
+import android.os.Process;
import android.os.UserHandle;
import android.provider.Settings;
import android.provider.Settings.Global;
import android.service.notification.Condition;
+import android.service.notification.DNDModeProto;
import android.service.notification.ZenModeConfig;
import android.service.notification.ZenModeConfig.ScheduleInfo;
import android.service.notification.ZenPolicy;
@@ -82,6 +93,7 @@ import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
import android.util.ArrayMap;
import android.util.Log;
+import android.util.StatsEvent;
import android.util.Xml;
import com.android.internal.R;
@@ -106,6 +118,9 @@ import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.Reader;
+import java.util.ArrayList;
+import java.util.LinkedList;
+import java.util.List;
import java.util.Objects;
@SmallTest
@@ -115,6 +130,7 @@ public class ZenModeHelperTest extends UiServiceTestCase {
private static final String EVENTS_DEFAULT_RULE_ID = "EVENTS_DEFAULT_RULE";
private static final String SCHEDULE_DEFAULT_RULE_ID = "EVERY_NIGHT_DEFAULT_RULE";
+ private static final int ZEN_MODE_FOR_TESTING = 99;
ConditionProviders mConditionProviders;
@Mock NotificationManager mNotificationManager;
@@ -124,6 +140,7 @@ public class ZenModeHelperTest extends UiServiceTestCase {
private Context mContext;
private ContentResolver mContentResolver;
@Mock AppOpsManager mAppOps;
+ private WrappedSysUiStatsEvent.WrappedBuilderFactory mStatsEventBuilderFactory;
@Before
public void setUp() {
@@ -140,6 +157,7 @@ public class ZenModeHelperTest extends UiServiceTestCase {
Log.d("ZenModeHelperTest", "Couldn't mock default zen mode config xml file err=" +
e.toString());
}
+ mStatsEventBuilderFactory = new WrappedSysUiStatsEvent.WrappedBuilderFactory();
when(mContext.getSystemService(AppOpsManager.class)).thenReturn(mAppOps);
when(mContext.getSystemService(NotificationManager.class)).thenReturn(mNotificationManager);
@@ -147,7 +165,7 @@ public class ZenModeHelperTest extends UiServiceTestCase {
AppGlobals.getPackageManager());
mConditionProviders.addSystemProvider(new CountdownConditionProvider());
mZenModeHelperSpy = spy(new ZenModeHelper(mContext, mTestableLooper.getLooper(),
- mConditionProviders));
+ mConditionProviders, mStatsEventBuilderFactory));
}
private XmlResourceParser getDefaultConfigParser() throws IOException, XmlPullParserException {
@@ -212,6 +230,10 @@ public class ZenModeHelperTest extends UiServiceTestCase {
}
private ArrayMap<String, ZenModeConfig.ZenRule> getCustomAutomaticRules() {
+ return getCustomAutomaticRules(ZEN_MODE_IMPORTANT_INTERRUPTIONS);
+ }
+
+ private ArrayMap<String, ZenModeConfig.ZenRule> getCustomAutomaticRules(int zenMode) {
ArrayMap<String, ZenModeConfig.ZenRule> automaticRules = new ArrayMap<>();
ZenModeConfig.ZenRule customRule = new ZenModeConfig.ZenRule();
final ScheduleInfo customRuleInfo = new ScheduleInfo();
@@ -219,10 +241,10 @@ public class ZenModeHelperTest extends UiServiceTestCase {
customRule.creationTime = 0;
customRule.id = "customRule";
customRule.name = "Custom Rule";
- customRule.zenMode = Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS;
+ customRule.zenMode = zenMode;
customRule.conditionId = ZenModeConfig.toScheduleConditionId(customRuleInfo);
customRule.configurationActivity =
- new ComponentName("android", "ScheduleConditionProvider");
+ new ComponentName("not.android", "ScheduleConditionProvider");
customRule.pkg = customRule.configurationActivity.getPackageName();
automaticRules.put("customRule", customRule);
return automaticRules;
@@ -244,7 +266,7 @@ public class ZenModeHelperTest extends UiServiceTestCase {
@Test
public void testZenOn_NotificationApplied() {
- mZenModeHelperSpy.mZenMode = Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS;
+ mZenModeHelperSpy.mZenMode = ZEN_MODE_IMPORTANT_INTERRUPTIONS;
// The most permissive policy
mZenModeHelperSpy.mConsolidatedPolicy = new Policy(Policy.PRIORITY_CATEGORY_ALARMS |
PRIORITY_CATEGORY_MEDIA | PRIORITY_CATEGORY_MESSAGES
@@ -267,7 +289,7 @@ public class ZenModeHelperTest extends UiServiceTestCase {
@Test
public void testZenOn_StarredCallers_CallTypesBlocked() {
- mZenModeHelperSpy.mZenMode = Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS;
+ mZenModeHelperSpy.mZenMode = ZEN_MODE_IMPORTANT_INTERRUPTIONS;
// The most permissive policy
mZenModeHelperSpy.mConsolidatedPolicy = new Policy(Policy.PRIORITY_CATEGORY_ALARMS |
PRIORITY_CATEGORY_MEDIA | PRIORITY_CATEGORY_MESSAGES
@@ -287,7 +309,7 @@ public class ZenModeHelperTest extends UiServiceTestCase {
@Test
public void testZenOn_AllCallers_CallTypesAllowed() {
- mZenModeHelperSpy.mZenMode = Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS;
+ mZenModeHelperSpy.mZenMode = ZEN_MODE_IMPORTANT_INTERRUPTIONS;
// The most permissive policy
mZenModeHelperSpy.mConsolidatedPolicy = new Policy(Policy.PRIORITY_CATEGORY_ALARMS |
PRIORITY_CATEGORY_MEDIA | PRIORITY_CATEGORY_MESSAGES
@@ -307,7 +329,7 @@ public class ZenModeHelperTest extends UiServiceTestCase {
@Test
public void testZenOn_AllowAlarmsMedia_NoAlarmMediaMuteApplied() {
- mZenModeHelperSpy.mZenMode = Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS;
+ mZenModeHelperSpy.mZenMode = ZEN_MODE_IMPORTANT_INTERRUPTIONS;
mZenModeHelperSpy.mConsolidatedPolicy = new Policy(Policy.PRIORITY_CATEGORY_ALARMS |
PRIORITY_CATEGORY_MEDIA, 0, 0, 0, 0, 0);
@@ -320,7 +342,7 @@ public class ZenModeHelperTest extends UiServiceTestCase {
@Test
public void testZenOn_DisallowAlarmsMedia_AlarmMediaMuteApplied() {
- mZenModeHelperSpy.mZenMode = Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS;
+ mZenModeHelperSpy.mZenMode = ZEN_MODE_IMPORTANT_INTERRUPTIONS;
mZenModeHelperSpy.mConsolidatedPolicy = new Policy(0, 0, 0, 0, 0, 0);
mZenModeHelperSpy.applyRestrictions();
verify(mZenModeHelperSpy, atLeastOnce()).applyRestrictions(true, true,
@@ -406,7 +428,7 @@ public class ZenModeHelperTest extends UiServiceTestCase {
public void testZenAllCannotBypass() {
// Only audio attributes with SUPPRESIBLE_NEVER can bypass
// with special case USAGE_ASSISTANCE_SONIFICATION
- mZenModeHelperSpy.mZenMode = Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS;
+ mZenModeHelperSpy.mZenMode = ZEN_MODE_IMPORTANT_INTERRUPTIONS;
mZenModeHelperSpy.mConsolidatedPolicy = new Policy(0, 0, 0, 0, 0, 0);
mZenModeHelperSpy.applyRestrictions();
@@ -428,7 +450,7 @@ public class ZenModeHelperTest extends UiServiceTestCase {
@Test
public void testApplyRestrictions_whitelist_priorityOnlyMode() {
mZenModeHelperSpy.setPriorityOnlyDndExemptPackages(new String[] {PKG_O});
- mZenModeHelperSpy.mZenMode = Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS;
+ mZenModeHelperSpy.mZenMode = ZEN_MODE_IMPORTANT_INTERRUPTIONS;
mZenModeHelperSpy.mConsolidatedPolicy = new Policy(0, 0, 0, 0, 0, 0);
mZenModeHelperSpy.applyRestrictions();
@@ -479,7 +501,7 @@ public class ZenModeHelperTest extends UiServiceTestCase {
Settings.Secure.putInt(mContentResolver, Settings.Secure.ZEN_SETTINGS_UPDATED, 0);
mZenModeHelperSpy.mIsBootComplete = true;
mZenModeHelperSpy.mConsolidatedPolicy = new Policy(0, 0, 0, 0, 0, 0);
- mZenModeHelperSpy.setZenModeSetting(Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS);
+ mZenModeHelperSpy.setZenModeSetting(ZEN_MODE_IMPORTANT_INTERRUPTIONS);
verify(mZenModeHelperSpy, times(1)).createZenUpgradeNotification();
verify(mNotificationManager, times(1)).notify(eq(ZenModeHelper.TAG),
@@ -494,7 +516,7 @@ public class ZenModeHelperTest extends UiServiceTestCase {
Settings.Secure.putInt(mContentResolver, Settings.Secure.SHOW_ZEN_UPGRADE_NOTIFICATION, 0);
Settings.Secure.putInt(mContentResolver, Settings.Secure.ZEN_SETTINGS_UPDATED, 0);
mZenModeHelperSpy.mIsBootComplete = true;
- mZenModeHelperSpy.setZenModeSetting(Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS);
+ mZenModeHelperSpy.setZenModeSetting(ZEN_MODE_IMPORTANT_INTERRUPTIONS);
verify(mZenModeHelperSpy, never()).createZenUpgradeNotification();
verify(mNotificationManager, never()).notify(eq(ZenModeHelper.TAG),
@@ -507,7 +529,7 @@ public class ZenModeHelperTest extends UiServiceTestCase {
Settings.Secure.putInt(mContentResolver, Settings.Secure.SHOW_ZEN_UPGRADE_NOTIFICATION, 0);
Settings.Secure.putInt(mContentResolver, Settings.Secure.ZEN_SETTINGS_UPDATED, 1);
mZenModeHelperSpy.mIsBootComplete = true;
- mZenModeHelperSpy.setZenModeSetting(Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS);
+ mZenModeHelperSpy.setZenModeSetting(ZEN_MODE_IMPORTANT_INTERRUPTIONS);
verify(mZenModeHelperSpy, never()).createZenUpgradeNotification();
verify(mNotificationManager, never()).notify(eq(ZenModeHelper.TAG),
@@ -524,7 +546,7 @@ public class ZenModeHelperTest extends UiServiceTestCase {
// 1. Current ringer is normal
when(mAudioManager.getRingerModeInternal()).thenReturn(AudioManager.RINGER_MODE_NORMAL);
// Set zen to priority-only with all notification sounds muted (so ringer will be muted)
- mZenModeHelperSpy.mZenMode = Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS;
+ mZenModeHelperSpy.mZenMode = ZEN_MODE_IMPORTANT_INTERRUPTIONS;
mZenModeHelperSpy.mConfig.allowReminders = false;
mZenModeHelperSpy.mConfig.allowCalls = false;
mZenModeHelperSpy.mConfig.allowMessages = false;
@@ -568,7 +590,7 @@ public class ZenModeHelperTest extends UiServiceTestCase {
// ringtone, notification and system streams are affected by ringer mode
mZenModeHelperSpy.mConfig.allowAlarms = true;
mZenModeHelperSpy.mConfig.allowReminders = true;
- mZenModeHelperSpy.mZenMode = Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS;
+ mZenModeHelperSpy.mZenMode = ZEN_MODE_IMPORTANT_INTERRUPTIONS;
ZenModeHelper.RingerModeDelegate ringerModeDelegateRingerMuted =
mZenModeHelperSpy.new RingerModeDelegate();
@@ -615,7 +637,7 @@ public class ZenModeHelperTest extends UiServiceTestCase {
// 1. Current ringer is normal
when(mAudioManager.getRingerModeInternal()).thenReturn(AudioManager.RINGER_MODE_NORMAL);
- mZenModeHelperSpy.mZenMode = Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS;
+ mZenModeHelperSpy.mZenMode = ZEN_MODE_IMPORTANT_INTERRUPTIONS;
mZenModeHelperSpy.mConfig.allowReminders = true;
// 2. apply priority only zen - verify ringer is normal
@@ -640,7 +662,7 @@ public class ZenModeHelperTest extends UiServiceTestCase {
// 1. Current ringer is silent
when(mAudioManager.getRingerModeInternal()).thenReturn(AudioManager.RINGER_MODE_SILENT);
- mZenModeHelperSpy.mZenMode = Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS;
+ mZenModeHelperSpy.mZenMode = ZEN_MODE_IMPORTANT_INTERRUPTIONS;
mZenModeHelperSpy.mConfig.allowReminders = true;
// 2. apply priority only zen - verify ringer is silent
@@ -666,7 +688,7 @@ public class ZenModeHelperTest extends UiServiceTestCase {
// 1. Current ringer is normal
when(mAudioManager.getRingerModeInternal()).thenReturn(AudioManager.RINGER_MODE_NORMAL);
// Set zen to priority-only with all notification sounds muted (so ringer will be muted)
- mZenModeHelperSpy.mZenMode = Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS;
+ mZenModeHelperSpy.mZenMode = ZEN_MODE_IMPORTANT_INTERRUPTIONS;
mZenModeHelperSpy.mConfig.allowReminders = true;
// 2. apply priority only zen - verify zen will still be normal
@@ -728,7 +750,7 @@ public class ZenModeHelperTest extends UiServiceTestCase {
// apply zen off multiple times - verify ringer is not set to normal
when(mAudioManager.getRingerModeInternal()).thenReturn(AudioManager.RINGER_MODE_SILENT);
- mZenModeHelperSpy.mZenMode = Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS;
+ mZenModeHelperSpy.mZenMode = ZEN_MODE_IMPORTANT_INTERRUPTIONS;
for (int i = 0; i < 3; i++) {
// if zen doesn't change, zen should not reapply itself to the ringer
mZenModeHelperSpy.evaluateZenMode("test", true);
@@ -756,7 +778,7 @@ public class ZenModeHelperTest extends UiServiceTestCase {
// apply zen off multiple times - verify ringer is not set to normal
when(mAudioManager.getRingerModeInternal()).thenReturn(AudioManager.RINGER_MODE_VIBRATE);
- mZenModeHelperSpy.mZenMode = Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS;
+ mZenModeHelperSpy.mZenMode = ZEN_MODE_IMPORTANT_INTERRUPTIONS;
for (int i = 0; i < 3; i++) {
// if zen doesn't change, zen should not reapply itself to the ringer
mZenModeHelperSpy.evaluateZenMode("test", true);
@@ -768,7 +790,7 @@ public class ZenModeHelperTest extends UiServiceTestCase {
@Test
public void testParcelConfig() {
- mZenModeHelperSpy.mZenMode = Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS;
+ mZenModeHelperSpy.mZenMode = ZEN_MODE_IMPORTANT_INTERRUPTIONS;
mZenModeHelperSpy.mConfig.allowAlarms = false;
mZenModeHelperSpy.mConfig.allowMedia = false;
mZenModeHelperSpy.mConfig.allowSystem = false;
@@ -792,7 +814,7 @@ public class ZenModeHelperTest extends UiServiceTestCase {
@Test
public void testWriteXml() throws Exception {
- mZenModeHelperSpy.mZenMode = Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS;
+ mZenModeHelperSpy.mZenMode = ZEN_MODE_IMPORTANT_INTERRUPTIONS;
mZenModeHelperSpy.mConfig.allowAlarms = false;
mZenModeHelperSpy.mConfig.allowMedia = false;
mZenModeHelperSpy.mConfig.allowSystem = false;
@@ -806,7 +828,7 @@ public class ZenModeHelperTest extends UiServiceTestCase {
mZenModeHelperSpy.mConfig.suppressedVisualEffects = SUPPRESSED_EFFECT_BADGE;
mZenModeHelperSpy.mConfig.manualRule = new ZenModeConfig.ZenRule();
mZenModeHelperSpy.mConfig.manualRule.zenMode =
- Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS;
+ ZEN_MODE_IMPORTANT_INTERRUPTIONS;
mZenModeHelperSpy.mConfig.manualRule.component = new ComponentName("a", "a");
mZenModeHelperSpy.mConfig.manualRule.pkg = "a";
mZenModeHelperSpy.mConfig.manualRule.enabled = true;
@@ -822,6 +844,102 @@ public class ZenModeHelperTest extends UiServiceTestCase {
}
@Test
+ public void testProto() {
+ mZenModeHelperSpy.mZenMode = ZEN_MODE_IMPORTANT_INTERRUPTIONS;
+ mZenModeHelperSpy.mConfig.manualRule = new ZenModeConfig.ZenRule();
+
+ int n = mZenModeHelperSpy.mConfig.automaticRules.size();
+ List<String> ids = new ArrayList<>(n);
+ for (ZenModeConfig.ZenRule rule : mZenModeHelperSpy.mConfig.automaticRules.values()) {
+ ids.add(rule.id);
+ }
+ ids.add("");
+
+ List<StatsEvent> events = new LinkedList<>();
+ mZenModeHelperSpy.pullRules(events);
+ assertEquals(n + 1, events.size());
+ for (WrappedSysUiStatsEvent.WrappedBuilder builder : mStatsEventBuilderFactory.builders) {
+ if (builder.getAtomId() == DND_MODE_RULE) {
+ if (builder.getInt(ZEN_MODE_FIELD_NUMBER) == DNDModeProto.ROOT_CONFIG) {
+ assertTrue(builder.getBoolean(ENABLED_FIELD_NUMBER));
+ assertFalse(builder.getBoolean(CHANNELS_BYPASSING_FIELD_NUMBER));
+ }
+ assertEquals(Process.SYSTEM_UID, builder.getInt(UID_FIELD_NUMBER));
+ assertTrue(builder.getBooleanAnnotation(UID_FIELD_NUMBER, ANNOTATION_ID_IS_UID));
+ String name = (String) builder.getValue(ID_FIELD_NUMBER);
+ assertTrue("unexpected rule id", ids.contains(name));
+ ids.remove(name);
+ } else {
+ fail("unexpected atom id: " + builder.getAtomId());
+ }
+ }
+ assertEquals("extra rule in output", 0, ids.size());
+ }
+
+ @Test
+ public void testProtoWithAutoRule() throws Exception {
+ setupZenConfig();
+ // one enabled automatic rule
+ mZenModeHelperSpy.mConfig.automaticRules = getCustomAutomaticRules(ZEN_MODE_FOR_TESTING);
+
+ List<StatsEvent> events = new LinkedList<>();
+ mZenModeHelperSpy.pullRules(events);
+
+ boolean foundCustomEvent = false;
+ for (WrappedSysUiStatsEvent.WrappedBuilder builder : mStatsEventBuilderFactory.builders) {
+ if (builder.getAtomId() == DND_MODE_RULE) {
+ if (ZEN_MODE_FOR_TESTING == builder.getInt(ZEN_MODE_FIELD_NUMBER)) {
+ foundCustomEvent = true;
+ assertEquals(0, builder.getInt(UID_FIELD_NUMBER));
+ assertTrue(builder.getBoolean(ENABLED_FIELD_NUMBER));
+ }
+ } else {
+ fail("unexpected atom id: " + builder.getAtomId());
+ }
+ }
+ assertTrue("couldn't find custom rule", foundCustomEvent);
+ }
+
+ @Test
+ public void testProtoRedactsIds() throws Exception {
+ setupZenConfig();
+ // one enabled automatic rule
+ mZenModeHelperSpy.mConfig.automaticRules = getCustomAutomaticRules();
+
+ List<StatsEvent> events = new LinkedList<>();
+ mZenModeHelperSpy.pullRules(events);
+
+ boolean foundCustomEvent = false;
+ for (WrappedSysUiStatsEvent.WrappedBuilder builder : mStatsEventBuilderFactory.builders) {
+ if (builder.getAtomId() == DND_MODE_RULE
+ && "customRule".equals(builder.getString(ID_FIELD_NUMBER))) {
+ fail("non-default IDs should be redacted");
+ }
+ }
+ }
+
+ @Test
+ public void testProtoWithManualRule() throws Exception {
+ setupZenConfig();
+ mZenModeHelperSpy.mConfig.automaticRules = getCustomAutomaticRules();
+ mZenModeHelperSpy.mConfig.manualRule = new ZenModeConfig.ZenRule();
+ mZenModeHelperSpy.mConfig.manualRule.enabled = true;
+ mZenModeHelperSpy.mConfig.manualRule.enabler = "com.enabler";
+
+ List<StatsEvent> events = new LinkedList<>();
+ mZenModeHelperSpy.pullRules(events);
+
+ boolean foundManualRule = false;
+ for (WrappedSysUiStatsEvent.WrappedBuilder builder : mStatsEventBuilderFactory.builders) {
+ if (builder.getAtomId() == DND_MODE_RULE
+ && ZenModeConfig.MANUAL_RULE_ID.equals(builder.getString(ID_FIELD_NUMBER))) {
+ assertEquals(0, builder.getInt(UID_FIELD_NUMBER));
+ foundManualRule = true;
+ }
+ }
+ assertTrue("couldn't find manual rule", foundManualRule); }
+
+ @Test
public void testWriteXml_onlyBackupsTargetUser() throws Exception {
// Setup configs for user 10 and 11.
setupZenConfig();
@@ -906,7 +1024,7 @@ public class ZenModeHelperTest extends UiServiceTestCase {
customRule.creationTime = 0;
customRule.id = "customRule";
customRule.name = "Custom Rule";
- customRule.zenMode = Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS;
+ customRule.zenMode = ZEN_MODE_IMPORTANT_INTERRUPTIONS;
customRule.conditionId = ZenModeConfig.toScheduleConditionId(customRuleInfo);
customRule.configurationActivity =
new ComponentName("android", "ScheduleConditionProvider");
@@ -951,7 +1069,7 @@ public class ZenModeHelperTest extends UiServiceTestCase {
customRule.creationTime = 0;
customRule.id = ruleId;
customRule.name = "Custom Rule";
- customRule.zenMode = Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS;
+ customRule.zenMode = ZEN_MODE_IMPORTANT_INTERRUPTIONS;
customRule.conditionId = ZenModeConfig.toScheduleConditionId(customRuleInfo);
customRule.configurationActivity =
new ComponentName("android", "ScheduleConditionProvider");
@@ -986,7 +1104,7 @@ public class ZenModeHelperTest extends UiServiceTestCase {
final ScheduleInfo weeknights = new ScheduleInfo();
customRule.enabled = true;
customRule.name = "Custom Rule";
- customRule.zenMode = Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS;
+ customRule.zenMode = ZEN_MODE_IMPORTANT_INTERRUPTIONS;
customRule.conditionId = ZenModeConfig.toScheduleConditionId(weeknights);
customRule.component = new ComponentName("android", "ScheduleConditionProvider");
enabledAutoRule.put("customRule", customRule);
@@ -1151,7 +1269,7 @@ public class ZenModeHelperTest extends UiServiceTestCase {
final ScheduleInfo weeknights = new ScheduleInfo();
customRule.enabled = false;
customRule.name = "Custom Rule";
- customRule.zenMode = Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS;
+ customRule.zenMode = ZEN_MODE_IMPORTANT_INTERRUPTIONS;
customRule.conditionId = ZenModeConfig.toScheduleConditionId(weeknights);
customRule.component = new ComponentName("android", "ScheduleConditionProvider");
disabledAutoRule.put("customRule", customRule);
@@ -1187,7 +1305,7 @@ public class ZenModeHelperTest extends UiServiceTestCase {
final ScheduleInfo customRuleInfo = new ScheduleInfo();
customRule.enabled = false;
customRule.name = "Custom Rule";
- customRule.zenMode = Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS;
+ customRule.zenMode = ZEN_MODE_IMPORTANT_INTERRUPTIONS;
customRule.conditionId = ZenModeConfig.toScheduleConditionId(customRuleInfo);
customRule.component = new ComponentName("android", "ScheduleConditionProvider");
customRule.zenPolicy = new ZenPolicy.Builder()
@@ -1200,7 +1318,7 @@ public class ZenModeHelperTest extends UiServiceTestCase {
final ScheduleInfo defaultScheduleRuleInfo = new ScheduleInfo();
defaultScheduleRule.enabled = false;
defaultScheduleRule.name = "Default Schedule Rule";
- defaultScheduleRule.zenMode = Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS;
+ defaultScheduleRule.zenMode = ZEN_MODE_IMPORTANT_INTERRUPTIONS;
defaultScheduleRule.conditionId = ZenModeConfig.toScheduleConditionId(
defaultScheduleRuleInfo);
customRule.component = new ComponentName("android", "ScheduleConditionProvider");
@@ -1238,7 +1356,7 @@ public class ZenModeHelperTest extends UiServiceTestCase {
final ScheduleInfo customRuleInfo = new ScheduleInfo();
customRule.enabled = false;
customRule.name = "Custom Rule";
- customRule.zenMode = Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS;
+ customRule.zenMode = ZEN_MODE_IMPORTANT_INTERRUPTIONS;
customRule.conditionId = ZenModeConfig.toScheduleConditionId(customRuleInfo);
customRule.component = new ComponentName("android", "ScheduleConditionProvider");
customRule.zenPolicy = new ZenPolicy.Builder()
@@ -1251,7 +1369,7 @@ public class ZenModeHelperTest extends UiServiceTestCase {
final ScheduleInfo defaultScheduleRuleInfo = new ScheduleInfo();
defaultScheduleRule.enabled = false;
defaultScheduleRule.name = "Default Schedule Rule";
- defaultScheduleRule.zenMode = Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS;
+ defaultScheduleRule.zenMode = ZEN_MODE_IMPORTANT_INTERRUPTIONS;
defaultScheduleRule.conditionId = ZenModeConfig.toScheduleConditionId(
defaultScheduleRuleInfo);
defaultScheduleRule.id = ZenModeConfig.EVERY_NIGHT_DEFAULT_RULE_ID;
@@ -1265,7 +1383,7 @@ public class ZenModeHelperTest extends UiServiceTestCase {
final ScheduleInfo defaultEventRuleInfo = new ScheduleInfo();
defaultEventRule.enabled = false;
defaultEventRule.name = "Default Event Rule";
- defaultEventRule.zenMode = Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS;
+ defaultEventRule.zenMode = ZEN_MODE_IMPORTANT_INTERRUPTIONS;
defaultEventRule.conditionId = ZenModeConfig.toScheduleConditionId(
defaultEventRuleInfo);
defaultEventRule.id = ZenModeConfig.EVENTS_DEFAULT_RULE_ID;
@@ -1295,6 +1413,10 @@ public class ZenModeHelperTest extends UiServiceTestCase {
assertTrue(rules.containsKey("customRule"));
setupZenConfigMaintained();
+
+ List<StatsEvent> events = new LinkedList<>();
+ mZenModeHelperSpy.pullRules(events);
+ assertEquals(4, events.size());
}
@Test
@@ -1323,10 +1445,12 @@ public class ZenModeHelperTest extends UiServiceTestCase {
@Test
public void testEmptyDefaultRulesMap() {
+ List<StatsEvent> events = new LinkedList<>();
ZenModeConfig config = new ZenModeConfig();
config.automaticRules = new ArrayMap<>();
mZenModeHelperSpy.mConfig = config;
mZenModeHelperSpy.updateDefaultZenRules(); // shouldn't throw null pointer
+ mZenModeHelperSpy.pullRules(events); // shouldn't throw null pointer
}
@Test
@@ -1342,7 +1466,7 @@ public class ZenModeHelperTest extends UiServiceTestCase {
updatedDefaultRule.creationTime = 0;
updatedDefaultRule.id = SCHEDULE_DEFAULT_RULE_ID;
updatedDefaultRule.name = "Schedule Default Rule";
- updatedDefaultRule.zenMode = Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS;
+ updatedDefaultRule.zenMode = ZEN_MODE_IMPORTANT_INTERRUPTIONS;
updatedDefaultRule.conditionId = ZenModeConfig.toScheduleConditionId(new ScheduleInfo());
updatedDefaultRule.component = new ComponentName("android", "ScheduleConditionProvider");
@@ -1368,7 +1492,7 @@ public class ZenModeHelperTest extends UiServiceTestCase {
updatedDefaultRule.creationTime = 0;
updatedDefaultRule.id = SCHEDULE_DEFAULT_RULE_ID;
updatedDefaultRule.name = "Schedule Default Rule";
- updatedDefaultRule.zenMode = Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS;
+ updatedDefaultRule.zenMode = ZEN_MODE_IMPORTANT_INTERRUPTIONS;
updatedDefaultRule.conditionId = ZenModeConfig.toScheduleConditionId(new ScheduleInfo());
updatedDefaultRule.component = new ComponentName("android", "ScheduleConditionProvider");
@@ -1395,7 +1519,7 @@ public class ZenModeHelperTest extends UiServiceTestCase {
customDefaultRule.creationTime = 0;
customDefaultRule.id = SCHEDULE_DEFAULT_RULE_ID;
customDefaultRule.name = "Schedule Default Rule";
- customDefaultRule.zenMode = Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS;
+ customDefaultRule.zenMode = ZEN_MODE_IMPORTANT_INTERRUPTIONS;
customDefaultRule.conditionId = ZenModeConfig.toScheduleConditionId(new ScheduleInfo());
customDefaultRule.component = new ComponentName("android", "ScheduleConditionProvider");
@@ -1433,7 +1557,7 @@ public class ZenModeHelperTest extends UiServiceTestCase {
}
private void setupZenConfig() {
- mZenModeHelperSpy.mZenMode = Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS;
+ mZenModeHelperSpy.mZenMode = ZEN_MODE_IMPORTANT_INTERRUPTIONS;
mZenModeHelperSpy.mConfig.allowAlarms = false;
mZenModeHelperSpy.mConfig.allowMedia = false;
mZenModeHelperSpy.mConfig.allowSystem = false;
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 a0ee417c8b47..b16ca8b92848 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/ZenPolicyTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/ZenPolicyTest.java
@@ -17,14 +17,18 @@
package com.android.server.notification;
import static junit.framework.Assert.assertEquals;
+import static junit.framework.Assert.fail;
import android.service.notification.ZenPolicy;
+import android.service.notification.nano.DNDPolicyProto;
import android.test.suitebuilder.annotation.SmallTest;
import androidx.test.runner.AndroidJUnit4;
import com.android.server.UiServiceTestCase;
+import com.google.protobuf.nano.InvalidProtocolBufferNanoException;
+
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -190,6 +194,7 @@ public class ZenPolicyTest extends UiServiceTestCase {
ZenPolicy policy = builder.build();
assertEquals(ZenPolicy.STATE_UNSET, policy.getPriorityCategoryMessages());
assertEquals(ZenPolicy.PEOPLE_TYPE_UNSET, policy.getPriorityMessageSenders());
+ assertProtoMatches(policy, policy.toProto());
}
@Test
@@ -201,6 +206,7 @@ public class ZenPolicyTest extends UiServiceTestCase {
ZenPolicy policy = builder.build();
assertEquals(ZenPolicy.STATE_ALLOW, policy.getPriorityCategoryCalls());
assertEquals(ZenPolicy.PEOPLE_TYPE_ANYONE, policy.getPriorityCallSenders());
+ assertProtoMatches(policy, policy.toProto());
}
@Test
@@ -210,6 +216,7 @@ public class ZenPolicyTest extends UiServiceTestCase {
ZenPolicy policy = builder.build();
assertAllPriorityCategoriesUnsetExcept(policy, -1);
assertAllVisualEffectsUnsetExcept(policy, -1);
+ assertProtoMatches(policy, policy.toProto());
}
@Test
@@ -221,12 +228,14 @@ public class ZenPolicyTest extends UiServiceTestCase {
assertAllPriorityCategoriesUnsetExcept(policy, ZenPolicy.PRIORITY_CATEGORY_REMINDERS);
assertEquals(ZenPolicy.STATE_ALLOW, policy.getPriorityCategoryReminders());
assertAllVisualEffectsUnsetExcept(policy, -1);
+ assertProtoMatches(policy, policy.toProto());
builder.allowReminders(false);
policy = builder.build();
assertAllPriorityCategoriesUnsetExcept(policy, ZenPolicy.PRIORITY_CATEGORY_REMINDERS);
assertEquals(ZenPolicy.STATE_DISALLOW, policy.getPriorityCategoryReminders());
assertAllVisualEffectsUnsetExcept(policy, -1);
+ assertProtoMatches(policy, policy.toProto());
}
@Test
@@ -238,12 +247,14 @@ public class ZenPolicyTest extends UiServiceTestCase {
assertAllPriorityCategoriesUnsetExcept(policy, ZenPolicy.PRIORITY_CATEGORY_EVENTS);
assertEquals(ZenPolicy.STATE_ALLOW, policy.getPriorityCategoryEvents());
assertAllVisualEffectsUnsetExcept(policy, -1);
+ assertProtoMatches(policy, policy.toProto());
builder.allowEvents(false);
policy = builder.build();
assertAllPriorityCategoriesUnsetExcept(policy, ZenPolicy.PRIORITY_CATEGORY_EVENTS);
assertEquals(ZenPolicy.STATE_DISALLOW, policy.getPriorityCategoryEvents());
assertAllVisualEffectsUnsetExcept(policy, -1);
+ assertProtoMatches(policy, policy.toProto());
}
@Test
@@ -256,6 +267,7 @@ public class ZenPolicyTest extends UiServiceTestCase {
assertEquals(ZenPolicy.STATE_ALLOW, policy.getPriorityCategoryMessages());
assertEquals(ZenPolicy.PEOPLE_TYPE_ANYONE, policy.getPriorityMessageSenders());
assertAllVisualEffectsUnsetExcept(policy, -1);
+ assertProtoMatches(policy, policy.toProto());
builder.allowMessages(ZenPolicy.PEOPLE_TYPE_CONTACTS);
policy = builder.build();
@@ -263,6 +275,7 @@ public class ZenPolicyTest extends UiServiceTestCase {
assertEquals(ZenPolicy.STATE_ALLOW, policy.getPriorityCategoryMessages());
assertEquals(ZenPolicy.PEOPLE_TYPE_CONTACTS, policy.getPriorityMessageSenders());
assertAllVisualEffectsUnsetExcept(policy, -1);
+ assertProtoMatches(policy, policy.toProto());
builder.allowMessages(ZenPolicy.PEOPLE_TYPE_STARRED);
policy = builder.build();
@@ -270,6 +283,7 @@ public class ZenPolicyTest extends UiServiceTestCase {
assertEquals(ZenPolicy.STATE_ALLOW, policy.getPriorityCategoryMessages());
assertEquals(ZenPolicy.PEOPLE_TYPE_STARRED, policy.getPriorityMessageSenders());
assertAllVisualEffectsUnsetExcept(policy, -1);
+ assertProtoMatches(policy, policy.toProto());
builder.allowMessages(ZenPolicy.PEOPLE_TYPE_NONE);
policy = builder.build();
@@ -277,11 +291,13 @@ public class ZenPolicyTest extends UiServiceTestCase {
assertEquals(ZenPolicy.STATE_DISALLOW, policy.getPriorityCategoryMessages());
assertEquals(ZenPolicy.PEOPLE_TYPE_NONE, policy.getPriorityMessageSenders());
assertAllVisualEffectsUnsetExcept(policy, -1);
+ assertProtoMatches(policy, policy.toProto());
builder.allowMessages(ZenPolicy.PEOPLE_TYPE_UNSET);
policy = builder.build();
assertAllPriorityCategoriesUnsetExcept(policy, -1);
assertAllVisualEffectsUnsetExcept(policy, -1);
+ assertProtoMatches(policy, policy.toProto());
}
@Test
@@ -294,6 +310,7 @@ public class ZenPolicyTest extends UiServiceTestCase {
assertEquals(ZenPolicy.STATE_ALLOW, policy.getPriorityCategoryCalls());
assertEquals(ZenPolicy.PEOPLE_TYPE_ANYONE, policy.getPriorityCallSenders());
assertAllVisualEffectsUnsetExcept(policy, -1);
+ assertProtoMatches(policy, policy.toProto());
builder.allowCalls(ZenPolicy.PEOPLE_TYPE_CONTACTS);
policy = builder.build();
@@ -301,6 +318,7 @@ public class ZenPolicyTest extends UiServiceTestCase {
assertEquals(ZenPolicy.STATE_ALLOW, policy.getPriorityCategoryCalls());
assertEquals(ZenPolicy.PEOPLE_TYPE_CONTACTS, policy.getPriorityCallSenders());
assertAllVisualEffectsUnsetExcept(policy, -1);
+ assertProtoMatches(policy, policy.toProto());
builder.allowCalls(ZenPolicy.PEOPLE_TYPE_STARRED);
policy = builder.build();
@@ -308,6 +326,7 @@ public class ZenPolicyTest extends UiServiceTestCase {
assertEquals(ZenPolicy.STATE_ALLOW, policy.getPriorityCategoryCalls());
assertEquals(ZenPolicy.PEOPLE_TYPE_STARRED, policy.getPriorityCallSenders());
assertAllVisualEffectsUnsetExcept(policy, -1);
+ assertProtoMatches(policy, policy.toProto());
builder.allowCalls(ZenPolicy.PEOPLE_TYPE_NONE);
policy = builder.build();
@@ -315,11 +334,13 @@ public class ZenPolicyTest extends UiServiceTestCase {
assertEquals(ZenPolicy.STATE_DISALLOW, policy.getPriorityCategoryCalls());
assertEquals(ZenPolicy.PEOPLE_TYPE_NONE, policy.getPriorityCallSenders());
assertAllVisualEffectsUnsetExcept(policy, -1);
+ assertProtoMatches(policy, policy.toProto());
builder.allowCalls(ZenPolicy.PEOPLE_TYPE_UNSET);
policy = builder.build();
assertAllPriorityCategoriesUnsetExcept(policy, -1);
assertAllVisualEffectsUnsetExcept(policy, -1);
+ assertProtoMatches(policy, policy.toProto());
}
@Test
@@ -331,12 +352,14 @@ public class ZenPolicyTest extends UiServiceTestCase {
assertAllPriorityCategoriesUnsetExcept(policy, ZenPolicy.PRIORITY_CATEGORY_REPEAT_CALLERS);
assertEquals(ZenPolicy.STATE_ALLOW, policy.getPriorityCategoryRepeatCallers());
assertAllVisualEffectsUnsetExcept(policy, -1);
+ assertProtoMatches(policy, policy.toProto());
builder.allowRepeatCallers(false);
policy = builder.build();
assertAllPriorityCategoriesUnsetExcept(policy, ZenPolicy.PRIORITY_CATEGORY_REPEAT_CALLERS);
assertEquals(ZenPolicy.STATE_DISALLOW, policy.getPriorityCategoryRepeatCallers());
assertAllVisualEffectsUnsetExcept(policy, -1);
+ assertProtoMatches(policy, policy.toProto());
}
@Test
@@ -348,12 +371,14 @@ public class ZenPolicyTest extends UiServiceTestCase {
assertAllPriorityCategoriesUnsetExcept(policy, ZenPolicy.PRIORITY_CATEGORY_ALARMS);
assertEquals(ZenPolicy.STATE_ALLOW, policy.getPriorityCategoryAlarms());
assertAllVisualEffectsUnsetExcept(policy, -1);
+ assertProtoMatches(policy, policy.toProto());
builder.allowAlarms(false);
policy = builder.build();
assertAllPriorityCategoriesUnsetExcept(policy, ZenPolicy.PRIORITY_CATEGORY_ALARMS);
assertEquals(ZenPolicy.STATE_DISALLOW, policy.getPriorityCategoryAlarms());
assertAllVisualEffectsUnsetExcept(policy, -1);
+ assertProtoMatches(policy, policy.toProto());
}
@Test
@@ -365,12 +390,14 @@ public class ZenPolicyTest extends UiServiceTestCase {
assertAllPriorityCategoriesUnsetExcept(policy, ZenPolicy.PRIORITY_CATEGORY_MEDIA);
assertEquals(ZenPolicy.STATE_ALLOW, policy.getPriorityCategoryMedia());
assertAllVisualEffectsUnsetExcept(policy, -1);
+ assertProtoMatches(policy, policy.toProto());
builder.allowMedia(false);
policy = builder.build();
assertAllPriorityCategoriesUnsetExcept(policy, ZenPolicy.PRIORITY_CATEGORY_MEDIA);
assertEquals(ZenPolicy.STATE_DISALLOW, policy.getPriorityCategoryMedia());
assertAllVisualEffectsUnsetExcept(policy, -1);
+ assertProtoMatches(policy, policy.toProto());
}
@Test
@@ -382,12 +409,119 @@ public class ZenPolicyTest extends UiServiceTestCase {
assertAllPriorityCategoriesUnsetExcept(policy, ZenPolicy.PRIORITY_CATEGORY_SYSTEM);
assertEquals(ZenPolicy.STATE_ALLOW, policy.getPriorityCategorySystem());
assertAllVisualEffectsUnsetExcept(policy, -1);
+ assertProtoMatches(policy, policy.toProto());
builder.allowSystem(false);
policy = builder.build();
assertAllPriorityCategoriesUnsetExcept(policy, ZenPolicy.PRIORITY_CATEGORY_SYSTEM);
assertEquals(ZenPolicy.STATE_DISALLOW, policy.getPriorityCategorySystem());
assertAllVisualEffectsUnsetExcept(policy, -1);
+ assertProtoMatches(policy, policy.toProto());
+ }
+
+ @Test
+ public void tesShowFullScreenIntent() {
+ ZenPolicy.Builder builder = new ZenPolicy.Builder();
+
+ builder.showFullScreenIntent(true);
+ ZenPolicy policy = builder.build();
+ assertAllVisualEffectsUnsetExcept(policy, ZenPolicy.VISUAL_EFFECT_FULL_SCREEN_INTENT);
+ assertProtoMatches(policy, policy.toProto());
+
+ builder.showFullScreenIntent(false);
+ policy = builder.build();
+ assertAllVisualEffectsUnsetExcept(policy, ZenPolicy.VISUAL_EFFECT_FULL_SCREEN_INTENT);
+ assertProtoMatches(policy, policy.toProto());
+ }
+
+ @Test
+ public void tesShowLights() {
+ ZenPolicy.Builder builder = new ZenPolicy.Builder();
+
+ builder.showLights(true);
+ ZenPolicy policy = builder.build();
+ assertAllVisualEffectsUnsetExcept(policy, ZenPolicy.VISUAL_EFFECT_LIGHTS);
+ assertProtoMatches(policy, policy.toProto());
+
+ builder.showLights(false);
+ policy = builder.build();
+ assertAllVisualEffectsUnsetExcept(policy, ZenPolicy.VISUAL_EFFECT_LIGHTS);
+ assertProtoMatches(policy, policy.toProto());
+ }
+
+ @Test
+ public void tesShowPeeking() {
+ ZenPolicy.Builder builder = new ZenPolicy.Builder();
+
+ builder.showPeeking(true);
+ ZenPolicy policy = builder.build();
+ assertAllVisualEffectsUnsetExcept(policy, ZenPolicy.VISUAL_EFFECT_PEEK);
+ assertProtoMatches(policy, policy.toProto());
+
+ builder.showPeeking(false);
+ policy = builder.build();
+ assertAllVisualEffectsUnsetExcept(policy, ZenPolicy.VISUAL_EFFECT_PEEK);
+ assertProtoMatches(policy, policy.toProto());
+ }
+
+ @Test
+ public void tesShowStatusBarIcons() {
+ ZenPolicy.Builder builder = new ZenPolicy.Builder();
+
+ builder.showStatusBarIcons(true);
+ ZenPolicy policy = builder.build();
+ assertAllVisualEffectsUnsetExcept(policy, ZenPolicy.VISUAL_EFFECT_STATUS_BAR);
+ assertProtoMatches(policy, policy.toProto());
+
+ builder.showStatusBarIcons(false);
+ policy = builder.build();
+ assertAllVisualEffectsUnsetExcept(policy, ZenPolicy.VISUAL_EFFECT_STATUS_BAR);
+ assertProtoMatches(policy, policy.toProto());
+ }
+
+ @Test
+ public void tesShowBadges() {
+ ZenPolicy.Builder builder = new ZenPolicy.Builder();
+
+ builder.showBadges(true);
+ ZenPolicy policy = builder.build();
+ assertAllVisualEffectsUnsetExcept(policy, ZenPolicy.VISUAL_EFFECT_BADGE);
+ assertProtoMatches(policy, policy.toProto());
+
+ builder.showBadges(false);
+ policy = builder.build();
+ assertAllVisualEffectsUnsetExcept(policy, ZenPolicy.VISUAL_EFFECT_BADGE);
+ assertProtoMatches(policy, policy.toProto());
+ }
+
+ @Test
+ public void tesShowInAmbientDisplay() {
+ ZenPolicy.Builder builder = new ZenPolicy.Builder();
+
+ builder.showInAmbientDisplay(true);
+ ZenPolicy policy = builder.build();
+ assertAllVisualEffectsUnsetExcept(policy, ZenPolicy.VISUAL_EFFECT_AMBIENT);
+ assertProtoMatches(policy, policy.toProto());
+
+ builder.showInAmbientDisplay(false);
+ policy = builder.build();
+ assertAllVisualEffectsUnsetExcept(policy, ZenPolicy.VISUAL_EFFECT_AMBIENT);
+ assertProtoMatches(policy, policy.toProto());
+ }
+
+ @Test
+ public void tesShowInNotificationList() {
+ ZenPolicy.Builder builder = new ZenPolicy.Builder();
+
+ builder.showInNotificationList(true);
+ ZenPolicy policy = builder.build();
+ assertAllVisualEffectsUnsetExcept(policy, ZenPolicy.VISUAL_EFFECT_NOTIFICATION_LIST);
+ assertProtoMatches(policy, policy.toProto());
+
+ builder.showInNotificationList(false);
+ policy = builder.build();
+ assertAllVisualEffectsUnsetExcept(policy, ZenPolicy.VISUAL_EFFECT_NOTIFICATION_LIST);
+ assertProtoMatches(policy, policy.toProto());
}
private void assertAllPriorityCategoriesUnsetExcept(ZenPolicy policy, int except) {
@@ -453,4 +587,35 @@ public class ZenPolicyTest extends UiServiceTestCase {
assertEquals(ZenPolicy.STATE_UNSET, policy.getVisualEffectNotificationList());
}
}
+
+ private void assertProtoMatches(ZenPolicy policy, byte[] bytes) {
+ try {
+ DNDPolicyProto proto = DNDPolicyProto.parseFrom(bytes);
+
+ assertEquals(policy.getPriorityCategoryCalls(), proto.calls);
+ assertEquals(policy.getPriorityCategoryRepeatCallers(), proto.repeatCallers);
+ assertEquals(policy.getPriorityCategoryMessages(), proto.messages);
+ assertEquals(policy.getPriorityCategoryConversations(), proto.conversations);
+ assertEquals(policy.getPriorityCategoryReminders(), proto.reminders);
+ assertEquals(policy.getPriorityCategoryEvents(), proto.events);
+ assertEquals(policy.getPriorityCategoryAlarms(), proto.alarms);
+ assertEquals(policy.getPriorityCategoryMedia(), proto.media);
+ assertEquals(policy.getPriorityCategorySystem(), proto.system);
+
+ assertEquals(policy.getVisualEffectFullScreenIntent(), proto.fullscreen);
+ assertEquals(policy.getVisualEffectLights(), proto.lights);
+ assertEquals(policy.getVisualEffectPeek(), proto.peek);
+ assertEquals(policy.getVisualEffectStatusBar(), proto.statusBar);
+ assertEquals(policy.getVisualEffectBadge(), proto.badge);
+ assertEquals(policy.getVisualEffectAmbient(), proto.ambient);
+ assertEquals(policy.getVisualEffectNotificationList(), proto.notificationList);
+
+ assertEquals(policy.getPriorityCallSenders(), proto.allowCallsFrom);
+ assertEquals(policy.getPriorityMessageSenders(), proto.allowMessagesFrom);
+ assertEquals(policy.getPriorityConversationSenders(), proto.allowConversationsFrom);
+ } catch (InvalidProtocolBufferNanoException e) {
+ fail("could not parse proto bytes");
+ }
+
+ }
}
diff --git a/services/tests/wmtests/AndroidManifest.xml b/services/tests/wmtests/AndroidManifest.xml
index f382fbae9280..30df0d4b4ad9 100644
--- a/services/tests/wmtests/AndroidManifest.xml
+++ b/services/tests/wmtests/AndroidManifest.xml
@@ -62,6 +62,7 @@
android:resumeWhilePausing="true"/>
<activity android:name="com.android.server.wm.ScreenDecorWindowTests$TestActivity"
android:showWhenLocked="true" android:allowEmbedded="true"/>
+ <activity android:name="com.android.server.wm.ActivityLeakTests$DetectLeakActivity" />
</application>
<instrumentation
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityLeakTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityLeakTests.java
new file mode 100644
index 000000000000..bd6ac58c2445
--- /dev/null
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityLeakTests.java
@@ -0,0 +1,184 @@
+/*
+ * 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.server.wm;
+
+import static android.content.Intent.FLAG_ACTIVITY_MULTIPLE_TASK;
+import static android.content.Intent.FLAG_ACTIVITY_NEW_DOCUMENT;
+import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
+
+import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
+
+import static org.junit.Assert.assertFalse;
+
+import android.app.Activity;
+import android.app.Instrumentation;
+import android.content.Context;
+import android.content.Intent;
+import android.os.Bundle;
+import android.os.Debug;
+import android.os.StrictMode;
+import android.os.strictmode.InstanceCountViolation;
+import android.util.Log;
+
+import org.junit.After;
+import org.junit.Test;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Tests for Activity leaks.
+ *
+ * Build/Install/Run:
+ * atest WmTests:ActivityLeakTests
+ */
+public class ActivityLeakTests {
+
+ private final Instrumentation mInstrumentation = getInstrumentation();
+ private final Context mContext = mInstrumentation.getTargetContext();
+ private final List<Activity> mStartedActivityList = new ArrayList<>();
+
+ @After
+ public void tearDown() {
+ mInstrumentation.runOnMainSync(() -> {
+ // Reset strict mode.
+ StrictMode.setVmPolicy(new StrictMode.VmPolicy.Builder().build());
+ });
+ for (Activity activity : mStartedActivityList) {
+ if (!activity.isDestroyed()) {
+ activity.finish();
+ }
+ }
+ mStartedActivityList.clear();
+ }
+
+ @Test
+ public void testActivityLeak() {
+ final Bundle intentExtras = new Bundle();
+ intentExtras.putBoolean(DetectLeakActivity.ENABLE_STRICT_MODE, true);
+ final DetectLeakActivity activity = (DetectLeakActivity) startActivity(
+ DetectLeakActivity.class, 0 /* flags */, intentExtras);
+ mStartedActivityList.add(activity);
+
+ activity.finish();
+
+ assertFalse("Leak found on activity", activity.isLeakedAfterDestroy());
+ }
+
+ @Test
+ public void testActivityLeakForTwoInstances() {
+ final Bundle intentExtras = new Bundle();
+
+ // Launch an activity, then enable strict mode
+ intentExtras.putBoolean(DetectLeakActivity.ENABLE_STRICT_MODE, true);
+ final DetectLeakActivity activity1 = (DetectLeakActivity) startActivity(
+ DetectLeakActivity.class, 0 /* flags */, intentExtras);
+ mStartedActivityList.add(activity1);
+
+ // Launch second activity instance.
+ intentExtras.putBoolean(DetectLeakActivity.ENABLE_STRICT_MODE, false);
+ final DetectLeakActivity activity2 = (DetectLeakActivity) startActivity(
+ DetectLeakActivity.class,
+ FLAG_ACTIVITY_MULTIPLE_TASK | FLAG_ACTIVITY_NEW_DOCUMENT, intentExtras);
+ mStartedActivityList.add(activity2);
+
+ // Destroy the activity
+ activity1.finish();
+ assertFalse("Leak found on activity 1", activity1.isLeakedAfterDestroy());
+
+ activity2.finish();
+ assertFalse("Leak found on activity 2", activity2.isLeakedAfterDestroy());
+ }
+
+ private Activity startActivity(Class<?> cls, int flags, Bundle extras) {
+ final Intent intent = new Intent(mContext, cls);
+ intent.addFlags(flags | FLAG_ACTIVITY_NEW_TASK);
+ if (extras != null) {
+ intent.putExtras(extras);
+ }
+ return mInstrumentation.startActivitySync(intent);
+ }
+
+ public static class DetectLeakActivity extends Activity {
+
+ private static final String TAG = "DetectLeakActivity";
+
+ public static final String ENABLE_STRICT_MODE = "enable_strict_mode";
+
+ private volatile boolean mWasDestroyed;
+ private volatile boolean mIsLeaked;
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ if (getIntent().getBooleanExtra(ENABLE_STRICT_MODE, false)) {
+ enableStrictMode();
+ }
+ }
+
+ @Override
+ protected void onDestroy() {
+ super.onDestroy();
+ getWindow().getDecorView().post(() -> {
+ synchronized (this) {
+ mWasDestroyed = true;
+ notifyAll();
+ }
+ });
+ }
+
+ public boolean isLeakedAfterDestroy() {
+ synchronized (this) {
+ while (!mWasDestroyed && !mIsLeaked) {
+ try {
+ wait(5000 /* timeoutMs */);
+ } catch (InterruptedException ignored) {
+ }
+ }
+ }
+ return mIsLeaked;
+ }
+
+ private void enableStrictMode() {
+ StrictMode.setVmPolicy(new StrictMode.VmPolicy.Builder()
+ .detectActivityLeaks()
+ .penaltyLog()
+ .penaltyListener(Runnable::run, violation -> {
+ if (!(violation instanceof InstanceCountViolation)) {
+ return;
+ }
+ synchronized (this) {
+ mIsLeaked = true;
+ notifyAll();
+ }
+ Log.w(TAG, violation.toString() + ", " + dumpHprofData());
+ })
+ .build());
+ }
+
+ private String dumpHprofData() {
+ try {
+ final String fileName = getDataDir().getPath() + "/ActivityLeakHeapDump.hprof";
+ Debug.dumpHprofData(fileName);
+ return "memory dump filename: " + fileName;
+ } catch (Throwable e) {
+ Log.e(TAG, "dumpHprofData failed", e);
+ return "failed to save memory dump";
+ }
+ }
+ }
+}
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityTaskManagerServiceTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityTaskManagerServiceTests.java
index bd616a3a96f3..64b5eca1beb8 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityTaskManagerServiceTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityTaskManagerServiceTests.java
@@ -17,7 +17,6 @@
package com.android.server.wm;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.any;
-import static com.android.dx.mockito.inline.extended.ExtendedMockito.doNothing;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession;
@@ -111,7 +110,7 @@ public class ActivityTaskManagerServiceTests extends ActivityTestsBase {
final ActivityStack stack = new StackBuilder(mRootWindowContainer).build();
final ActivityRecord activity = stack.getBottomMostTask().getTopNonFinishingActivity();
ClientLifecycleManager lifecycleManager = mService.getLifecycleManager();
- doNothing().when(lifecycleManager).scheduleTransaction(any());
+ doReturn(false).when(activity).inPinnedWindowingMode();
doReturn(false).when(activity).checkEnterPictureInPictureState(anyString(), anyBoolean());
mService.requestPictureInPictureMode(activity.token);
@@ -120,6 +119,19 @@ public class ActivityTaskManagerServiceTests extends ActivityTestsBase {
verify(lifecycleManager, times(0)).scheduleTransaction(any());
}
+ @Test(expected = IllegalStateException.class)
+ public void testOnPictureInPictureRequested_alreadyInPIPMode() throws RemoteException {
+ final ActivityStack stack = new StackBuilder(mRootWindowContainer).build();
+ final ActivityRecord activity = stack.getBottomMostTask().getTopNonFinishingActivity();
+ ClientLifecycleManager lifecycleManager = mService.getLifecycleManager();
+ doReturn(true).when(activity).inPinnedWindowingMode();
+
+ mService.requestPictureInPictureMode(activity.token);
+
+ // Check that no transactions with enter pip requests are made.
+ verify(lifecycleManager, times(0)).scheduleTransaction(any());
+ }
+
@Test
public void testDisplayWindowListener() {
final ArrayList<Integer> added = new ArrayList<>();
diff --git a/services/tests/wmtests/src/com/android/server/wm/AppWindowTokenTests.java b/services/tests/wmtests/src/com/android/server/wm/AppWindowTokenTests.java
index 36d4888fa56e..02de408343c5 100644
--- a/services/tests/wmtests/src/com/android/server/wm/AppWindowTokenTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/AppWindowTokenTests.java
@@ -21,6 +21,7 @@ import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_BEHIND;
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE;
+import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_PORTRAIT;
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE;
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSET;
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
@@ -295,6 +296,27 @@ public class AppWindowTokenTests extends WindowTestsBase {
}
@Test
+ public void testRespectTopFullscreenOrientation() {
+ final Configuration displayConfig = mActivity.mDisplayContent.getConfiguration();
+ final Configuration activityConfig = mActivity.getConfiguration();
+ mActivity.setOrientation(SCREEN_ORIENTATION_PORTRAIT);
+
+ assertEquals(Configuration.ORIENTATION_PORTRAIT, displayConfig.orientation);
+ assertEquals(Configuration.ORIENTATION_PORTRAIT, activityConfig.orientation);
+
+ final ActivityRecord topActivity = WindowTestUtils.createTestActivityRecord(mStack);
+ topActivity.setOrientation(SCREEN_ORIENTATION_LANDSCAPE);
+
+ assertEquals(Configuration.ORIENTATION_LANDSCAPE, displayConfig.orientation);
+ // Although the activity requested portrait, it is not the top activity that determines
+ // the display orientation. So it should be able to inherit the orientation from parent.
+ // Otherwise its configuration will be inconsistent that its orientation is portrait but
+ // other screen configurations are in landscape, e.g. screenWidthDp, screenHeightDp, and
+ // window configuration.
+ assertEquals(Configuration.ORIENTATION_LANDSCAPE, activityConfig.orientation);
+ }
+
+ @Test
public void testReportOrientationChange() {
mActivity.setOrientation(SCREEN_ORIENTATION_LANDSCAPE);
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 7197ce9c22aa..4ad7dff87072 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
@@ -16,7 +16,10 @@
package com.android.server.wm;
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
+import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
+import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE;
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_PORTRAIT;
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
@@ -73,6 +76,8 @@ import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.atLeastOnce;
+import static org.mockito.Mockito.clearInvocations;
import static org.mockito.Mockito.doAnswer;
import android.annotation.SuppressLint;
@@ -1168,6 +1173,57 @@ public class DisplayContentTests extends WindowTestsBase {
}
@Test
+ public void testNoFixedRotationWithPip() {
+ mWm.mIsFixedRotationTransformEnabled = true;
+ // Make resume-top really update the activity state.
+ doReturn(false).when(mWm.mAtmService).isBooting();
+ doReturn(true).when(mWm.mAtmService).isBooted();
+ // Speed up the test by a few seconds.
+ mWm.mAtmService.deferWindowLayout();
+ doNothing().when(mWm).startFreezingDisplay(anyInt(), anyInt(), any(), anyInt());
+
+ final DisplayContent displayContent = mWm.mRoot.getDefaultDisplay();
+ final Configuration displayConfig = displayContent.getConfiguration();
+ final ActivityRecord pinnedActivity = createActivityRecord(displayContent,
+ WINDOWING_MODE_PINNED, ACTIVITY_TYPE_STANDARD);
+ final Task pinnedTask = pinnedActivity.getRootTask();
+ final ActivityRecord homeActivity = WindowTestUtils.createTestActivityRecord(
+ displayContent.getDefaultTaskDisplayArea().getOrCreateRootHomeTask());
+ if (displayConfig.orientation == Configuration.ORIENTATION_PORTRAIT) {
+ homeActivity.setOrientation(SCREEN_ORIENTATION_PORTRAIT);
+ pinnedActivity.setOrientation(SCREEN_ORIENTATION_LANDSCAPE);
+ } else {
+ homeActivity.setOrientation(SCREEN_ORIENTATION_LANDSCAPE);
+ pinnedActivity.setOrientation(SCREEN_ORIENTATION_PORTRAIT);
+ }
+ final int homeConfigOrientation = homeActivity.getRequestedConfigurationOrientation();
+ final int pinnedConfigOrientation = pinnedActivity.getRequestedConfigurationOrientation();
+
+ assertEquals(homeConfigOrientation, displayConfig.orientation);
+
+ clearInvocations(mWm);
+ // Leave PiP to fullscreen. The orientation can be updated from
+ // ActivityRecord#reportDescendantOrientationChangeIfNeeded.
+ pinnedTask.setWindowingMode(WINDOWING_MODE_FULLSCREEN);
+ homeActivity.setState(ActivityStack.ActivityState.STOPPED, "test");
+
+ assertFalse(displayContent.hasTopFixedRotationLaunchingApp());
+ verify(mWm, atLeastOnce()).startFreezingDisplay(anyInt(), anyInt(), any(), anyInt());
+ assertEquals(pinnedConfigOrientation, displayConfig.orientation);
+ assertFalse(displayContent.getPinnedStackController().isPipActiveOrWindowingModeChanging());
+
+ clearInvocations(mWm);
+ // Enter PiP from fullscreen. The orientation can be updated from
+ // ensure-visibility/resume-focused-stack -> ActivityRecord#makeActiveIfNeeded -> resume.
+ pinnedTask.setWindowingMode(WINDOWING_MODE_PINNED);
+
+ assertFalse(displayContent.hasTopFixedRotationLaunchingApp());
+ verify(mWm, atLeastOnce()).startFreezingDisplay(anyInt(), anyInt(), any(), anyInt());
+ assertEquals(homeConfigOrientation, displayConfig.orientation);
+ assertTrue(displayContent.getPinnedStackController().isPipActiveOrWindowingModeChanging());
+ }
+
+ @Test
public void testRemoteRotation() {
DisplayContent dc = createNewDisplay();
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 68bc58493f13..665cf83cd33c 100644
--- a/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java
@@ -145,7 +145,8 @@ public class SizeCompatTests extends ActivityTestsBase {
final Rect appBounds = mActivity.getWindowConfiguration().getAppBounds();
// The parent configuration doesn't change since the first resolved configuration, so the
- // activity should fit in the parent naturally. (size=583x700).
+ // activity should fit in the parent naturally (size=583x700, appBounds=[9, 100 - 592, 800],
+ // horizontal offset = round((600 - 583) / 2) = 9)).
assertFitted();
final int offsetX = (int) ((1f + displayBounds.width() - appBounds.width()) / 2);
// The bounds must be horizontal centered.
@@ -160,7 +161,7 @@ public class SizeCompatTests extends ActivityTestsBase {
assertFitted();
// After the orientation of activity is changed, even display is not rotated, the aspect
- // ratio should be the same (appBounds=[9, 100 - 592, 800], x-offset=round((600-583)/2)=9).
+ // ratio should be the same (bounds=[0, 0 - 600, 600], appBounds=[0, 100 - 600, 600]).
assertEquals(appBounds.width(), appBounds.height() * aspectRatio, 0.5f /* delta */);
// The notch is still on top.
assertEquals(mActivity.getBounds().height(), appBounds.height() + notchHeight);
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
index cf07221917cc..9621f68f9d6c 100644
--- a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
@@ -73,6 +73,7 @@ import android.util.ArraySet;
import android.util.Log;
import android.util.Slog;
+import com.android.internal.annotations.GuardedBy;
import com.android.internal.app.IVoiceActionCheckCallback;
import com.android.internal.app.IVoiceInteractionManagerService;
import com.android.internal.app.IVoiceInteractionSessionListener;
@@ -230,6 +231,10 @@ public class VoiceInteractionManagerService extends SystemService {
private int mCurUser;
private boolean mCurUserUnlocked;
private boolean mCurUserSupported;
+
+ @GuardedBy("this")
+ private boolean mTemporarilyDisabled;
+
private final boolean mEnableService;
VoiceInteractionManagerServiceStub() {
@@ -316,8 +321,12 @@ public class VoiceInteractionManagerService extends SystemService {
Settings.Secure.VOICE_INTERACTION_SERVICE, userHandle);
ComponentName curRecognizer = getCurRecognizer(userHandle);
VoiceInteractionServiceInfo curInteractorInfo = null;
- if (DEBUG) Slog.d(TAG, "curInteractorStr=" + curInteractorStr
- + " curRecognizer=" + curRecognizer);
+ if (DEBUG) {
+ Slog.d(TAG, "curInteractorStr=" + curInteractorStr
+ + " curRecognizer=" + curRecognizer
+ + " mEnableService=" + mEnableService
+ + " mTemporarilyDisabled=" + mTemporarilyDisabled);
+ }
if (curInteractorStr == null && curRecognizer != null && mEnableService) {
// If there is no interactor setting, that means we are upgrading
// from an older platform version. If the current recognizer is not
@@ -472,10 +481,11 @@ public class VoiceInteractionManagerService extends SystemService {
}
void switchImplementationIfNeededLocked(boolean force) {
- if (!mCurUserSupported) {
+ if (!mCurUserSupported || mTemporarilyDisabled) {
if (DEBUG_USER) {
- Slog.d(TAG, "switchImplementationIfNeeded(): skipping on unsuported user "
- + mCurUser);
+ Slog.d(TAG, "switchImplementationIfNeeded(): skipping: force= " + force
+ + "mCurUserSupported=" + mCurUserSupported
+ + "mTemporarilyDisabled=" + mTemporarilyDisabled);
}
if (mImpl != null) {
mImpl.shutdownLocked();
@@ -928,6 +938,25 @@ public class VoiceInteractionManagerService extends SystemService {
}
}
+ @Override
+ public void setDisabled(boolean disabled) {
+ enforceCallingPermission(Manifest.permission.ACCESS_VOICE_INTERACTION_SERVICE);
+ synchronized (this) {
+ if (mTemporarilyDisabled == disabled) {
+ if (DEBUG) Slog.d(TAG, "setDisabled(): already " + disabled);
+ return;
+ }
+ Slog.i(TAG, "setDisabled(): changing to " + disabled);
+ final long caller = Binder.clearCallingIdentity();
+ try {
+ mTemporarilyDisabled = disabled;
+ switchImplementationIfNeeded(/* force= */ false);
+ } finally {
+ Binder.restoreCallingIdentity(caller);
+ }
+ }
+ }
+
//----------------- Model management APIs --------------------------------//
@Override
@@ -1378,6 +1407,7 @@ public class VoiceInteractionManagerService extends SystemService {
synchronized (this) {
pw.println("VOICE INTERACTION MANAGER (dumpsys voiceinteraction)");
pw.println(" mEnableService: " + mEnableService);
+ pw.println(" mTemporarilyDisabled: " + mTemporarilyDisabled);
pw.println(" mCurUser: " + mCurUser);
pw.println(" mCurUserUnlocked: " + mCurUserUnlocked);
pw.println(" mCurUserSupported: " + mCurUserSupported);
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceShellCommand.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceShellCommand.java
index 3f4ddb6846ab..6c355a3b4b30 100644
--- a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceShellCommand.java
+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceShellCommand.java
@@ -52,6 +52,8 @@ final class VoiceInteractionManagerServiceShellCommand extends ShellCommand {
return requestShow(pw);
case "hide":
return requestHide(pw);
+ case "disable":
+ return requestDisable(pw);
default:
return handleDefaultCommands(cmd);
}
@@ -69,6 +71,8 @@ final class VoiceInteractionManagerServiceShellCommand extends ShellCommand {
pw.println("");
pw.println(" hide");
pw.println(" Hides the current session");
+ pw.println(" disable [true|false]");
+ pw.println(" Temporarily disable (when true) service");
pw.println("");
}
}
@@ -127,6 +131,17 @@ final class VoiceInteractionManagerServiceShellCommand extends ShellCommand {
return 0;
}
+ private int requestDisable(PrintWriter pw) {
+ boolean disabled = Boolean.parseBoolean(getNextArgRequired());
+ Slog.i(TAG, "requestDisable(): " + disabled);
+ try {
+ mService.setDisabled(disabled);
+ } catch (Exception e) {
+ return handleError(pw, "requestDisable()", e);
+ }
+ return 0;
+ }
+
private static int handleError(PrintWriter pw, String message, Exception e) {
Slog.e(TAG, "error calling " + message, e);
pw.printf("Error calling %s: %s\n", message, e);
diff --git a/telephony/common/com/android/internal/telephony/CarrierAppUtils.java b/telephony/common/com/android/internal/telephony/CarrierAppUtils.java
index b3d7c0d36763..4606fb4b631c 100644
--- a/telephony/common/com/android/internal/telephony/CarrierAppUtils.java
+++ b/telephony/common/com/android/internal/telephony/CarrierAppUtils.java
@@ -21,7 +21,6 @@ import android.content.ContentResolver;
import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
-import android.content.res.Resources;
import android.os.SystemConfigManager;
import android.os.UserHandle;
import android.permission.PermissionManager;
@@ -30,9 +29,7 @@ import android.telephony.TelephonyManager;
import android.util.ArrayMap;
import android.util.Log;
-import com.android.internal.R;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.telephony.util.ArrayUtils;
import java.util.ArrayList;
import java.util.List;
@@ -162,12 +159,9 @@ public final class CarrierAppUtils {
try {
for (ApplicationInfo ai : candidates) {
String packageName = ai.packageName;
- String[] restrictedCarrierApps = Resources.getSystem().getStringArray(
- R.array.config_restrictedPreinstalledCarrierApps);
boolean hasPrivileges = telephonyManager != null
&& telephonyManager.checkCarrierPrivilegesForPackageAnyPhone(packageName)
- == TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS
- && !ArrayUtils.contains(restrictedCarrierApps, packageName);
+ == TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS;
// add hiddenUntilInstalled flag for carrier apps and associated apps
packageManager.setSystemAppState(
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index 87330d66ab84..a85bd060d65e 100755
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -4241,8 +4241,8 @@ public class CarrierConfigManager {
"GPRS:24,24", "EDGE:70,18", "UMTS:115,115", "CDMA-IS95A:14,14", "CDMA-IS95B:14,14",
"1xRTT:30,30", "EvDo-rev.0:750,48", "EvDo-rev.A:950,550", "HSDPA:4300,620",
"HSUPA:4300,1800", "HSPA:4300,1800", "EvDo-rev.B:1500,550", "eHRPD:750,48",
- "HSPAP:13000,3400", "TD-SCDMA:115,115", "LTE:30000,15000", "NR_NSA:47000,15000",
- "NR_NSA_MMWAVE:145000,15000", "NR_SA:145000,15000"});
+ "HSPAP:13000,3400", "TD-SCDMA:115,115", "LTE:30000,15000", "NR_NSA:47000,18000",
+ "NR_NSA_MMWAVE:145000,60000", "NR_SA:145000,60000"});
sDefaults.putBoolean(KEY_BANDWIDTH_NR_NSA_USE_LTE_VALUE_FOR_UPSTREAM_BOOL, false);
sDefaults.putString(KEY_WCDMA_DEFAULT_SIGNAL_STRENGTH_MEASUREMENT_STRING, "rssi");
sDefaults.putBoolean(KEY_CONFIG_SHOW_ORIG_DIAL_STRING_FOR_CDMA_BOOL, false);
diff --git a/telephony/java/android/telephony/SmsCbMessage.java b/telephony/java/android/telephony/SmsCbMessage.java
index 752707e5a5dc..d366efe0d979 100644
--- a/telephony/java/android/telephony/SmsCbMessage.java
+++ b/telephony/java/android/telephony/SmsCbMessage.java
@@ -594,6 +594,7 @@ public final class SmsCbMessage implements Parcelable {
SmsCbEtwsInfo etwsInfo = getEtwsWarningInfo();
if (etwsInfo != null) {
cv.put(CellBroadcasts.ETWS_WARNING_TYPE, etwsInfo.getWarningType());
+ cv.put(CellBroadcasts.ETWS_IS_PRIMARY, etwsInfo.isPrimary());
}
SmsCbCmasInfo cmasInfo = getCmasWarningInfo();
@@ -667,9 +668,12 @@ public final class SmsCbMessage implements Parcelable {
SmsCbEtwsInfo etwsInfo;
int etwsWarningTypeColumn = cursor.getColumnIndex(CellBroadcasts.ETWS_WARNING_TYPE);
- if (etwsWarningTypeColumn != -1 && !cursor.isNull(etwsWarningTypeColumn)) {
+ int etwsIsPrimaryColumn = cursor.getColumnIndex(CellBroadcasts.ETWS_IS_PRIMARY);
+ if (etwsWarningTypeColumn != -1 && !cursor.isNull(etwsWarningTypeColumn)
+ && etwsIsPrimaryColumn != -1 && !cursor.isNull(etwsIsPrimaryColumn)) {
int warningType = cursor.getInt(etwsWarningTypeColumn);
- etwsInfo = new SmsCbEtwsInfo(warningType, false, false, false, null);
+ boolean isPrimary = cursor.getInt(etwsIsPrimaryColumn) != 0;
+ etwsInfo = new SmsCbEtwsInfo(warningType, false, false, isPrimary, null);
} else {
etwsInfo = null;
}
diff --git a/tests/PackageWatchdog/src/com/android/server/PackageWatchdogTest.java b/tests/PackageWatchdog/src/com/android/server/PackageWatchdogTest.java
index d011dbbbe5db..ae93a81f274e 100644
--- a/tests/PackageWatchdog/src/com/android/server/PackageWatchdogTest.java
+++ b/tests/PackageWatchdog/src/com/android/server/PackageWatchdogTest.java
@@ -1113,6 +1113,7 @@ public class PackageWatchdogTest {
mTestLooper.dispatchAll();
List<Set> expectedSyncRequests = List.of(
+ Set.of(),
Set.of(APP_A),
Set.of(APP_A, APP_B),
Set.of(APP_A, APP_B, APP_C),
diff --git a/tests/RollbackTest/MultiUserRollbackTest.xml b/tests/RollbackTest/MultiUserRollbackTest.xml
index ba86c3ff6777..2f62af1856da 100644
--- a/tests/RollbackTest/MultiUserRollbackTest.xml
+++ b/tests/RollbackTest/MultiUserRollbackTest.xml
@@ -15,6 +15,12 @@
-->
<configuration description="Runs rollback tests for multiple users">
<option name="test-suite-tag" value="MultiUserRollbackTest" />
+ <target_preparer class="com.android.tradefed.targetprep.RunCommandTargetPreparer">
+ <option name="run-command" value="pm uninstall com.android.cts.install.lib.testapp.A" />
+ <option name="run-command" value="pm uninstall com.android.cts.install.lib.testapp.B" />
+ <option name="teardown-command" value="pm uninstall com.android.cts.install.lib.testapp.A" />
+ <option name="teardown-command" value="pm uninstall com.android.cts.install.lib.testapp.B" />
+ </target_preparer>
<test class="com.android.tradefed.testtype.HostTest" >
<option name="class" value="com.android.tests.rollback.host.MultiUserRollbackTest" />
</test>
diff --git a/tests/RollbackTest/MultiUserRollbackTest/src/com/android/tests/rollback/host/MultiUserRollbackTest.java b/tests/RollbackTest/MultiUserRollbackTest/src/com/android/tests/rollback/host/MultiUserRollbackTest.java
index a4c81d577522..42b886f0774f 100644
--- a/tests/RollbackTest/MultiUserRollbackTest/src/com/android/tests/rollback/host/MultiUserRollbackTest.java
+++ b/tests/RollbackTest/MultiUserRollbackTest/src/com/android/tests/rollback/host/MultiUserRollbackTest.java
@@ -40,23 +40,18 @@ public class MultiUserRollbackTest extends BaseHostJUnit4Test {
private static final long SWITCH_USER_COMPLETED_NUMBER_OF_POLLS = 60;
private static final long SWITCH_USER_COMPLETED_POLL_INTERVAL_IN_MILLIS = 1000;
- private void cleanUp() throws Exception {
- getDevice().executeShellCommand("pm rollback-app com.android.cts.install.lib.testapp.A");
- getDevice().executeShellCommand("pm uninstall com.android.cts.install.lib.testapp.A");
- }
-
@After
public void tearDown() throws Exception {
- cleanUp();
removeSecondaryUserIfNecessary();
+ runPhaseForUsers("cleanUp", mOriginalUserId);
}
@Before
public void setup() throws Exception {
- cleanUp();
mOriginalUserId = getDevice().getCurrentUser();
createAndStartSecondaryUser();
installPackage("RollbackTest.apk", "--user all");
+ runPhaseForUsers("cleanUp", mOriginalUserId);
}
@Test
diff --git a/tests/RollbackTest/NetworkStagedRollbackTest/src/com/android/tests/rollback/host/NetworkStagedRollbackTest.java b/tests/RollbackTest/NetworkStagedRollbackTest/src/com/android/tests/rollback/host/NetworkStagedRollbackTest.java
index 57c52f9c3021..61d7c763e8d7 100644
--- a/tests/RollbackTest/NetworkStagedRollbackTest/src/com/android/tests/rollback/host/NetworkStagedRollbackTest.java
+++ b/tests/RollbackTest/NetworkStagedRollbackTest/src/com/android/tests/rollback/host/NetworkStagedRollbackTest.java
@@ -59,12 +59,14 @@ public class NetworkStagedRollbackTest extends BaseHostJUnit4Test {
@Before
public void setUp() throws Exception {
+ runPhase("cleanUp");
mLogger.start(getDevice());
}
@After
public void tearDown() throws Exception {
mLogger.stop();
+ runPhase("cleanUp");
}
/**
diff --git a/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/MultiUserRollbackTest.java b/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/MultiUserRollbackTest.java
index 400bb04f0fab..8641f4d4013a 100644
--- a/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/MultiUserRollbackTest.java
+++ b/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/MultiUserRollbackTest.java
@@ -22,6 +22,7 @@ import static com.google.common.truth.Truth.assertThat;
import android.Manifest;
import android.content.rollback.RollbackInfo;
+import android.content.rollback.RollbackManager;
import com.android.cts.install.lib.Install;
import com.android.cts.install.lib.InstallUtils;
@@ -54,6 +55,17 @@ public class MultiUserRollbackTest {
}
@Test
+ public void cleanUp() {
+ RollbackManager rm = RollbackUtils.getRollbackManager();
+ rm.getAvailableRollbacks().stream().flatMap(info -> info.getPackages().stream())
+ .map(info -> info.getPackageName()).forEach(rm::expireRollbackForPackage);
+ rm.getRecentlyCommittedRollbacks().stream().flatMap(info -> info.getPackages().stream())
+ .map(info -> info.getPackageName()).forEach(rm::expireRollbackForPackage);
+ assertThat(rm.getAvailableRollbacks()).isEmpty();
+ assertThat(rm.getRecentlyCommittedRollbacks()).isEmpty();
+ }
+
+ @Test
public void testBasic() throws Exception {
new RollbackTest().testBasic();
}
diff --git a/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/NetworkStagedRollbackTest.java b/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/NetworkStagedRollbackTest.java
index 8fb59c7c3e2c..42b0c608822e 100644
--- a/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/NetworkStagedRollbackTest.java
+++ b/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/NetworkStagedRollbackTest.java
@@ -19,6 +19,8 @@ package com.android.tests.rollback;
import static com.android.cts.rollback.lib.RollbackInfoSubject.assertThat;
import static com.android.cts.rollback.lib.RollbackUtils.getUniqueRollbackInfoForPackage;
+import static com.google.common.truth.Truth.assertThat;
+
import android.Manifest;
import android.content.ComponentName;
import android.content.Intent;
@@ -91,14 +93,23 @@ public class NetworkStagedRollbackTest {
}
@Test
+ public void cleanUp() {
+ RollbackManager rm = RollbackUtils.getRollbackManager();
+ rm.getAvailableRollbacks().stream().flatMap(info -> info.getPackages().stream())
+ .map(info -> info.getPackageName()).forEach(rm::expireRollbackForPackage);
+ rm.getRecentlyCommittedRollbacks().stream().flatMap(info -> info.getPackages().stream())
+ .map(info -> info.getPackageName()).forEach(rm::expireRollbackForPackage);
+ assertThat(rm.getAvailableRollbacks()).isEmpty();
+ assertThat(rm.getRecentlyCommittedRollbacks()).isEmpty();
+ uninstallNetworkStackPackage();
+ }
+
+ @Test
public void testNetworkFailedRollback_Phase1() throws Exception {
// Remove available rollbacks and uninstall NetworkStack on /data/
RollbackManager rm = RollbackUtils.getRollbackManager();
String networkStack = getNetworkStackPackageName();
- rm.expireRollbackForPackage(networkStack);
- uninstallNetworkStackPackage();
-
assertThat(getUniqueRollbackInfoForPackage(rm.getAvailableRollbacks(),
networkStack)).isNull();
@@ -153,9 +164,6 @@ public class NetworkStagedRollbackTest {
RollbackManager rm = RollbackUtils.getRollbackManager();
String networkStack = getNetworkStackPackageName();
- rm.expireRollbackForPackage(networkStack);
- uninstallNetworkStackPackage();
-
assertThat(getUniqueRollbackInfoForPackage(rm.getAvailableRollbacks(),
networkStack)).isNull();
diff --git a/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/RollbackTest.java b/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/RollbackTest.java
index 48b5bed609d1..dd08771b220d 100644
--- a/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/RollbackTest.java
+++ b/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/RollbackTest.java
@@ -48,6 +48,8 @@ import com.android.cts.rollback.lib.Rollback;
import com.android.cts.rollback.lib.RollbackBroadcastReceiver;
import com.android.cts.rollback.lib.RollbackUtils;
+import org.junit.After;
+import org.junit.Before;
import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -81,6 +83,21 @@ public class RollbackTest {
pri -> packageName.equals(pri.getPackageName())));
}
+ @Before
+ @After
+ public void cleanUp() {
+ try {
+ InstallUtils.adoptShellPermissionIdentity(Manifest.permission.TEST_MANAGE_ROLLBACKS);
+ RollbackManager rm = RollbackUtils.getRollbackManager();
+ rm.getAvailableRollbacks().stream().flatMap(info -> info.getPackages().stream())
+ .map(info -> info.getPackageName()).forEach(rm::expireRollbackForPackage);
+ rm.getRecentlyCommittedRollbacks().stream().flatMap(info -> info.getPackages().stream())
+ .map(info -> info.getPackageName()).forEach(rm::expireRollbackForPackage);
+ } finally {
+ InstallUtils.dropShellPermissionIdentity();
+ }
+ }
+
/**
* Test basic rollbacks.
*/
diff --git a/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/StagedRollbackTest.java b/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/StagedRollbackTest.java
index 6c9ffe2a7fac..00bd4cf388ce 100644
--- a/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/StagedRollbackTest.java
+++ b/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/StagedRollbackTest.java
@@ -360,7 +360,10 @@ public class StagedRollbackTest {
RollbackManager rm = RollbackUtils.getRollbackManager();
rm.getAvailableRollbacks().stream().flatMap(info -> info.getPackages().stream())
.map(info -> info.getPackageName()).forEach(rm::expireRollbackForPackage);
- assertThat(RollbackUtils.getRollbackManager().getAvailableRollbacks()).isEmpty();
+ rm.getRecentlyCommittedRollbacks().stream().flatMap(info -> info.getPackages().stream())
+ .map(info -> info.getPackageName()).forEach(rm::expireRollbackForPackage);
+ assertThat(rm.getAvailableRollbacks()).isEmpty();
+ assertThat(rm.getRecentlyCommittedRollbacks()).isEmpty();
}
private static final String APK_IN_APEX_TESTAPEX_NAME = "com.android.apex.apkrollback.test";
diff --git a/tests/RollbackTest/StagedRollbackTest.xml b/tests/RollbackTest/StagedRollbackTest.xml
index 2750d3765c20..83fef8e0a04b 100644
--- a/tests/RollbackTest/StagedRollbackTest.xml
+++ b/tests/RollbackTest/StagedRollbackTest.xml
@@ -19,6 +19,12 @@
<option name="cleanup-apks" value="true" />
<option name="test-file-name" value="RollbackTest.apk" />
</target_preparer>
+ <target_preparer class="com.android.tradefed.targetprep.RunCommandTargetPreparer">
+ <option name="run-command" value="pm uninstall com.android.cts.install.lib.testapp.A" />
+ <option name="run-command" value="pm uninstall com.android.cts.install.lib.testapp.B" />
+ <option name="teardown-command" value="pm uninstall com.android.cts.install.lib.testapp.A" />
+ <option name="teardown-command" value="pm uninstall com.android.cts.install.lib.testapp.B" />
+ </target_preparer>
<test class="com.android.tradefed.testtype.HostTest" >
<option name="class" value="com.android.tests.rollback.host.StagedRollbackTest" />
</test>
diff --git a/tests/net/common/java/android/net/NetworkAgentConfigTest.kt b/tests/net/common/java/android/net/NetworkAgentConfigTest.kt
index de65ba24972b..a4d8353d1253 100644
--- a/tests/net/common/java/android/net/NetworkAgentConfigTest.kt
+++ b/tests/net/common/java/android/net/NetworkAgentConfigTest.kt
@@ -44,7 +44,7 @@ class NetworkAgentConfigTest {
setPartialConnectivityAcceptable(false)
setUnvalidatedConnectivityAcceptable(true)
}.build()
- assertParcelSane(config, 9)
+ assertParcelSane(config, 10)
}
@Test @IgnoreUpTo(Build.VERSION_CODES.Q)
diff --git a/tests/utils/hostutils/Android.bp b/tests/utils/hostutils/Android.bp
new file mode 100644
index 000000000000..c9ad70280aa6
--- /dev/null
+++ b/tests/utils/hostutils/Android.bp
@@ -0,0 +1,28 @@
+// 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.
+//
+
+java_library_host {
+ name: "frameworks-base-hostutils",
+
+ srcs: [
+ "src/**/*.java",
+ "src/**/*.kt",
+ ],
+
+ libs: [
+ "tradefed",
+ "junit",
+ ],
+}
diff --git a/tests/utils/hostutils/src/com/android/internal/util/test/SystemPreparer.java b/tests/utils/hostutils/src/com/android/internal/util/test/SystemPreparer.java
new file mode 100644
index 000000000000..6bd6985f9675
--- /dev/null
+++ b/tests/utils/hostutils/src/com/android/internal/util/test/SystemPreparer.java
@@ -0,0 +1,362 @@
+/*
+ * 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.internal.util.test;
+
+import static org.junit.Assert.assertTrue;
+
+import com.android.tradefed.device.DeviceNotAvailableException;
+import com.android.tradefed.device.ITestDevice;
+import com.android.tradefed.log.LogUtil;
+
+import org.junit.Assert;
+import org.junit.ClassRule;
+import org.junit.rules.ExternalResource;
+import org.junit.rules.TemporaryFolder;
+import org.junit.rules.TestRule;
+import org.junit.runner.Description;
+import org.junit.runners.model.Statement;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.ArrayList;
+
+import javax.annotation.Nullable;
+
+/**
+ * Allows pushing files onto the device and various options for rebooting. Useful for installing
+ * APKs/files to system partitions which otherwise wouldn't be easily changed.
+ *
+ * It's strongly recommended to pass in a {@link ClassRule} annotated {@link TestRuleDelegate} to
+ * do a full reboot at the end of a test to ensure the device is in a valid state, assuming the
+ * default {@link RebootStrategy#FULL} isn't used.
+ */
+public class SystemPreparer extends ExternalResource {
+ private static final long OVERLAY_ENABLE_TIMEOUT_MS = 30000;
+
+ // The paths of the files pushed onto the device through this rule.
+ private ArrayList<String> mPushedFiles = new ArrayList<>();
+
+ // The package names of packages installed through this rule.
+ private ArrayList<String> mInstalledPackages = new ArrayList<>();
+
+ private final TemporaryFolder mHostTempFolder;
+ private final DeviceProvider mDeviceProvider;
+ private final RebootStrategy mRebootStrategy;
+ private final TearDownRule mTearDownRule;
+
+ public SystemPreparer(TemporaryFolder hostTempFolder, DeviceProvider deviceProvider) {
+ this(hostTempFolder, RebootStrategy.FULL, null, deviceProvider);
+ }
+
+ public SystemPreparer(TemporaryFolder hostTempFolder, RebootStrategy rebootStrategy,
+ @Nullable TestRuleDelegate testRuleDelegate, DeviceProvider deviceProvider) {
+ mHostTempFolder = hostTempFolder;
+ mDeviceProvider = deviceProvider;
+ mRebootStrategy = rebootStrategy;
+ mTearDownRule = new TearDownRule(mDeviceProvider);
+ if (testRuleDelegate != null) {
+ testRuleDelegate.setDelegate(mTearDownRule);
+ }
+ }
+
+ /** Copies a file within the host test jar to a path on device. */
+ public SystemPreparer pushResourceFile(String filePath, String outputPath)
+ throws DeviceNotAvailableException, IOException {
+ final ITestDevice device = mDeviceProvider.getDevice();
+ remount();
+ assertTrue(device.pushFile(copyResourceToTemp(filePath), outputPath));
+ mPushedFiles.add(outputPath);
+ return this;
+ }
+
+ /** Copies a file directly from the host file system to a path on device. */
+ public SystemPreparer pushFile(File file, String outputPath)
+ throws DeviceNotAvailableException {
+ final ITestDevice device = mDeviceProvider.getDevice();
+ remount();
+ assertTrue(device.pushFile(file, outputPath));
+ mPushedFiles.add(outputPath);
+ return this;
+ }
+
+ /** Deletes the given path from the device */
+ public SystemPreparer deleteFile(String file) throws DeviceNotAvailableException {
+ final ITestDevice device = mDeviceProvider.getDevice();
+ remount();
+ device.deleteFile(file);
+ return this;
+ }
+
+ /** Installs an APK within the host test jar onto the device. */
+ public SystemPreparer installResourceApk(String resourcePath, String packageName)
+ throws DeviceNotAvailableException, IOException {
+ final ITestDevice device = mDeviceProvider.getDevice();
+ final File tmpFile = copyResourceToTemp(resourcePath);
+ final String result = device.installPackage(tmpFile, true /* reinstall */);
+ Assert.assertNull(result);
+ mInstalledPackages.add(packageName);
+ return this;
+ }
+
+ /** Sets the enable state of an overlay package. */
+ public SystemPreparer setOverlayEnabled(String packageName, boolean enabled)
+ throws DeviceNotAvailableException {
+ final ITestDevice device = mDeviceProvider.getDevice();
+ final String enable = enabled ? "enable" : "disable";
+
+ // Wait for the overlay to change its enabled state.
+ final long endMillis = System.currentTimeMillis() + OVERLAY_ENABLE_TIMEOUT_MS;
+ String result;
+ while (System.currentTimeMillis() <= endMillis) {
+ device.executeShellCommand(String.format("cmd overlay %s %s", enable, packageName));
+ result = device.executeShellCommand("cmd overlay dump isenabled "
+ + packageName);
+ if (((enabled) ? "true\n" : "false\n").equals(result)) {
+ return this;
+ }
+
+ try {
+ Thread.sleep(200);
+ } catch (InterruptedException ignore) {
+ }
+ }
+
+ throw new IllegalStateException(String.format("Failed to %s overlay %s:\n%s", enable,
+ packageName, device.executeShellCommand("cmd overlay list")));
+ }
+
+ /** Restarts the device and waits until after boot is completed. */
+ public SystemPreparer reboot() throws DeviceNotAvailableException {
+ ITestDevice device = mDeviceProvider.getDevice();
+ switch (mRebootStrategy) {
+ case FULL:
+ device.reboot();
+ break;
+ case UNTIL_ONLINE:
+ device.rebootUntilOnline();
+ break;
+ case USERSPACE:
+ device.rebootUserspace();
+ break;
+ case USERSPACE_UNTIL_ONLINE:
+ device.rebootUserspaceUntilOnline();
+ break;
+ case START_STOP:
+ device.executeShellCommand("stop");
+ device.executeShellCommand("start");
+ ITestDevice.RecoveryMode cachedRecoveryMode = device.getRecoveryMode();
+ device.setRecoveryMode(ITestDevice.RecoveryMode.ONLINE);
+
+ if (device.isEncryptionSupported()) {
+ if (device.isDeviceEncrypted()) {
+ LogUtil.CLog.e("Device is encrypted after userspace reboot!");
+ device.unlockDevice();
+ }
+ }
+
+ device.setRecoveryMode(cachedRecoveryMode);
+ device.waitForDeviceAvailable();
+ break;
+ }
+ return this;
+ }
+
+ public SystemPreparer remount() throws DeviceNotAvailableException {
+ mTearDownRule.remount();
+ return this;
+ }
+
+ /** Copies a file within the host test jar to a temporary file on the host machine. */
+ private File copyResourceToTemp(String resourcePath) throws IOException {
+ final File tempFile = mHostTempFolder.newFile();
+ final ClassLoader classLoader = getClass().getClassLoader();
+ try (InputStream assetIs = classLoader.getResource(resourcePath).openStream();
+ FileOutputStream assetOs = new FileOutputStream(tempFile)) {
+ if (assetIs == null) {
+ throw new IllegalStateException("Failed to find resource " + resourcePath);
+ }
+
+ int b;
+ while ((b = assetIs.read()) >= 0) {
+ assetOs.write(b);
+ }
+ }
+
+ return tempFile;
+ }
+
+ /** Removes installed packages and files that were pushed to the device. */
+ @Override
+ protected void after() {
+ final ITestDevice device = mDeviceProvider.getDevice();
+ try {
+ remount();
+ for (final String file : mPushedFiles) {
+ device.deleteFile(file);
+ }
+ for (final String packageName : mInstalledPackages) {
+ device.uninstallPackage(packageName);
+ }
+ reboot();
+ } catch (DeviceNotAvailableException e) {
+ Assert.fail(e.toString());
+ }
+ }
+
+ /**
+ * A hacky workaround since {@link org.junit.AfterClass} and {@link ClassRule} require static
+ * members. Will defer assignment of the actual {@link TestRule} to execute until after any
+ * test case has been run.
+ *
+ * In effect, this makes the {@link ITestDevice} to be accessible after all test cases have
+ * been executed, allowing {@link ITestDevice#reboot()} to be used to fully restore the device.
+ */
+ public static class TestRuleDelegate implements TestRule {
+
+ private boolean mThrowOnNull;
+
+ @Nullable
+ private TestRule mTestRule;
+
+ public TestRuleDelegate(boolean throwOnNull) {
+ mThrowOnNull = throwOnNull;
+ }
+
+ public void setDelegate(TestRule testRule) {
+ mTestRule = testRule;
+ }
+
+ @Override
+ public Statement apply(Statement base, Description description) {
+ if (mTestRule == null) {
+ if (mThrowOnNull) {
+ throw new IllegalStateException("TestRule delegate was not set");
+ } else {
+ return new Statement() {
+ @Override
+ public void evaluate() throws Throwable {
+ base.evaluate();
+ }
+ };
+ }
+ }
+
+ Statement statement = mTestRule.apply(base, description);
+ mTestRule = null;
+ return statement;
+ }
+ }
+
+ /**
+ * Forces a full reboot at the end of the test class to restore any device state.
+ */
+ private static class TearDownRule extends ExternalResource {
+
+ private DeviceProvider mDeviceProvider;
+ private boolean mInitialized;
+ private boolean mWasVerityEnabled;
+ private boolean mWasAdbRoot;
+ private boolean mIsVerityEnabled;
+
+ TearDownRule(DeviceProvider deviceProvider) {
+ mDeviceProvider = deviceProvider;
+ }
+
+ @Override
+ protected void before() {
+ // This method will never be run
+ }
+
+ @Override
+ protected void after() {
+ try {
+ initialize();
+ ITestDevice device = mDeviceProvider.getDevice();
+ if (mWasVerityEnabled != mIsVerityEnabled) {
+ device.executeShellCommand(
+ mWasVerityEnabled ? "enable-verity" : "disable-verity");
+ }
+ device.reboot();
+ if (!mWasAdbRoot) {
+ device.disableAdbRoot();
+ }
+ } catch (DeviceNotAvailableException e) {
+ Assert.fail(e.toString());
+ }
+ }
+
+ /**
+ * Remount is done inside this class so that the verity state can be tracked.
+ */
+ public void remount() throws DeviceNotAvailableException {
+ initialize();
+ ITestDevice device = mDeviceProvider.getDevice();
+ device.enableAdbRoot();
+ if (mIsVerityEnabled) {
+ mIsVerityEnabled = false;
+ device.executeShellCommand("disable-verity");
+ device.reboot();
+ }
+ device.executeShellCommand("remount");
+ device.waitForDeviceAvailable();
+ }
+
+ private void initialize() throws DeviceNotAvailableException {
+ if (mInitialized) {
+ return;
+ }
+ mInitialized = true;
+ ITestDevice device = mDeviceProvider.getDevice();
+ mWasAdbRoot = device.isAdbRoot();
+ device.enableAdbRoot();
+ String veritySystem = device.getProperty("partition.system.verified");
+ String verityVendor = device.getProperty("partition.vendor.verified");
+ mWasVerityEnabled = (veritySystem != null && !veritySystem.isEmpty())
+ || (verityVendor != null && !verityVendor.isEmpty());
+ mIsVerityEnabled = mWasVerityEnabled;
+ }
+ }
+
+ public interface DeviceProvider {
+ ITestDevice getDevice();
+ }
+
+ /**
+ * How to reboot the device. Ordered from slowest to fastest.
+ */
+ public enum RebootStrategy {
+ /** @see ITestDevice#reboot() */
+ FULL,
+
+ /** @see ITestDevice#rebootUntilOnline() () */
+ UNTIL_ONLINE,
+
+ /** @see ITestDevice#rebootUserspace() */
+ USERSPACE,
+
+ /** @see ITestDevice#rebootUserspaceUntilOnline() () */
+ USERSPACE_UNTIL_ONLINE,
+
+ /**
+ * Uses shell stop && start to "reboot" the device. May leave invalid state after each test.
+ * Whether this matters or not depends on what's being tested.
+ */
+ START_STOP
+ }
+}
diff --git a/tools/aapt2/Debug.cpp b/tools/aapt2/Debug.cpp
index 1eb7d95f381a..439f231193df 100644
--- a/tools/aapt2/Debug.cpp
+++ b/tools/aapt2/Debug.cpp
@@ -252,29 +252,6 @@ class ValueBodyPrinter : public ConstValueVisitor {
Printer* printer_;
};
-std::string OverlayablePoliciesToString(PolicyFlags policies) {
- std::string str;
-
- uint32_t remaining = policies;
- for (auto const& policy : kPolicyStringToFlag) {
- if ((policies & policy.second) != policy.second) {
- continue;
- }
- if (!str.empty()) {
- str.append("|");
- }
- str.append(policy.first.data());
- remaining &= ~policy.second;
- }
- if (remaining != 0) {
- if (!str.empty()) {
- str.append("|");
- }
- str.append(StringPrintf("0x%08x", remaining));
- }
- return !str.empty() ? str : "none";
-}
-
} // namespace
void Debug::PrintTable(const ResourceTable& table, const DebugPrintTableOptions& options,
@@ -575,7 +552,7 @@ void Debug::DumpOverlayable(const ResourceTable& table, text::Printer* printer)
overlayable_item.overlayable->name.c_str(),
overlayable_item.overlayable->actor.c_str());
const auto policy_subsection = StringPrintf(R"(policies="%s")",
- OverlayablePoliciesToString(overlayable_item.policies).c_str());
+ android::idmap2::policy::PoliciesToDebugString(overlayable_item.policies).c_str());
const auto value =
StringPrintf("%s/%s", to_string(type->type).data(), entry->name.c_str());
items.push_back(DumpOverlayableEntry{overlayable_section, policy_subsection, value});
diff --git a/wifi/Android.bp b/wifi/Android.bp
index 0df578f2216b..9c5b7b66f2a3 100644
--- a/wifi/Android.bp
+++ b/wifi/Android.bp
@@ -111,11 +111,6 @@ java_sdk_library {
":framework-wifi-util-lib-aidls",
],
- // TODO(b/155480189) - Remove naming_scheme once references have been resolved.
- // Temporary java_sdk_library component naming scheme to use to ease the transition from separate
- // modules to java_sdk_library.
- naming_scheme: "framework-modules",
-
jarjar_rules: ":wifi-jarjar-rules",
installable: true,
@@ -140,7 +135,6 @@ java_sdk_library {
permitted_packages: [
"android.hardware.wifi",
"android.net.wifi",
- "android.x.net.wifi",
// Created by jarjar rules.
"com.android.wifi.x",
],
diff --git a/wifi/java/android/net/wifi/WifiEnterpriseConfig.java b/wifi/java/android/net/wifi/WifiEnterpriseConfig.java
index 2e4e7f541ac2..7b86b084baab 100644
--- a/wifi/java/android/net/wifi/WifiEnterpriseConfig.java
+++ b/wifi/java/android/net/wifi/WifiEnterpriseConfig.java
@@ -1381,4 +1381,26 @@ public class WifiEnterpriseConfig implements Parcelable {
public String getWapiCertSuite() {
return getFieldValue(WAPI_CERT_SUITE_KEY);
}
+
+ /**
+ * Method determines whether the Enterprise configuration is insecure. An insecure
+ * configuration is one where EAP method requires a CA certification, i.e. PEAP, TLS, or
+ * TTLS, and any of the following conditions are met:
+ * - Both certificate and CA path are not configured.
+ * - Both alternative subject match and domain suffix match are not set.
+ *
+ * Note: this method does not exhaustively check security of the configuration - i.e. a return
+ * value of {@code false} is not a guarantee that the configuration is secure.
+ * @hide
+ */
+ public boolean isInsecure() {
+ if (mEapMethod != Eap.PEAP && mEapMethod != Eap.TLS && mEapMethod != Eap.TTLS) {
+ return false;
+ }
+ if (!mIsAppInstalledCaCert && TextUtils.isEmpty(getCaPath())) {
+ return true;
+ }
+ return TextUtils.isEmpty(getAltSubjectMatch()) && TextUtils.isEmpty(
+ getDomainSuffixMatch());
+ }
}
diff --git a/wifi/java/android/net/wifi/WifiInfo.java b/wifi/java/android/net/wifi/WifiInfo.java
index 70c5e72e4e0c..b841921355e9 100644
--- a/wifi/java/android/net/wifi/WifiInfo.java
+++ b/wifi/java/android/net/wifi/WifiInfo.java
@@ -632,7 +632,6 @@ public class WifiInfo implements Parcelable {
/**
* @hide
- * TODO: makes real freq boundaries
*/
public boolean is24GHz() {
return ScanResult.is24GHz(mFrequency);
@@ -640,7 +639,6 @@ public class WifiInfo implements Parcelable {
/**
* @hide
- * TODO: makes real freq boundaries
*/
@UnsupportedAppUsage
public boolean is5GHz() {
@@ -648,6 +646,13 @@ public class WifiInfo implements Parcelable {
}
/**
+ * @hide
+ */
+ public boolean is6GHz() {
+ return ScanResult.is6GHz(mFrequency);
+ }
+
+ /**
* Record the MAC address of the WLAN interface
* @param macAddress the MAC address in {@code XX:XX:XX:XX:XX:XX} form
* @hide
diff --git a/wifi/java/android/net/wifi/WifiNetworkSuggestion.java b/wifi/java/android/net/wifi/WifiNetworkSuggestion.java
index 8c494943200f..4d3a2c02c686 100644
--- a/wifi/java/android/net/wifi/WifiNetworkSuggestion.java
+++ b/wifi/java/android/net/wifi/WifiNetworkSuggestion.java
@@ -257,28 +257,38 @@ public final class WifiNetworkSuggestion implements Parcelable {
/**
* Set the associated enterprise configuration for this network. Needed for authenticating
- * to WPA2-EAP networks. See {@link WifiEnterpriseConfig} for description.
+ * to WPA2 enterprise networks. See {@link WifiEnterpriseConfig} for description.
*
* @param enterpriseConfig Instance of {@link WifiEnterpriseConfig}.
* @return Instance of {@link Builder} to enable chaining of the builder method.
+ * @throws IllegalArgumentException if configuration CA certificate or
+ * AltSubjectMatch/DomainSuffixMatch is not set.
*/
public @NonNull Builder setWpa2EnterpriseConfig(
@NonNull WifiEnterpriseConfig enterpriseConfig) {
checkNotNull(enterpriseConfig);
+ if (enterpriseConfig.isInsecure()) {
+ throw new IllegalArgumentException("Enterprise configuration is insecure");
+ }
mWpa2EnterpriseConfig = new WifiEnterpriseConfig(enterpriseConfig);
return this;
}
/**
* Set the associated enterprise configuration for this network. Needed for authenticating
- * to WPA3-SuiteB networks. See {@link WifiEnterpriseConfig} for description.
+ * to WPA3 enterprise networks. See {@link WifiEnterpriseConfig} for description.
*
* @param enterpriseConfig Instance of {@link WifiEnterpriseConfig}.
* @return Instance of {@link Builder} to enable chaining of the builder method.
+ * @throws IllegalArgumentException if configuration CA certificate or
+ * AltSubjectMatch/DomainSuffixMatch is not set.
*/
public @NonNull Builder setWpa3EnterpriseConfig(
@NonNull WifiEnterpriseConfig enterpriseConfig) {
checkNotNull(enterpriseConfig);
+ if (enterpriseConfig.isInsecure()) {
+ throw new IllegalArgumentException("Enterprise configuration is insecure");
+ }
mWpa3EnterpriseConfig = new WifiEnterpriseConfig(enterpriseConfig);
return this;
}
diff --git a/wifi/java/android/net/wifi/hotspot2/omadm/PpsMoParser.java b/wifi/java/android/net/wifi/hotspot2/omadm/PpsMoParser.java
index 68358abe188d..ae60ed47fd6a 100644
--- a/wifi/java/android/net/wifi/hotspot2/omadm/PpsMoParser.java
+++ b/wifi/java/android/net/wifi/hotspot2/omadm/PpsMoParser.java
@@ -937,7 +937,7 @@ public final class PpsMoParser {
*/
private static Credential parseCredential(PPSNode node) throws ParsingException {
if (node.isLeaf()) {
- throw new ParsingException("Leaf node not expected for HomeSP");
+ throw new ParsingException("Leaf node not expected for Credential");
}
Credential credential = new Credential();
@@ -1009,8 +1009,8 @@ public final class PpsMoParser {
parseEAPMethod(child, userCred);
break;
default:
- throw new ParsingException("Unknown node under UsernamPassword: " +
- child.getName());
+ throw new ParsingException("Unknown node under UsernamePassword: "
+ + child.getName());
}
}
return userCred;
@@ -1065,7 +1065,7 @@ public final class PpsMoParser {
private static Credential.CertificateCredential parseCertificateCredential(PPSNode node)
throws ParsingException {
if (node.isLeaf()) {
- throw new ParsingException("Leaf node not expected for DigitalCertificate");
+ throw new ParsingException("Leaf node not expected for CertificateCredential");
}
Credential.CertificateCredential certCred = new Credential.CertificateCredential();
@@ -1078,8 +1078,8 @@ public final class PpsMoParser {
certCred.setCertSha256Fingerprint(parseHexString(getPpsNodeValue(child)));
break;
default:
- throw new ParsingException("Unknown node under DigitalCertificate: " +
- child.getName());
+ throw new ParsingException("Unknown node under CertificateCredential: "
+ + child.getName());
}
}
return certCred;
@@ -1096,7 +1096,7 @@ public final class PpsMoParser {
private static Credential.SimCredential parseSimCredential(PPSNode node)
throws ParsingException {
if (node.isLeaf()) {
- throw new ParsingException("Leaf node not expected for SIM");
+ throw new ParsingException("Leaf node not expected for SimCredential");
}
Credential.SimCredential simCred = new Credential.SimCredential();
@@ -1109,7 +1109,8 @@ public final class PpsMoParser {
simCred.setEapType(parseInteger(getPpsNodeValue(child)));
break;
default:
- throw new ParsingException("Unknown node under SIM: " + child.getName());
+ throw new ParsingException("Unknown node under SimCredential: "
+ + child.getName());
}
}
return simCred;
@@ -1657,7 +1658,7 @@ public final class PpsMoParser {
private static void parseVendorAndroidExtension(PPSNode node, PasspointConfiguration config)
throws ParsingException {
if (node.isLeaf()) {
- throw new ParsingException("Leaf node not expected for Extension");
+ throw new ParsingException("Leaf node not expected for AndroidExtension");
}
for (PPSNode child : node.getChildren()) {
switch (child.getName()) {
@@ -1707,7 +1708,8 @@ public final class PpsMoParser {
*/
private static byte[] parseHexString(String str) throws ParsingException {
if ((str.length() & 1) == 1) {
- throw new ParsingException("Odd length hex string: " + str.length());
+ throw new ParsingException("Odd length hex string: " + str + ", length: "
+ + str.length());
}
byte[] result = new byte[str.length() / 2];
diff --git a/wifi/tests/src/android/net/wifi/WifiEnterpriseConfigTest.java b/wifi/tests/src/android/net/wifi/WifiEnterpriseConfigTest.java
index 320c187bbc2d..268645c85cae 100644
--- a/wifi/tests/src/android/net/wifi/WifiEnterpriseConfigTest.java
+++ b/wifi/tests/src/android/net/wifi/WifiEnterpriseConfigTest.java
@@ -47,6 +47,7 @@ public class WifiEnterpriseConfigTest {
public static final String KEYSTORE_URI = "keystore://";
public static final String CA_CERT_PREFIX = KEYSTORE_URI + Credentials.CA_CERTIFICATE;
public static final String KEYSTORES_URI = "keystores://";
+ private static final String TEST_DOMAIN_SUFFIX_MATCH = "domainSuffixMatch";
private WifiEnterpriseConfig mEnterpriseConfig;
@@ -540,4 +541,30 @@ public class WifiEnterpriseConfigTest {
mEnterpriseConfig.setEapMethod(Eap.UNAUTH_TLS);
assertEquals(null, getSupplicantPhase2Method());
}
+
+ @Test
+ public void testIsEnterpriseConfigSecure() {
+ WifiEnterpriseConfig baseConfig = new WifiEnterpriseConfig();
+ baseConfig.setEapMethod(Eap.PEAP);
+ baseConfig.setPhase2Method(Phase2.MSCHAPV2);
+ assertTrue(baseConfig.isInsecure());
+
+ WifiEnterpriseConfig noMatchConfig = new WifiEnterpriseConfig(baseConfig);
+ noMatchConfig.setCaCertificate(FakeKeys.CA_CERT0);
+ // Missing match is insecure.
+ assertTrue(noMatchConfig.isInsecure());
+
+ WifiEnterpriseConfig noCaConfig = new WifiEnterpriseConfig(baseConfig);
+ noCaConfig.setDomainSuffixMatch(TEST_DOMAIN_SUFFIX_MATCH);
+ // Missing CA certificate is insecure.
+ assertTrue(noCaConfig.isInsecure());
+
+ WifiEnterpriseConfig secureConfig = new WifiEnterpriseConfig();
+ secureConfig.setEapMethod(Eap.PEAP);
+ secureConfig.setPhase2Method(Phase2.MSCHAPV2);
+ secureConfig.setCaCertificate(FakeKeys.CA_CERT0);
+ secureConfig.setDomainSuffixMatch(TEST_DOMAIN_SUFFIX_MATCH);
+ assertFalse(secureConfig.isInsecure());
+ }
+
}
diff --git a/wifi/tests/src/android/net/wifi/WifiNetworkSuggestionTest.java b/wifi/tests/src/android/net/wifi/WifiNetworkSuggestionTest.java
index d1d1c6165dbd..16b4ad08a830 100644
--- a/wifi/tests/src/android/net/wifi/WifiNetworkSuggestionTest.java
+++ b/wifi/tests/src/android/net/wifi/WifiNetworkSuggestionTest.java
@@ -38,6 +38,7 @@ public class WifiNetworkSuggestionTest {
private static final String TEST_PRESHARED_KEY = "Test123";
private static final String TEST_FQDN = "fqdn";
private static final String TEST_WAPI_CERT_SUITE = "suite";
+ private static final String TEST_DOMAIN_SUFFIX_MATCH = "domainSuffixMatch";
/**
* Validate correctness of WifiNetworkSuggestion object created by
@@ -208,6 +209,8 @@ public class WifiNetworkSuggestionTest {
WifiEnterpriseConfig enterpriseConfig = new WifiEnterpriseConfig();
enterpriseConfig.setEapMethod(WifiEnterpriseConfig.Eap.TLS);
enterpriseConfig.setPhase2Method(WifiEnterpriseConfig.Phase2.GTC);
+ enterpriseConfig.setCaCertificate(FakeKeys.CA_CERT0);
+ enterpriseConfig.setDomainSuffixMatch(TEST_DOMAIN_SUFFIX_MATCH);
WifiNetworkSuggestion suggestion = new WifiNetworkSuggestion.Builder()
.setSsid(TEST_SSID)
@@ -230,6 +233,40 @@ public class WifiNetworkSuggestionTest {
}
/**
+ * Ensure create enterprise suggestion requires CA, when CA certificate is missing, will throw
+ * an exception.
+ */
+ @Test (expected = IllegalArgumentException.class)
+ public void testWifiNetworkSuggestionBuilderForEapNetworkWithoutCa() {
+ WifiEnterpriseConfig enterpriseConfig = new WifiEnterpriseConfig();
+ enterpriseConfig.setEapMethod(WifiEnterpriseConfig.Eap.TLS);
+ enterpriseConfig.setPhase2Method(WifiEnterpriseConfig.Phase2.GTC);
+ enterpriseConfig.setDomainSuffixMatch(TEST_DOMAIN_SUFFIX_MATCH);
+
+ WifiNetworkSuggestion suggestion = new WifiNetworkSuggestion.Builder()
+ .setSsid(TEST_SSID)
+ .setWpa2EnterpriseConfig(enterpriseConfig)
+ .build();
+ }
+
+ /**
+ * Ensure create enterprise suggestion requires CA, when both domain suffix and alt subject
+ * match are missing, will throw an exception.
+ */
+ @Test (expected = IllegalArgumentException.class)
+ public void testWifiNetworkSuggestionBuilderForEapNetworkWithoutMatch() {
+ WifiEnterpriseConfig enterpriseConfig = new WifiEnterpriseConfig();
+ enterpriseConfig.setEapMethod(WifiEnterpriseConfig.Eap.TLS);
+ enterpriseConfig.setPhase2Method(WifiEnterpriseConfig.Phase2.GTC);
+ enterpriseConfig.setCaCertificate(FakeKeys.CA_CERT0);
+
+ WifiNetworkSuggestion suggestion = new WifiNetworkSuggestion.Builder()
+ .setSsid(TEST_SSID)
+ .setWpa3EnterpriseConfig(enterpriseConfig)
+ .build();
+ }
+
+ /**
* Validate correctness of WifiNetworkSuggestion object created by
* {@link WifiNetworkSuggestion.Builder#build()} for WAPI-PSK network.
*/