summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Android.bp1
-rw-r--r--Android.mk17
-rwxr-xr-xapi/current.txt52
-rw-r--r--api/system-current.txt10
-rw-r--r--cmds/statsd/Android.bp22
-rw-r--r--cmds/statsd/Android.mk22
-rw-r--r--cmds/statsd/src/atoms.proto104
-rw-r--r--cmds/statsd/src/external/StatsPullerManager.cpp29
-rw-r--r--cmds/statsd/src/logd/LogEvent.cpp65
-rw-r--r--cmds/statsd/src/logd/LogEvent.h3
-rw-r--r--cmds/statsd/src/metrics/GaugeMetricProducer.cpp19
-rw-r--r--cmds/statsd/src/metrics/GaugeMetricProducer.h1
-rw-r--r--cmds/statsd/tests/LogEvent_test.cpp85
-rw-r--r--cmds/statsd/tests/e2e/GaugeMetric_e2e_pull_test.cpp27
-rw-r--r--cmds/statsd/tests/metrics/GaugeMetricProducer_test.cpp108
-rw-r--r--config/boot-image-profile.txt3
-rw-r--r--core/java/android/accessibilityservice/AccessibilityService.java10
-rw-r--r--core/java/android/accounts/Account.java37
-rw-r--r--core/java/android/app/Activity.java2
-rw-r--r--core/java/android/app/INotificationManager.aidl5
-rw-r--r--core/java/android/app/NotificationManager.java128
-rw-r--r--core/java/android/app/admin/DeviceAdminInfo.java37
-rw-r--r--core/java/android/app/assist/AssistStructure.java13
-rw-r--r--core/java/android/appwidget/AppWidgetProviderInfo.java2
-rw-r--r--core/java/android/content/pm/PackageManager.java7
-rw-r--r--core/java/android/inputmethodservice/AbstractInputMethodService.java8
-rw-r--r--core/java/android/inputmethodservice/InputMethodService.java115
-rw-r--r--core/java/android/os/Process.java43
-rw-r--r--core/java/android/os/StatsLogEventWrapper.java9
-rw-r--r--core/java/android/os/ZygoteProcess.java42
-rw-r--r--core/java/android/preference/SeekBarVolumizer.java2
-rw-r--r--core/java/android/service/autofill/CharSequenceTransformation.java2
-rw-r--r--core/java/android/service/notification/NotificationAssistantService.java3
-rw-r--r--core/java/android/service/notification/NotificationListenerService.java4
-rw-r--r--core/java/android/service/notification/StatusBarNotification.java16
-rw-r--r--core/java/android/text/FontConfig.java9
-rw-r--r--core/java/android/text/Hyphenator.java138
-rw-r--r--core/java/android/text/StaticLayout.java12
-rw-r--r--core/java/android/text/TextLine.java9
-rw-r--r--core/java/android/transition/Fade.java2
-rw-r--r--core/java/android/transition/Slide.java2
-rw-r--r--core/java/android/transition/Visibility.java6
-rw-r--r--core/java/android/util/TypedValue.java4
-rw-r--r--core/java/android/view/SurfaceView.java3
-rw-r--r--core/java/android/view/View.java15
-rw-r--r--core/java/android/view/ViewRootImpl.java91
-rw-r--r--core/java/android/view/autofill/AutofillId.java34
-rw-r--r--core/java/android/view/autofill/AutofillManager.java28
-rw-r--r--core/java/android/view/inputmethod/InputMethodManager.java324
-rw-r--r--core/java/android/widget/TextView.java18
-rw-r--r--core/java/com/android/internal/app/procstats/AssociationState.java41
-rw-r--r--core/java/com/android/internal/app/procstats/DumpUtils.java46
-rw-r--r--core/java/com/android/internal/app/procstats/ProcessState.java40
-rw-r--r--core/java/com/android/internal/app/procstats/ProcessStats.java6
-rw-r--r--core/java/com/android/internal/app/procstats/ServiceState.java58
-rw-r--r--core/java/com/android/internal/inputmethod/IInputMethodPrivilegedOperations.aidl11
-rw-r--r--core/java/com/android/internal/inputmethod/InputMethodPrivilegedOperations.java365
-rw-r--r--core/java/com/android/internal/inputmethod/InputMethodPrivilegedOperationsRegistry.java116
-rw-r--r--core/java/com/android/internal/os/ZygoteConnection.java12
-rw-r--r--core/java/com/android/internal/view/IInputConnectionWrapper.java9
-rw-r--r--core/java/com/android/internal/view/IInputMethodClient.aidl1
-rw-r--r--core/java/com/android/internal/view/IInputMethodManager.aidl10
-rw-r--r--core/java/com/android/internal/view/InputBindResult.java14
-rw-r--r--core/java/com/android/internal/view/InputConnectionWrapper.java13
-rw-r--r--core/java/com/android/server/AppWidgetBackupBridge.java4
-rwxr-xr-xcore/jni/android/graphics/Bitmap.cpp4
-rw-r--r--core/jni/android_media_AudioSystem.cpp120
-rw-r--r--core/jni/android_view_ThreadedRenderer.cpp3
-rw-r--r--core/proto/android/service/procstats.proto149
-rw-r--r--core/proto/android/service/procstats_enum.proto78
-rw-r--r--core/res/res/values-af/strings.xml3
-rw-r--r--core/res/res/values-am/strings.xml3
-rw-r--r--core/res/res/values-ar/strings.xml3
-rw-r--r--core/res/res/values-as/strings.xml3
-rw-r--r--core/res/res/values-az/strings.xml3
-rw-r--r--core/res/res/values-b+sr+Latn/strings.xml3
-rw-r--r--core/res/res/values-be/strings.xml3
-rw-r--r--core/res/res/values-bg/strings.xml3
-rw-r--r--core/res/res/values-bn/strings.xml3
-rw-r--r--core/res/res/values-bs/strings.xml3
-rw-r--r--core/res/res/values-ca/strings.xml5
-rw-r--r--core/res/res/values-cs/strings.xml3
-rw-r--r--core/res/res/values-da/strings.xml15
-rw-r--r--core/res/res/values-de/strings.xml3
-rw-r--r--core/res/res/values-el/strings.xml3
-rw-r--r--core/res/res/values-en-rAU/strings.xml3
-rw-r--r--core/res/res/values-en-rCA/strings.xml3
-rw-r--r--core/res/res/values-en-rGB/strings.xml3
-rw-r--r--core/res/res/values-en-rIN/strings.xml3
-rw-r--r--core/res/res/values-en-rXC/strings.xml3
-rw-r--r--core/res/res/values-es-rUS/strings.xml3
-rw-r--r--core/res/res/values-es/strings.xml3
-rw-r--r--core/res/res/values-et/strings.xml3
-rw-r--r--core/res/res/values-eu/strings.xml3
-rw-r--r--core/res/res/values-fa/strings.xml3
-rw-r--r--core/res/res/values-fi/strings.xml3
-rw-r--r--core/res/res/values-fr-rCA/strings.xml5
-rw-r--r--core/res/res/values-fr/strings.xml3
-rw-r--r--core/res/res/values-gl/strings.xml7
-rw-r--r--core/res/res/values-gu/strings.xml3
-rw-r--r--core/res/res/values-hi/strings.xml78
-rw-r--r--core/res/res/values-hr/strings.xml3
-rw-r--r--core/res/res/values-hu/strings.xml3
-rw-r--r--core/res/res/values-hy/strings.xml3
-rw-r--r--core/res/res/values-in/strings.xml3
-rw-r--r--core/res/res/values-is/strings.xml3
-rw-r--r--core/res/res/values-it/strings.xml7
-rw-r--r--core/res/res/values-iw/strings.xml3
-rw-r--r--core/res/res/values-ja/strings.xml3
-rw-r--r--core/res/res/values-ka/strings.xml3
-rw-r--r--core/res/res/values-kk/strings.xml3
-rw-r--r--core/res/res/values-km/strings.xml3
-rw-r--r--core/res/res/values-kn/strings.xml3
-rw-r--r--core/res/res/values-ko/strings.xml5
-rw-r--r--core/res/res/values-ky/strings.xml3
-rw-r--r--core/res/res/values-lo/strings.xml3
-rw-r--r--core/res/res/values-lt/strings.xml3
-rw-r--r--core/res/res/values-lv/strings.xml3
-rw-r--r--core/res/res/values-mcc310-mnc030-pt-rBR/strings.xml4
-rw-r--r--core/res/res/values-mcc310-mnc030-pt/strings.xml4
-rw-r--r--core/res/res/values-mcc310-mnc170-pt-rBR/strings.xml4
-rw-r--r--core/res/res/values-mcc310-mnc170-pt/strings.xml4
-rw-r--r--core/res/res/values-mcc310-mnc280-pt-rBR/strings.xml4
-rw-r--r--core/res/res/values-mcc310-mnc280-pt/strings.xml4
-rw-r--r--core/res/res/values-mcc310-mnc380-pt-rBR/strings.xml4
-rw-r--r--core/res/res/values-mcc310-mnc380-pt/strings.xml4
-rw-r--r--core/res/res/values-mcc310-mnc410-pt-rBR/strings.xml4
-rw-r--r--core/res/res/values-mcc310-mnc410-pt/strings.xml4
-rw-r--r--core/res/res/values-mcc310-mnc560-pt-rBR/strings.xml4
-rw-r--r--core/res/res/values-mcc310-mnc560-pt/strings.xml4
-rw-r--r--core/res/res/values-mcc310-mnc950-pt-rBR/strings.xml4
-rw-r--r--core/res/res/values-mcc310-mnc950-pt/strings.xml4
-rw-r--r--core/res/res/values-mcc311-mnc180-pt-rBR/strings.xml4
-rw-r--r--core/res/res/values-mcc311-mnc180-pt/strings.xml4
-rw-r--r--core/res/res/values-mk/strings.xml3
-rw-r--r--core/res/res/values-ml/strings.xml3
-rw-r--r--core/res/res/values-mn/strings.xml3
-rw-r--r--core/res/res/values-mr/strings.xml3
-rw-r--r--core/res/res/values-ms/strings.xml3
-rw-r--r--core/res/res/values-my/strings.xml3
-rw-r--r--core/res/res/values-nb/strings.xml3
-rw-r--r--core/res/res/values-ne/strings.xml3
-rw-r--r--core/res/res/values-nl/strings.xml3
-rw-r--r--core/res/res/values-or/strings.xml3
-rw-r--r--core/res/res/values-pa/strings.xml3
-rw-r--r--core/res/res/values-pl/strings.xml3
-rw-r--r--core/res/res/values-pt-rBR/strings.xml73
-rw-r--r--core/res/res/values-pt-rPT/strings.xml3
-rw-r--r--core/res/res/values-pt/strings.xml73
-rw-r--r--core/res/res/values-ro/strings.xml3
-rw-r--r--core/res/res/values-ru/strings.xml3
-rw-r--r--core/res/res/values-si/strings.xml5
-rw-r--r--core/res/res/values-sk/strings.xml3
-rw-r--r--core/res/res/values-sl/strings.xml3
-rw-r--r--core/res/res/values-sq/strings.xml5
-rw-r--r--core/res/res/values-sr/strings.xml3
-rw-r--r--core/res/res/values-sv/strings.xml3
-rw-r--r--core/res/res/values-sw/strings.xml5
-rw-r--r--core/res/res/values-ta/strings.xml5
-rw-r--r--core/res/res/values-te/strings.xml3
-rw-r--r--core/res/res/values-th/strings.xml5
-rw-r--r--core/res/res/values-tl/strings.xml3
-rw-r--r--core/res/res/values-tr/strings.xml3
-rw-r--r--core/res/res/values-uk/strings.xml3
-rw-r--r--core/res/res/values-ur/strings.xml3
-rw-r--r--core/res/res/values-uz/strings.xml5
-rw-r--r--core/res/res/values-vi/strings.xml3
-rw-r--r--core/res/res/values-watch/config.xml3
-rw-r--r--core/res/res/values-zh-rCN/strings.xml5
-rw-r--r--core/res/res/values-zh-rHK/strings.xml3
-rw-r--r--core/res/res/values-zh-rTW/strings.xml3
-rw-r--r--core/res/res/values-zu/strings.xml3
-rw-r--r--core/res/res/values/attrs.xml4
-rw-r--r--core/res/res/values/config.xml5
-rw-r--r--core/res/res/values/styles.xml6
-rw-r--r--core/tests/coretests/src/android/graphics/TypefaceSystemFallbackTest.java10
-rw-r--r--core/tests/coretests/src/android/text/FontFallbackSetup.java5
-rw-r--r--data/fonts/fonts.xml4
-rw-r--r--graphics/java/android/graphics/FontListParser.java9
-rw-r--r--graphics/java/android/graphics/Paint.java44
-rw-r--r--graphics/java/android/graphics/Typeface.java130
-rw-r--r--graphics/java/android/graphics/drawable/Icon.java3
-rw-r--r--graphics/java/android/graphics/fonts/Font.java87
-rw-r--r--graphics/java/android/graphics/fonts/FontFamily.java17
-rw-r--r--graphics/java/android/graphics/fonts/SystemFonts.java56
-rw-r--r--keystore/java/android/security/KeyChain.java82
-rw-r--r--libs/hwui/Android.bp4
-rw-r--r--libs/hwui/DeferredLayerUpdater.cpp1
-rw-r--r--libs/hwui/EglReadback.cpp95
-rw-r--r--libs/hwui/EglReadback.h50
-rw-r--r--libs/hwui/Layer.cpp3
-rw-r--r--libs/hwui/Layer.h13
-rw-r--r--libs/hwui/Readback.cpp287
-rw-r--r--libs/hwui/Readback.h22
-rw-r--r--libs/hwui/hwui/Bitmap.cpp2
-rw-r--r--libs/hwui/pipeline/skia/LayerDrawable.cpp33
-rw-r--r--libs/hwui/pipeline/skia/LayerDrawable.h2
-rw-r--r--libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp59
-rw-r--r--libs/hwui/pipeline/skia/SkiaOpenGLPipeline.h1
-rw-r--r--libs/hwui/pipeline/skia/SkiaOpenGLReadback.cpp147
-rw-r--r--libs/hwui/pipeline/skia/SkiaOpenGLReadback.h37
-rw-r--r--libs/hwui/pipeline/skia/SkiaVulkanPipeline.cpp5
-rw-r--r--libs/hwui/pipeline/skia/SkiaVulkanPipeline.h1
-rw-r--r--libs/hwui/pipeline/skia/SkiaVulkanReadback.h44
-rw-r--r--libs/hwui/renderthread/CanvasContext.cpp4
-rw-r--r--libs/hwui/renderthread/CanvasContext.h1
-rw-r--r--libs/hwui/renderthread/IRenderPipeline.h1
-rw-r--r--libs/hwui/renderthread/RenderProxy.cpp12
-rw-r--r--libs/hwui/renderthread/RenderProxy.h2
-rw-r--r--libs/hwui/renderthread/RenderThread.cpp16
-rw-r--r--libs/hwui/utils/TestWindowContext.cpp197
-rw-r--r--libs/hwui/utils/TestWindowContext.h64
-rw-r--r--location/java/android/location/LocationManager.java13
-rw-r--r--media/java/android/media/AudioAttributes.java5
-rw-r--r--media/java/android/media/AudioSystem.java4
-rw-r--r--media/java/android/media/MediaPlayer2.java16
-rw-r--r--media/java/android/media/MediaPlayer2Impl.java328
-rw-r--r--media/java/android/media/SubtitleData.java8
-rw-r--r--media/java/android/media/TimedMetaData.java8
-rw-r--r--media/java/android/media/TimedText.java10
-rw-r--r--media/jni/Android.bp4
-rw-r--r--media/jni/android_media_MediaPlayer2.cpp73
-rw-r--r--media/proto/Android.bp20
-rw-r--r--media/proto/jarjar-rules.txt2
-rw-r--r--media/proto/mediaplayer2.proto53
-rw-r--r--packages/DefaultContainerService/res/values-fr-rCA/strings.xml2
-rw-r--r--packages/DefaultContainerService/res/values-pt-rPT/strings.xml2
-rw-r--r--packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java1
-rw-r--r--packages/SettingsLib/HelpUtils/res/values-af/strings.xml21
-rw-r--r--packages/SettingsLib/HelpUtils/res/values-am/strings.xml21
-rw-r--r--packages/SettingsLib/HelpUtils/res/values-ar/strings.xml21
-rw-r--r--packages/SettingsLib/HelpUtils/res/values-as/strings.xml21
-rw-r--r--packages/SettingsLib/HelpUtils/res/values-az/strings.xml21
-rw-r--r--packages/SettingsLib/HelpUtils/res/values-b+sr+Latn/strings.xml21
-rw-r--r--packages/SettingsLib/HelpUtils/res/values-be/strings.xml21
-rw-r--r--packages/SettingsLib/HelpUtils/res/values-bg/strings.xml21
-rw-r--r--packages/SettingsLib/HelpUtils/res/values-bn/strings.xml21
-rw-r--r--packages/SettingsLib/HelpUtils/res/values-bs/strings.xml21
-rw-r--r--packages/SettingsLib/HelpUtils/res/values-ca/strings.xml21
-rw-r--r--packages/SettingsLib/HelpUtils/res/values-cs/strings.xml21
-rw-r--r--packages/SettingsLib/HelpUtils/res/values-da/strings.xml21
-rw-r--r--packages/SettingsLib/HelpUtils/res/values-de/strings.xml21
-rw-r--r--packages/SettingsLib/HelpUtils/res/values-el/strings.xml21
-rw-r--r--packages/SettingsLib/HelpUtils/res/values-en-rAU/strings.xml21
-rw-r--r--packages/SettingsLib/HelpUtils/res/values-en-rCA/strings.xml21
-rw-r--r--packages/SettingsLib/HelpUtils/res/values-en-rGB/strings.xml21
-rw-r--r--packages/SettingsLib/HelpUtils/res/values-en-rIN/strings.xml21
-rw-r--r--packages/SettingsLib/HelpUtils/res/values-en-rXC/strings.xml21
-rw-r--r--packages/SettingsLib/HelpUtils/res/values-es-rUS/strings.xml21
-rw-r--r--packages/SettingsLib/HelpUtils/res/values-es/strings.xml21
-rw-r--r--packages/SettingsLib/HelpUtils/res/values-et/strings.xml21
-rw-r--r--packages/SettingsLib/HelpUtils/res/values-eu/strings.xml21
-rw-r--r--packages/SettingsLib/HelpUtils/res/values-fa/strings.xml21
-rw-r--r--packages/SettingsLib/HelpUtils/res/values-fi/strings.xml21
-rw-r--r--packages/SettingsLib/HelpUtils/res/values-fr-rCA/strings.xml21
-rw-r--r--packages/SettingsLib/HelpUtils/res/values-fr/strings.xml21
-rw-r--r--packages/SettingsLib/HelpUtils/res/values-gl/strings.xml21
-rw-r--r--packages/SettingsLib/HelpUtils/res/values-gu/strings.xml21
-rw-r--r--packages/SettingsLib/HelpUtils/res/values-hr/strings.xml21
-rw-r--r--packages/SettingsLib/HelpUtils/res/values-hu/strings.xml21
-rw-r--r--packages/SettingsLib/HelpUtils/res/values-hy/strings.xml21
-rw-r--r--packages/SettingsLib/HelpUtils/res/values-in/strings.xml21
-rw-r--r--packages/SettingsLib/HelpUtils/res/values-is/strings.xml21
-rw-r--r--packages/SettingsLib/HelpUtils/res/values-it/strings.xml21
-rw-r--r--packages/SettingsLib/HelpUtils/res/values-iw/strings.xml21
-rw-r--r--packages/SettingsLib/HelpUtils/res/values-ja/strings.xml21
-rw-r--r--packages/SettingsLib/HelpUtils/res/values-ka/strings.xml21
-rw-r--r--packages/SettingsLib/HelpUtils/res/values-kk/strings.xml21
-rw-r--r--packages/SettingsLib/HelpUtils/res/values-km/strings.xml21
-rw-r--r--packages/SettingsLib/HelpUtils/res/values-kn/strings.xml21
-rw-r--r--packages/SettingsLib/HelpUtils/res/values-ko/strings.xml21
-rw-r--r--packages/SettingsLib/HelpUtils/res/values-ky/strings.xml21
-rw-r--r--packages/SettingsLib/HelpUtils/res/values-lo/strings.xml21
-rw-r--r--packages/SettingsLib/HelpUtils/res/values-lt/strings.xml21
-rw-r--r--packages/SettingsLib/HelpUtils/res/values-lv/strings.xml21
-rw-r--r--packages/SettingsLib/HelpUtils/res/values-mk/strings.xml21
-rw-r--r--packages/SettingsLib/HelpUtils/res/values-ml/strings.xml21
-rw-r--r--packages/SettingsLib/HelpUtils/res/values-mn/strings.xml21
-rw-r--r--packages/SettingsLib/HelpUtils/res/values-mr/strings.xml21
-rw-r--r--packages/SettingsLib/HelpUtils/res/values-ms/strings.xml21
-rw-r--r--packages/SettingsLib/HelpUtils/res/values-my/strings.xml21
-rw-r--r--packages/SettingsLib/HelpUtils/res/values-nb/strings.xml21
-rw-r--r--packages/SettingsLib/HelpUtils/res/values-ne/strings.xml21
-rw-r--r--packages/SettingsLib/HelpUtils/res/values-nl/strings.xml21
-rw-r--r--packages/SettingsLib/HelpUtils/res/values-or/strings.xml21
-rw-r--r--packages/SettingsLib/HelpUtils/res/values-pa/strings.xml21
-rw-r--r--packages/SettingsLib/HelpUtils/res/values-pl/strings.xml21
-rw-r--r--packages/SettingsLib/HelpUtils/res/values-pt-rBR/strings.xml21
-rw-r--r--packages/SettingsLib/HelpUtils/res/values-pt-rPT/strings.xml21
-rw-r--r--packages/SettingsLib/HelpUtils/res/values-pt/strings.xml21
-rw-r--r--packages/SettingsLib/HelpUtils/res/values-ro/strings.xml21
-rw-r--r--packages/SettingsLib/HelpUtils/res/values-ru/strings.xml21
-rw-r--r--packages/SettingsLib/HelpUtils/res/values-si/strings.xml21
-rw-r--r--packages/SettingsLib/HelpUtils/res/values-sk/strings.xml21
-rw-r--r--packages/SettingsLib/HelpUtils/res/values-sl/strings.xml21
-rw-r--r--packages/SettingsLib/HelpUtils/res/values-sq/strings.xml21
-rw-r--r--packages/SettingsLib/HelpUtils/res/values-sr/strings.xml21
-rw-r--r--packages/SettingsLib/HelpUtils/res/values-sv/strings.xml21
-rw-r--r--packages/SettingsLib/HelpUtils/res/values-sw/strings.xml21
-rw-r--r--packages/SettingsLib/HelpUtils/res/values-ta/strings.xml21
-rw-r--r--packages/SettingsLib/HelpUtils/res/values-te/strings.xml21
-rw-r--r--packages/SettingsLib/HelpUtils/res/values-th/strings.xml21
-rw-r--r--packages/SettingsLib/HelpUtils/res/values-tl/strings.xml21
-rw-r--r--packages/SettingsLib/HelpUtils/res/values-tr/strings.xml21
-rw-r--r--packages/SettingsLib/HelpUtils/res/values-uk/strings.xml21
-rw-r--r--packages/SettingsLib/HelpUtils/res/values-ur/strings.xml21
-rw-r--r--packages/SettingsLib/HelpUtils/res/values-uz/strings.xml21
-rw-r--r--packages/SettingsLib/HelpUtils/res/values-vi/strings.xml21
-rw-r--r--packages/SettingsLib/HelpUtils/res/values-zh-rCN/strings.xml21
-rw-r--r--packages/SettingsLib/HelpUtils/res/values-zh-rHK/strings.xml21
-rw-r--r--packages/SettingsLib/HelpUtils/res/values-zh-rTW/strings.xml21
-rw-r--r--packages/SettingsLib/HelpUtils/res/values-zu/strings.xml21
-rw-r--r--packages/SettingsLib/res/values-af/strings.xml1
-rw-r--r--packages/SettingsLib/res/values-am/strings.xml1
-rw-r--r--packages/SettingsLib/res/values-ar/strings.xml1
-rw-r--r--packages/SettingsLib/res/values-as/strings.xml1
-rw-r--r--packages/SettingsLib/res/values-az/strings.xml1
-rw-r--r--packages/SettingsLib/res/values-b+sr+Latn/strings.xml1
-rw-r--r--packages/SettingsLib/res/values-be/strings.xml1
-rw-r--r--packages/SettingsLib/res/values-bg/strings.xml1
-rw-r--r--packages/SettingsLib/res/values-bn/strings.xml1
-rw-r--r--packages/SettingsLib/res/values-bs/strings.xml1
-rw-r--r--packages/SettingsLib/res/values-ca/strings.xml1
-rw-r--r--packages/SettingsLib/res/values-cs/strings.xml1
-rw-r--r--packages/SettingsLib/res/values-da/strings.xml3
-rw-r--r--packages/SettingsLib/res/values-de/strings.xml1
-rw-r--r--packages/SettingsLib/res/values-el/strings.xml1
-rw-r--r--packages/SettingsLib/res/values-en-rAU/strings.xml1
-rw-r--r--packages/SettingsLib/res/values-en-rCA/strings.xml1
-rw-r--r--packages/SettingsLib/res/values-en-rGB/strings.xml1
-rw-r--r--packages/SettingsLib/res/values-en-rIN/strings.xml1
-rw-r--r--packages/SettingsLib/res/values-en-rXC/strings.xml1
-rw-r--r--packages/SettingsLib/res/values-es-rUS/strings.xml1
-rw-r--r--packages/SettingsLib/res/values-es/strings.xml5
-rw-r--r--packages/SettingsLib/res/values-et/strings.xml1
-rw-r--r--packages/SettingsLib/res/values-eu/strings.xml1
-rw-r--r--packages/SettingsLib/res/values-fa/strings.xml1
-rw-r--r--packages/SettingsLib/res/values-fi/strings.xml1
-rw-r--r--packages/SettingsLib/res/values-fr-rCA/strings.xml1
-rw-r--r--packages/SettingsLib/res/values-fr/strings.xml3
-rw-r--r--packages/SettingsLib/res/values-gl/strings.xml1
-rw-r--r--packages/SettingsLib/res/values-gu/strings.xml1
-rw-r--r--packages/SettingsLib/res/values-hi/strings.xml1
-rw-r--r--packages/SettingsLib/res/values-hr/strings.xml1
-rw-r--r--packages/SettingsLib/res/values-hu/strings.xml1
-rw-r--r--packages/SettingsLib/res/values-hy/strings.xml1
-rw-r--r--packages/SettingsLib/res/values-in/strings.xml3
-rw-r--r--packages/SettingsLib/res/values-is/strings.xml1
-rw-r--r--packages/SettingsLib/res/values-it/strings.xml1
-rw-r--r--packages/SettingsLib/res/values-iw/strings.xml1
-rw-r--r--packages/SettingsLib/res/values-ja/strings.xml1
-rw-r--r--packages/SettingsLib/res/values-ka/strings.xml1
-rw-r--r--packages/SettingsLib/res/values-kk/strings.xml1
-rw-r--r--packages/SettingsLib/res/values-km/strings.xml1
-rw-r--r--packages/SettingsLib/res/values-kn/strings.xml1
-rw-r--r--packages/SettingsLib/res/values-ko/strings.xml1
-rw-r--r--packages/SettingsLib/res/values-ky/strings.xml1
-rw-r--r--packages/SettingsLib/res/values-lo/strings.xml1
-rw-r--r--packages/SettingsLib/res/values-lt/strings.xml1
-rw-r--r--packages/SettingsLib/res/values-lv/strings.xml1
-rw-r--r--packages/SettingsLib/res/values-mk/strings.xml1
-rw-r--r--packages/SettingsLib/res/values-ml/strings.xml1
-rw-r--r--packages/SettingsLib/res/values-mn/strings.xml1
-rw-r--r--packages/SettingsLib/res/values-mr/strings.xml1
-rw-r--r--packages/SettingsLib/res/values-ms/strings.xml1
-rw-r--r--packages/SettingsLib/res/values-my/strings.xml1
-rw-r--r--packages/SettingsLib/res/values-nb/strings.xml1
-rw-r--r--packages/SettingsLib/res/values-ne/strings.xml1
-rw-r--r--packages/SettingsLib/res/values-nl/strings.xml1
-rw-r--r--packages/SettingsLib/res/values-or/strings.xml1
-rw-r--r--packages/SettingsLib/res/values-pa/strings.xml1
-rw-r--r--packages/SettingsLib/res/values-pl/strings.xml1
-rw-r--r--packages/SettingsLib/res/values-pt-rBR/strings.xml5
-rw-r--r--packages/SettingsLib/res/values-pt-rPT/strings.xml1
-rw-r--r--packages/SettingsLib/res/values-pt/strings.xml5
-rw-r--r--packages/SettingsLib/res/values-ro/strings.xml1
-rw-r--r--packages/SettingsLib/res/values-ru/strings.xml1
-rw-r--r--packages/SettingsLib/res/values-si/strings.xml1
-rw-r--r--packages/SettingsLib/res/values-sk/strings.xml1
-rw-r--r--packages/SettingsLib/res/values-sl/strings.xml1
-rw-r--r--packages/SettingsLib/res/values-sq/strings.xml1
-rw-r--r--packages/SettingsLib/res/values-sr/strings.xml1
-rw-r--r--packages/SettingsLib/res/values-sv/strings.xml1
-rw-r--r--packages/SettingsLib/res/values-sw/strings.xml1
-rw-r--r--packages/SettingsLib/res/values-ta/strings.xml1
-rw-r--r--packages/SettingsLib/res/values-te/strings.xml1
-rw-r--r--packages/SettingsLib/res/values-th/strings.xml1
-rw-r--r--packages/SettingsLib/res/values-tl/strings.xml1
-rw-r--r--packages/SettingsLib/res/values-tr/strings.xml1
-rw-r--r--packages/SettingsLib/res/values-uk/strings.xml1
-rw-r--r--packages/SettingsLib/res/values-ur/strings.xml1
-rw-r--r--packages/SettingsLib/res/values-uz/strings.xml1
-rw-r--r--packages/SettingsLib/res/values-vi/strings.xml1
-rw-r--r--packages/SettingsLib/res/values-zh-rCN/strings.xml1
-rw-r--r--packages/SettingsLib/res/values-zh-rHK/strings.xml1
-rw-r--r--packages/SettingsLib/res/values-zh-rTW/strings.xml1
-rw-r--r--packages/SettingsLib/res/values-zu/strings.xml1
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/bluetooth/MapProfile.java53
-rw-r--r--packages/SettingsProvider/src/com/android/providers/settings/GenerationRegistry.java1
-rw-r--r--packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java5
-rw-r--r--packages/SettingsProvider/src/com/android/providers/settings/SettingsState.java17
-rw-r--r--packages/SystemUI/res-keyguard/values-pt-rBR/strings.xml66
-rw-r--r--packages/SystemUI/res-keyguard/values-pt/strings.xml66
-rw-r--r--packages/SystemUI/res/layout/notification_info.xml1
-rw-r--r--packages/SystemUI/res/values-af/strings.xml11
-rw-r--r--packages/SystemUI/res/values-am/strings.xml11
-rw-r--r--packages/SystemUI/res/values-ar/strings.xml15
-rw-r--r--packages/SystemUI/res/values-as/strings.xml11
-rw-r--r--packages/SystemUI/res/values-az/strings.xml13
-rw-r--r--packages/SystemUI/res/values-b+sr+Latn/strings.xml12
-rw-r--r--packages/SystemUI/res/values-be/strings.xml13
-rw-r--r--packages/SystemUI/res/values-bg/strings.xml11
-rw-r--r--packages/SystemUI/res/values-bn/strings.xml11
-rw-r--r--packages/SystemUI/res/values-bs/strings.xml14
-rw-r--r--packages/SystemUI/res/values-ca/strings.xml11
-rw-r--r--packages/SystemUI/res/values-cs/strings.xml13
-rw-r--r--packages/SystemUI/res/values-da/strings.xml11
-rw-r--r--packages/SystemUI/res/values-de/strings.xml11
-rw-r--r--packages/SystemUI/res/values-el/strings.xml11
-rw-r--r--packages/SystemUI/res/values-es-rUS/strings.xml11
-rw-r--r--packages/SystemUI/res/values-es/strings.xml11
-rw-r--r--packages/SystemUI/res/values-et/strings.xml11
-rw-r--r--packages/SystemUI/res/values-eu/strings.xml11
-rw-r--r--packages/SystemUI/res/values-fa/strings.xml11
-rw-r--r--packages/SystemUI/res/values-fi/strings.xml11
-rw-r--r--packages/SystemUI/res/values-fr-rCA/strings.xml11
-rw-r--r--packages/SystemUI/res/values-fr/strings.xml13
-rw-r--r--packages/SystemUI/res/values-gl/strings.xml11
-rw-r--r--packages/SystemUI/res/values-gu/strings.xml11
-rw-r--r--packages/SystemUI/res/values-hi/strings.xml11
-rw-r--r--packages/SystemUI/res/values-hr/strings.xml12
-rw-r--r--packages/SystemUI/res/values-hu/strings.xml11
-rw-r--r--packages/SystemUI/res/values-hy/strings.xml11
-rw-r--r--packages/SystemUI/res/values-in/strings.xml11
-rw-r--r--packages/SystemUI/res/values-is/strings.xml11
-rw-r--r--packages/SystemUI/res/values-it/strings.xml11
-rw-r--r--packages/SystemUI/res/values-iw/strings.xml13
-rw-r--r--packages/SystemUI/res/values-ja/strings.xml11
-rw-r--r--packages/SystemUI/res/values-ka/strings.xml11
-rw-r--r--packages/SystemUI/res/values-kk/strings.xml11
-rw-r--r--packages/SystemUI/res/values-km/strings.xml11
-rw-r--r--packages/SystemUI/res/values-kn/strings.xml11
-rw-r--r--packages/SystemUI/res/values-ko/strings.xml11
-rw-r--r--packages/SystemUI/res/values-ky/strings.xml11
-rw-r--r--packages/SystemUI/res/values-lo/strings.xml11
-rw-r--r--packages/SystemUI/res/values-lt/strings.xml13
-rw-r--r--packages/SystemUI/res/values-lv/strings.xml12
-rw-r--r--packages/SystemUI/res/values-mk/strings.xml11
-rw-r--r--packages/SystemUI/res/values-ml/strings.xml11
-rw-r--r--packages/SystemUI/res/values-mn/strings.xml11
-rw-r--r--packages/SystemUI/res/values-mr/strings.xml11
-rw-r--r--packages/SystemUI/res/values-ms/strings.xml11
-rw-r--r--packages/SystemUI/res/values-my/strings.xml11
-rw-r--r--packages/SystemUI/res/values-nb/strings.xml11
-rw-r--r--packages/SystemUI/res/values-ne/strings.xml11
-rw-r--r--packages/SystemUI/res/values-nl/strings.xml11
-rw-r--r--packages/SystemUI/res/values-or/strings.xml11
-rw-r--r--packages/SystemUI/res/values-pa/strings.xml11
-rw-r--r--packages/SystemUI/res/values-pl/strings.xml13
-rw-r--r--packages/SystemUI/res/values-pt-rBR/strings.xml15
-rw-r--r--packages/SystemUI/res/values-pt-rPT/strings.xml11
-rw-r--r--packages/SystemUI/res/values-pt/strings.xml15
-rw-r--r--packages/SystemUI/res/values-ro/strings.xml12
-rw-r--r--packages/SystemUI/res/values-ru/strings.xml13
-rw-r--r--packages/SystemUI/res/values-si/strings.xml11
-rw-r--r--packages/SystemUI/res/values-sk/strings.xml13
-rw-r--r--packages/SystemUI/res/values-sl/strings.xml13
-rw-r--r--packages/SystemUI/res/values-sq/strings.xml11
-rw-r--r--packages/SystemUI/res/values-sr/strings.xml12
-rw-r--r--packages/SystemUI/res/values-sv/strings.xml11
-rw-r--r--packages/SystemUI/res/values-sw/strings.xml11
-rw-r--r--packages/SystemUI/res/values-ta/strings.xml11
-rw-r--r--packages/SystemUI/res/values-te/strings.xml11
-rw-r--r--packages/SystemUI/res/values-th/strings.xml15
-rw-r--r--packages/SystemUI/res/values-tl/strings.xml11
-rw-r--r--packages/SystemUI/res/values-tr/strings.xml11
-rw-r--r--packages/SystemUI/res/values-uk/strings.xml13
-rw-r--r--packages/SystemUI/res/values-ur/strings.xml11
-rw-r--r--packages/SystemUI/res/values-uz/strings.xml11
-rw-r--r--packages/SystemUI/res/values-vi/strings.xml15
-rw-r--r--packages/SystemUI/res/values-zh-rCN/strings.xml11
-rw-r--r--packages/SystemUI/res/values-zh-rHK/strings.xml11
-rw-r--r--packages/SystemUI/res/values-zh-rTW/strings.xml11
-rw-r--r--packages/SystemUI/res/values-zu/strings.xml11
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/QSAnimator.java6
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/QSFragment.java1
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/QSPanel.java1
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/QSSecurityFooter.java1
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java6
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/AlertingNotificationManager.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/NotificationLifetimeExtender.java14
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/NotificationRemoteInputManager.java6
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java39
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/car/FullscreenUserSwitcher.java115
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java8
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/ShadeViewRefactor.java36
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGutsManager.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java386
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/AlertingNotificationManagerTest.java9
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationRemoteInputManagerTest.java4
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationEntryManagerTest.java2
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationGutsManagerTest.java8
-rw-r--r--packages/VpnDialogs/res/values-ru/strings.xml2
-rw-r--r--packages/VpnDialogs/res/values-vi/strings.xml2
-rw-r--r--packages/overlays/DisplayCutoutEmulationCornerOverlay/res/values-bn/strings.xml21
-rw-r--r--packages/overlays/DisplayCutoutEmulationCornerOverlay/res/values-hi/strings.xml21
-rw-r--r--packages/overlays/DisplayCutoutEmulationCornerOverlay/res/values-te/strings.xml21
-rw-r--r--packages/overlays/DisplayCutoutEmulationDoubleOverlay/res/values-bn/strings.xml21
-rw-r--r--packages/overlays/DisplayCutoutEmulationDoubleOverlay/res/values-hi/strings.xml21
-rw-r--r--packages/overlays/DisplayCutoutEmulationDoubleOverlay/res/values-te/strings.xml21
-rw-r--r--packages/overlays/DisplayCutoutEmulationDoubleOverlay/res/values-uz/strings.xml2
-rw-r--r--packages/overlays/DisplayCutoutEmulationNarrowOverlay/res/values-bn/strings.xml23
-rw-r--r--packages/overlays/DisplayCutoutEmulationNarrowOverlay/res/values-fr/strings.xml2
-rw-r--r--packages/overlays/DisplayCutoutEmulationNarrowOverlay/res/values-hi/strings.xml23
-rw-r--r--packages/overlays/DisplayCutoutEmulationNarrowOverlay/res/values-te/strings.xml23
-rw-r--r--packages/overlays/DisplayCutoutEmulationTallOverlay/res/values-bn/strings.xml21
-rw-r--r--packages/overlays/DisplayCutoutEmulationTallOverlay/res/values-fr/strings.xml2
-rw-r--r--packages/overlays/DisplayCutoutEmulationTallOverlay/res/values-hi/strings.xml21
-rw-r--r--packages/overlays/DisplayCutoutEmulationTallOverlay/res/values-te/strings.xml21
-rw-r--r--packages/overlays/DisplayCutoutEmulationTallOverlay/res/values-uz/strings.xml2
-rw-r--r--packages/overlays/DisplayCutoutEmulationWideOverlay/res/values-bn/strings.xml21
-rw-r--r--packages/overlays/DisplayCutoutEmulationWideOverlay/res/values-fr/strings.xml2
-rw-r--r--packages/overlays/DisplayCutoutEmulationWideOverlay/res/values-hi/strings.xml21
-rw-r--r--packages/overlays/DisplayCutoutEmulationWideOverlay/res/values-te/strings.xml21
-rw-r--r--proto/src/metrics_constants.proto5
-rw-r--r--services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java12
-rw-r--r--services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java1
-rw-r--r--services/autofill/java/com/android/server/autofill/Session.java61
-rw-r--r--services/autofill/java/com/android/server/autofill/ViewState.java10
-rw-r--r--services/backup/java/com/android/server/backup/KeyValueAdbBackupEngine.java19
-rw-r--r--services/backup/java/com/android/server/backup/fullbackup/AppMetadataBackupWriter.java283
-rw-r--r--services/backup/java/com/android/server/backup/fullbackup/FullBackupEngine.java270
-rw-r--r--services/backup/java/com/android/server/backup/keyvalue/KeyValueBackupTask.java153
-rw-r--r--services/backup/java/com/android/server/backup/utils/FullBackupUtils.java72
-rw-r--r--services/core/java/com/android/server/AlarmManagerService.java406
-rw-r--r--services/core/java/com/android/server/InputMethodManagerService.java133
-rw-r--r--services/core/java/com/android/server/LooperStatsService.java2
-rw-r--r--services/core/java/com/android/server/NetworkManagementService.java57
-rw-r--r--services/core/java/com/android/server/TelephonyRegistry.java94
-rw-r--r--services/core/java/com/android/server/accounts/AccountManagerService.java46
-rw-r--r--services/core/java/com/android/server/am/ActivityDisplay.java40
-rw-r--r--services/core/java/com/android/server/am/ActivityManagerService.java14
-rw-r--r--services/core/java/com/android/server/am/ActivityStack.java14
-rw-r--r--services/core/java/com/android/server/am/ActivityStackSupervisor.java68
-rw-r--r--services/core/java/com/android/server/am/TEST_MAPPING22
-rw-r--r--services/core/java/com/android/server/biometrics/face/FaceService.java7
-rw-r--r--services/core/java/com/android/server/clipboard/ClipboardService.java9
-rw-r--r--services/core/java/com/android/server/job/JobSchedulerService.java2
-rw-r--r--services/core/java/com/android/server/notification/NotificationManagerService.java161
-rw-r--r--services/core/java/com/android/server/notification/PreferencesHelper.java151
-rw-r--r--services/core/java/com/android/server/pm/OtaDexoptService.java22
-rw-r--r--services/core/java/com/android/server/pm/PackageManagerService.java2
-rw-r--r--services/core/java/com/android/server/pm/PackageManagerServiceUtils.java13
-rw-r--r--services/core/java/com/android/server/stats/StatsCompanionService.java217
-rw-r--r--services/core/java/com/android/server/wallpaper/WallpaperManagerService.java15
-rw-r--r--services/core/java/com/android/server/wm/BoundsAnimationController.java18
-rw-r--r--services/core/java/com/android/server/wm/TEST_MAPPING22
-rw-r--r--services/core/java/com/android/server/wm/WindowStateAnimator.java3
-rw-r--r--services/core/jni/com_android_server_UsbDescriptorParser.cpp6
-rw-r--r--services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java25
-rw-r--r--services/java/com/android/server/SystemServer.java3
-rw-r--r--services/net/java/android/net/ip/RouterAdvertisementDaemon.java22
-rw-r--r--services/robotests/Android.mk4
-rw-r--r--services/robotests/src/com/android/server/backup/fullbackup/AppMetadataBackupWriterTest.java495
-rw-r--r--services/robotests/src/com/android/server/backup/keyvalue/KeyValueBackupTaskTest.java90
-rw-r--r--services/robotests/src/com/android/server/testing/shadows/ShadowBackupDataOutput.java5
-rw-r--r--services/robotests/src/com/android/server/testing/shadows/ShadowFullBackup.java70
-rw-r--r--services/tests/mockingservicestests/Android.mk13
-rw-r--r--services/tests/mockingservicestests/AndroidManifest.xml5
-rw-r--r--services/tests/mockingservicestests/AndroidTest.xml1
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/AlarmManagerServiceTest.java374
-rw-r--r--services/tests/servicestests/Android.mk4
-rw-r--r--services/tests/servicestests/AndroidManifest.xml3
-rw-r--r--services/tests/servicestests/src/com/android/server/BackgroundRestrictedAlarmsTest.java (renamed from services/tests/servicestests/src/com/android/server/AlarmManagerServiceTest.java)3
-rw-r--r--services/tests/servicestests/src/com/android/server/am/ActivityStackTests.java2
-rw-r--r--services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java41
-rw-r--r--services/tests/servicestests/utils/com/android/server/testutils/OffsettableClock.java (renamed from services/tests/servicestests/src/com/android/server/testutils/OffsettableClock.java)0
-rw-r--r--services/tests/servicestests/utils/com/android/server/testutils/TestHandler.java (renamed from services/tests/servicestests/src/com/android/server/testutils/TestHandler.java)0
-rw-r--r--services/tests/servicestests/utils/com/android/server/testutils/TestUtils.java (renamed from services/tests/servicestests/src/com/android/server/testutils/TestUtils.java)0
-rw-r--r--services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java178
-rw-r--r--services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java161
-rw-r--r--services/tests/wmtests/Android.mk41
-rw-r--r--services/tests/wmtests/AndroidManifest.xml31
-rw-r--r--services/tests/wmtests/AndroidTest.xml32
-rw-r--r--services/tests/wmtests/src/com/android/server/am/DummyAmTests.java46
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/DummyWmTests.java46
-rw-r--r--services/usage/java/com/android/server/usage/AppTimeLimitController.java1
-rw-r--r--services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerService.java1
-rw-r--r--telephony/java/android/telephony/SubscriptionManager.java127
-rw-r--r--telephony/java/android/telephony/TelephonyManager.java119
-rw-r--r--telephony/java/com/android/internal/telephony/ITelephony.aidl33
-rw-r--r--telephony/java/com/android/internal/telephony/ITelephonyRegistry.aidl3
-rw-r--r--test-mock/api/system-current.txt1
-rw-r--r--tests/SystemMemoryTest/README.txt3
-rw-r--r--tests/SystemMemoryTest/host/src/com/android/tests/sysmem/host/Metrics.java25
-rw-r--r--tests/TtsTests/src/com/android/speech/tts/TextToSpeechTests.java9
-rwxr-xr-xtools/hiddenapi/generate_hiddenapi_lists.py4
-rwxr-xr-xtools/hiddenapi/sort_api.sh6
-rw-r--r--tools/stats_log_api_gen/Collation.cpp10
-rw-r--r--tools/stats_log_api_gen/main.cpp111
600 files changed, 10516 insertions, 3588 deletions
diff --git a/Android.bp b/Android.bp
index 2ab91a1503e8..aeb3cebe8a13 100644
--- a/Android.bp
+++ b/Android.bp
@@ -683,6 +683,7 @@ java_defaults {
static_libs: [
"framework-protos",
+ "mediaplayer2-protos",
"android.hidl.base-V1.0-java",
"android.hardware.cas-V1.0-java",
"android.hardware.contexthub-V1.0-java",
diff --git a/Android.mk b/Android.mk
index 988c009bdbac..5c4c2376f80e 100644
--- a/Android.mk
+++ b/Android.mk
@@ -322,6 +322,11 @@ $(OUT_DOCS)/offline-sdk-timestamp: $(OUT_DOCS)/offline-sdk-docs-docs.zip
( unzip -qo $< -d $(OUT_DOCS)/offline-sdk && touch -f $@ ) || exit 1
# ==== hiddenapi lists =======================================
+.KATI_RESTAT: \
+ $(INTERNAL_PLATFORM_HIDDENAPI_WHITELIST) \
+ $(INTERNAL_PLATFORM_HIDDENAPI_LIGHT_GREYLIST) \
+ $(INTERNAL_PLATFORM_HIDDENAPI_DARK_GREYLIST) \
+ $(INTERNAL_PLATFORM_HIDDENAPI_BLACKLIST)
$(INTERNAL_PLATFORM_HIDDENAPI_WHITELIST): \
.KATI_IMPLICIT_OUTPUTS := \
$(INTERNAL_PLATFORM_HIDDENAPI_LIGHT_GREYLIST) \
@@ -346,10 +351,14 @@ $(INTERNAL_PLATFORM_HIDDENAPI_WHITELIST): \
$(INTERNAL_PLATFORM_HIDDENAPI_PRIVATE_LIST)) \
$(PRIVATE_GREYLIST_INPUTS) \
--input-blacklists frameworks/base/config/hiddenapi-force-blacklist.txt \
- --output-whitelist $(INTERNAL_PLATFORM_HIDDENAPI_WHITELIST) \
- --output-light-greylist $(INTERNAL_PLATFORM_HIDDENAPI_LIGHT_GREYLIST) \
- --output-dark-greylist $(INTERNAL_PLATFORM_HIDDENAPI_DARK_GREYLIST) \
- --output-blacklist $(INTERNAL_PLATFORM_HIDDENAPI_BLACKLIST)
+ --output-whitelist $(INTERNAL_PLATFORM_HIDDENAPI_WHITELIST).tmp \
+ --output-light-greylist $(INTERNAL_PLATFORM_HIDDENAPI_LIGHT_GREYLIST).tmp \
+ --output-dark-greylist $(INTERNAL_PLATFORM_HIDDENAPI_DARK_GREYLIST).tmp \
+ --output-blacklist $(INTERNAL_PLATFORM_HIDDENAPI_BLACKLIST).tmp
+ $(call commit-change-for-toc,$(INTERNAL_PLATFORM_HIDDENAPI_WHITELIST))
+ $(call commit-change-for-toc,$(INTERNAL_PLATFORM_HIDDENAPI_LIGHT_GREYLIST))
+ $(call commit-change-for-toc,$(INTERNAL_PLATFORM_HIDDENAPI_DARK_GREYLIST))
+ $(call commit-change-for-toc,$(INTERNAL_PLATFORM_HIDDENAPI_BLACKLIST))
# Include subdirectory makefiles
# ============================================================
diff --git a/api/current.txt b/api/current.txt
index 73898554af16..e31f8a05611d 100755
--- a/api/current.txt
+++ b/api/current.txt
@@ -2826,7 +2826,7 @@ package android.accessibilityservice {
field public static final java.lang.String SERVICE_META_DATA = "android.accessibilityservice";
field public static final int SHOW_MODE_AUTO = 0; // 0x0
field public static final int SHOW_MODE_HIDDEN = 1; // 0x1
- field public static final int SHOW_MODE_WITH_HARD_KEYBOARD = 2; // 0x2
+ field public static final int SHOW_MODE_IGNORE_HARD_KEYBOARD = 2; // 0x2
}
public static abstract class AccessibilityService.GestureResultCallback {
@@ -5680,6 +5680,7 @@ package android.app {
public class NotificationManager {
method public java.lang.String addAutomaticZenRule(android.app.AutomaticZenRule);
method public boolean areNotificationsEnabled();
+ method public boolean canNotifyAsPackage(java.lang.String);
method public void cancel(int);
method public void cancel(java.lang.String, int);
method public void cancelAll();
@@ -5698,13 +5699,17 @@ package android.app {
method public android.app.NotificationChannelGroup getNotificationChannelGroup(java.lang.String);
method public java.util.List<android.app.NotificationChannelGroup> getNotificationChannelGroups();
method public java.util.List<android.app.NotificationChannel> getNotificationChannels();
+ method public java.lang.String getNotificationDelegate();
method public android.app.NotificationManager.Policy getNotificationPolicy();
method public boolean isNotificationListenerAccessGranted(android.content.ComponentName);
method public boolean isNotificationPolicyAccessGranted();
method public void notify(int, android.app.Notification);
method public void notify(java.lang.String, int, android.app.Notification);
+ method public void notifyAsPackage(java.lang.String, java.lang.String, int, android.app.Notification);
method public boolean removeAutomaticZenRule(java.lang.String);
+ method public void revokeNotificationDelegate();
method public final void setInterruptionFilter(int);
+ method public void setNotificationDelegate(java.lang.String);
method public void setNotificationPolicy(android.app.NotificationManager.Policy);
method public boolean updateAutomaticZenRule(java.lang.String, android.app.AutomaticZenRule);
field public static final java.lang.String ACTION_APP_BLOCK_STATE_CHANGED = "android.app.action.APP_BLOCK_STATE_CHANGED";
@@ -13978,6 +13983,7 @@ package android.graphics {
method public float getFontSpacing();
method public java.lang.String getFontVariationSettings();
method public int getHinting();
+ method public int getHyphenEdit();
method public float getLetterSpacing();
method public android.graphics.MaskFilter getMaskFilter();
method public int getOffsetForAdvance(char[], int, int, int, int, boolean, float);
@@ -14041,6 +14047,7 @@ package android.graphics {
method public void setFontFeatureSettings(java.lang.String);
method public boolean setFontVariationSettings(java.lang.String);
method public void setHinting(int);
+ method public void setHyphenEdit(int);
method public void setLetterSpacing(float);
method public void setLinearText(boolean);
method public android.graphics.MaskFilter setMaskFilter(android.graphics.MaskFilter);
@@ -14579,6 +14586,14 @@ package android.graphics {
method public android.graphics.Typeface.Builder setWeight(int);
}
+ public static class Typeface.CustomFallbackBuilder {
+ ctor public Typeface.CustomFallbackBuilder(android.graphics.fonts.FontFamily);
+ method public android.graphics.Typeface build();
+ method public android.graphics.Typeface.CustomFallbackBuilder setFallback(java.lang.String);
+ method public android.graphics.Typeface.CustomFallbackBuilder setItalic(boolean);
+ method public android.graphics.Typeface.CustomFallbackBuilder setWeight(int);
+ }
+
public class Xfermode {
ctor public Xfermode();
}
@@ -15218,6 +15233,9 @@ package android.graphics.fonts {
public final class Font {
method public android.graphics.fonts.FontVariationAxis[] getAxes();
+ method public java.nio.ByteBuffer getBuffer();
+ method public java.io.File getFile();
+ method public android.os.LocaleList getLocaleList();
method public int getTtcIndex();
method public int getWeight();
method public boolean isItalic();
@@ -15226,7 +15244,9 @@ package android.graphics.fonts {
field public static final int FONT_WEIGHT_EXTRA_BOLD = 800; // 0x320
field public static final int FONT_WEIGHT_EXTRA_LIGHT = 200; // 0xc8
field public static final int FONT_WEIGHT_LIGHT = 300; // 0x12c
+ field public static final int FONT_WEIGHT_MAX = 1000; // 0x3e8
field public static final int FONT_WEIGHT_MEDIUM = 500; // 0x1f4
+ field public static final int FONT_WEIGHT_MIN = 1; // 0x1
field public static final int FONT_WEIGHT_NORMAL = 400; // 0x190
field public static final int FONT_WEIGHT_SEMI_BOLD = 600; // 0x258
field public static final int FONT_WEIGHT_THIN = 100; // 0x64
@@ -15266,6 +15286,10 @@ package android.graphics.fonts {
method public static java.lang.String toFontVariationSettings(android.graphics.fonts.FontVariationAxis[]);
}
+ public class SystemFonts {
+ method public static java.util.Set<android.graphics.fonts.Font> getAvailableFonts();
+ }
+
}
package android.graphics.pdf {
@@ -39637,10 +39661,12 @@ package android.service.notification {
method public int getId();
method public java.lang.String getKey();
method public android.app.Notification getNotification();
+ method public java.lang.String getOpPkg();
method public java.lang.String getOverrideGroupKey();
method public java.lang.String getPackageName();
method public long getPostTime();
method public java.lang.String getTag();
+ method public int getUid();
method public android.os.UserHandle getUser();
method public deprecated int getUserId();
method public boolean isClearable();
@@ -42610,6 +42636,7 @@ package android.telephony {
}
public class SubscriptionManager {
+ method public void addOnOpportunisticSubscriptionsChangedListener(java.util.concurrent.Executor, android.telephony.SubscriptionManager.OnOpportunisticSubscriptionsChangedListener);
method public void addOnSubscriptionsChangedListener(android.telephony.SubscriptionManager.OnSubscriptionsChangedListener);
method public boolean canManageSubscription(android.telephony.SubscriptionInfo);
method public static deprecated android.telephony.SubscriptionManager from(android.content.Context);
@@ -42624,8 +42651,10 @@ package android.telephony {
method public static int getDefaultSubscriptionId();
method public static int getDefaultVoiceSubscriptionId();
method public java.util.List<android.telephony.SubscriptionInfo> getOpportunisticSubscriptions(int);
+ method public static int[] getSubscriptionIds(int);
method public java.util.List<android.telephony.SubscriptionPlan> getSubscriptionPlans(int);
method public boolean isNetworkRoaming(int);
+ method public void removeOnOpportunisticSubscriptionsChangedListener(android.telephony.SubscriptionManager.OnOpportunisticSubscriptionsChangedListener);
method public void removeOnSubscriptionsChangedListener(android.telephony.SubscriptionManager.OnSubscriptionsChangedListener);
method public void setSubscriptionOverrideCongested(int, boolean, long);
method public void setSubscriptionOverrideUnmetered(int, boolean, long);
@@ -42641,6 +42670,11 @@ package android.telephony {
field public static final int INVALID_SUBSCRIPTION_ID = -1; // 0xffffffff
}
+ public static class SubscriptionManager.OnOpportunisticSubscriptionsChangedListener {
+ ctor public SubscriptionManager.OnOpportunisticSubscriptionsChangedListener();
+ method public void onOpportunisticSubscriptionsChanged();
+ }
+
public static class SubscriptionManager.OnSubscriptionsChangedListener {
ctor public SubscriptionManager.OnSubscriptionsChangedListener();
method public void onSubscriptionsChanged();
@@ -43474,6 +43508,22 @@ package android.text {
method public abstract void handleTag(boolean, java.lang.String, android.text.Editable, org.xml.sax.XMLReader);
}
+ public class Hyphenator {
+ method public static int packHyphenEdit(int, int);
+ method public static int unpackEndHyphenEdit(int);
+ method public static int unpackStartHyphenEdit(int);
+ field public static final int END_HYPHEN_EDIT_INSERT_ARMENIAN_HYPHEN = 3; // 0x3
+ field public static final int END_HYPHEN_EDIT_INSERT_HYPHEN = 2; // 0x2
+ field public static final int END_HYPHEN_EDIT_INSERT_MAQAF = 4; // 0x4
+ field public static final int END_HYPHEN_EDIT_INSERT_UCAS_HYPHEN = 5; // 0x5
+ field public static final int END_HYPHEN_EDIT_INSERT_ZWJ_AND_HYPHEN = 6; // 0x6
+ field public static final int END_HYPHEN_EDIT_NO_EDIT = 0; // 0x0
+ field public static final int END_HYPHEN_EDIT_REPLACE_WITH_HYPHEN = 1; // 0x1
+ field public static final int START_HYPHEN_EDIT_INSERT_HYPHEN = 1; // 0x1
+ field public static final int START_HYPHEN_EDIT_INSERT_ZWJ = 2; // 0x2
+ field public static final int START_HYPHEN_EDIT_NO_EDIT = 0; // 0x0
+ }
+
public abstract interface InputFilter {
method public abstract java.lang.CharSequence filter(java.lang.CharSequence, int, int, android.text.Spanned, int, int);
}
diff --git a/api/system-current.txt b/api/system-current.txt
index afce431d49ec..1e1c621a561d 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -1115,6 +1115,7 @@ package android.content.pm {
public abstract class PackageManager {
method public abstract void addOnPermissionsChangeListener(android.content.pm.PackageManager.OnPermissionsChangedListener);
+ method public abstract boolean arePermissionsIndividuallyControlled();
method public abstract java.util.List<android.content.IntentFilter> getAllIntentFilters(java.lang.String);
method public android.content.pm.dex.ArtManager getArtManager();
method public abstract java.lang.String getDefaultBrowserPackageNameAsUser(int);
@@ -1266,6 +1267,14 @@ package android.content.pm.permission {
}
+package android.graphics.drawable {
+
+ public final class Icon implements android.os.Parcelable {
+ method public static android.graphics.drawable.Icon createWithResource(android.content.res.Resources, int);
+ }
+
+}
+
package android.hardware {
public final class Sensor {
@@ -2615,6 +2624,7 @@ package android.location {
method public deprecated boolean addGpsNavigationMessageListener(android.location.GpsNavigationMessageEvent.Listener);
method public void flushGnssBatch();
method public int getGnssBatchSize();
+ method public java.lang.String getNetworkProviderPackage();
method public boolean isLocationEnabledForUser(android.os.UserHandle);
method public boolean isProviderEnabledForUser(java.lang.String, android.os.UserHandle);
method public boolean registerGnssBatchedLocationCallback(long, boolean, android.location.BatchedLocationCallback, android.os.Handler);
diff --git a/cmds/statsd/Android.bp b/cmds/statsd/Android.bp
index b5660995fa36..3fae586725ec 100644
--- a/cmds/statsd/Android.bp
+++ b/cmds/statsd/Android.bp
@@ -43,3 +43,25 @@ cc_library_host_shared {
}
+// ==== java proto device library (for test only) ==============================
+java_library {
+ name: "statsdprotolite",
+ proto: {
+ type: "lite",
+ include_dirs: ["external/protobuf/src"],
+ },
+
+ srcs: [
+ "src/stats_log.proto",
+ "src/statsd_config.proto",
+ "src/atoms.proto",
+ ],
+
+ static_libs: [
+ "platformprotoslite",
+ ],
+ // Protos have lots of MissingOverride and similar.
+ errorprone: {
+ javacflags: ["-XepDisableAllChecks"],
+ },
+}
diff --git a/cmds/statsd/Android.mk b/cmds/statsd/Android.mk
index ba2aaad875d0..5e87ef658dd5 100644
--- a/cmds/statsd/Android.mk
+++ b/cmds/statsd/Android.mk
@@ -243,28 +243,6 @@ LOCAL_SHARED_LIBRARIES := $(statsd_common_shared_libraries) \
include $(BUILD_NATIVE_TEST)
##############################
-# stats proto static java lib
-##############################
-
-include $(CLEAR_VARS)
-LOCAL_MODULE := statsdprotolite
-
-LOCAL_SRC_FILES := \
- src/stats_log.proto \
- src/statsd_config.proto \
- src/atoms.proto
-
-LOCAL_PROTOC_OPTIMIZE_TYPE := lite
-
-LOCAL_STATIC_JAVA_LIBRARIES := \
- platformprotoslite
-
-LOCAL_PROTOC_FLAGS := \
- -Iexternal/protobuf/src
-
-include $(BUILD_STATIC_JAVA_LIBRARY)
-
-##############################
# statsd micro benchmark
##############################
diff --git a/cmds/statsd/src/atoms.proto b/cmds/statsd/src/atoms.proto
index 2ecfbe733bca..8f3ad9df2370 100644
--- a/cmds/statsd/src/atoms.proto
+++ b/cmds/statsd/src/atoms.proto
@@ -130,6 +130,7 @@ message Atom {
GenericAtom generic_atom = 82;
KeyValuePairsAtom key_value_pairs_atom = 83;
VibratorStateChanged vibrator_state_changed = 84;
+ DeferredJobStatsReported deferred_job_stats_reported = 85;
}
// Pulled events will start at field 10000.
@@ -153,13 +154,17 @@ message Atom {
SystemUptime system_uptime = 10015;
CpuActiveTime cpu_active_time = 10016;
CpuClusterTime cpu_cluster_time = 10017;
- DiskSpace disk_space = 10018;
+ DiskSpace disk_space = 10018 [deprecated=true];
RemainingBatteryCapacity remaining_battery_capacity = 10019;
FullBatteryCapacity full_battery_capacity = 10020;
Temperature temperature = 10021;
BinderCalls binder_calls = 10022;
BinderCallsExceptions binder_calls_exceptions = 10023;
LooperStats looper_stats = 10024;
+ DiskStats disk_stats = 10025;
+ DirectoryUsage directory_usage = 10026;
+ AppSize app_size = 10027;
+ CategorySize category_size = 10028;
}
// DO NOT USE field numbers above 100,000 in AOSP. Field numbers above
@@ -469,6 +474,22 @@ message SyncStateChanged {
optional State state = 3;
}
+/*
+ * Deferred job stats.
+ *
+ * Logged from:
+ * frameworks/base/services/core/java/com/android/server/job/JobSchedulerService.java
+*/
+message DeferredJobStatsReported {
+ repeated AttributionNode attribution_node = 1;
+
+ // Number of jobs deferred.
+ optional int32 num_jobs_deferred = 2;
+
+ // Time since the last job runs.
+ optional int64 time_since_last_job_millis = 3;
+}
+
/**
* Logs when a job scheduler job state changes.
*
@@ -737,7 +758,7 @@ message WifiRadioPowerStateChanged {
* Logs kernel wakeup reasons and aborts.
*
* Logged from:
- * frameworks/base/services/core/java/com/android/server/am/BatteryStatsService.java
+ * frameworks/base/core/java/com/android/internal/os/BatteryStatsImpl.java
*/
message KernelWakeupReported {
// Name of the kernel wakeup reason (or abort).
@@ -2251,3 +2272,82 @@ message LooperStats {
// recorded_total_cpu_micros / recorded_message_count * call_count.
optional int64 recorded_total_cpu_micros = 9;
}
+
+/**
+ * Pulls disk information, such as write speed and latency.
+ */
+message DiskStats {
+ // Time taken to open, write 512B to, and close a file.
+ // -1 if error performing the check.
+ optional int64 data_write_latency_millis = 1;
+
+ optional bool file_based_encryption = 2;
+
+ // Recent disk write speed in kB/s.
+ // -1 if error querying storageed.
+ // 0 if data is unavailable.
+ optional int32 recent_disk_write_speed = 3;
+}
+
+
+/**
+ * Free and total bytes of the Data, Cache, and System partition.
+ */
+message DirectoryUsage {
+ enum Directory {
+ UNKNOWN = 0;
+ DATA = 1;
+ CACHE = 2;
+ SYSTEM = 3;
+ }
+ optional Directory directory = 1;
+ optional int64 free_bytes = 2;
+ optional int64 total_bytes = 3;
+}
+
+
+/**
+ * Size of an application: apk size, data size, and cache size.
+ * Reads from a cached file produced daily by DiskStatsLoggingService.java.
+ * Information is only reported for apps with the primary user (user 0).
+ * Sizes are aggregated by package name.
+ */
+message AppSize {
+ // Including uids will involve modifying diskstats logic.
+ optional string package_name = 1;
+ // App size in bytes. -1 if unavailable.
+ optional int64 app_size_bytes = 2;
+ // App data size in bytes. -1 if unavailable.
+ optional int64 app_data_size_bytes = 3;
+ // App cache size in bytes. -1 if unavailable.
+ optional int64 app_cache_size_bytes = 4;
+ // Time that the cache file was produced.
+ // Uses System.currentTimeMillis(), which is wall clock time.
+ optional int64 cache_time_millis = 5;
+}
+
+
+/**
+ * Size of a particular category. Eg: photos, videos.
+ * Reads from a cached file produced daily by DiskStatsLoggingService.java.
+ */
+message CategorySize {
+ enum Category {
+ UNKNOWN = 0;
+ APP_SIZE = 1;
+ APP_DATA_SIZE = 2;
+ APP_CACHE_SIZE = 3;
+ PHOTOS = 4;
+ VIDEOS = 5;
+ AUDIO = 6;
+ DOWNLOADS = 7;
+ SYSTEM = 8;
+ OTHER = 9;
+ }
+ optional Category category = 1;
+ // Category size in bytes.
+ optional int64 size_bytes = 2;
+ // Time that the cache file was produced.
+ // Uses System.currentTimeMillis(), which is wall clock time.
+ optional int64 cache_time_millis = 3;
+}
diff --git a/cmds/statsd/src/external/StatsPullerManager.cpp b/cmds/statsd/src/external/StatsPullerManager.cpp
index 28718823bb32..dbc13dc36ea7 100644
--- a/cmds/statsd/src/external/StatsPullerManager.cpp
+++ b/cmds/statsd/src/external/StatsPullerManager.cpp
@@ -149,9 +149,6 @@ const std::map<int, PullAtomInfo> StatsPullerManager::kAllPullAtomInfo = {
// system_uptime
{android::util::SYSTEM_UPTIME,
{{}, {}, 1 * NS_PER_SEC, new StatsCompanionServicePuller(android::util::SYSTEM_UPTIME)}},
- // disk_space
- {android::util::DISK_SPACE,
- {{}, {}, 1 * NS_PER_SEC, new StatsCompanionServicePuller(android::util::DISK_SPACE)}},
// remaining_battery_capacity
{android::util::REMAINING_BATTERY_CAPACITY,
{{},
@@ -189,7 +186,31 @@ const std::map<int, PullAtomInfo> StatsPullerManager::kAllPullAtomInfo = {
{{5, 6, 7, 8, 9},
{2, 3, 4},
1 * NS_PER_SEC,
- new StatsCompanionServicePuller(android::util::LOOPER_STATS)}}
+ new StatsCompanionServicePuller(android::util::LOOPER_STATS)}},
+ // Disk Stats
+ {android::util::DISK_STATS,
+ {{},
+ {},
+ 1 * NS_PER_SEC,
+ new StatsCompanionServicePuller(android::util::DISK_STATS)}},
+ // Directory usage
+ {android::util::DIRECTORY_USAGE,
+ {{},
+ {},
+ 1 * NS_PER_SEC,
+ new StatsCompanionServicePuller(android::util::DIRECTORY_USAGE)}},
+ // Size of app's code, data, and cache
+ {android::util::APP_SIZE,
+ {{},
+ {},
+ 1 * NS_PER_SEC,
+ new StatsCompanionServicePuller(android::util::APP_SIZE)}},
+ // Size of specific categories of files. Eg. Music.
+ {android::util::CATEGORY_SIZE,
+ {{},
+ {},
+ 1 * NS_PER_SEC,
+ new StatsCompanionServicePuller(android::util::CATEGORY_SIZE)}},
};
StatsPullerManager::StatsPullerManager() : mNextPullTimeNs(NO_ALARM_UPDATE) {
diff --git a/cmds/statsd/src/logd/LogEvent.cpp b/cmds/statsd/src/logd/LogEvent.cpp
index 73e6572db50f..cf04ee3e17ec 100644
--- a/cmds/statsd/src/logd/LogEvent.cpp
+++ b/cmds/statsd/src/logd/LogEvent.cpp
@@ -175,6 +175,56 @@ bool LogEvent::write(float value) {
return false;
}
+
+
+bool LogEvent::writeKeyValuePairs(const std::map<int32_t, int64_t>& int_map,
+ const std::map<int32_t, std::string>& string_map,
+ const std::map<int32_t, float>& float_map) {
+ if (mContext) {
+ if (android_log_write_list_begin(mContext) < 0) {
+ return false;
+ }
+ for (const auto& itr : int_map) {
+ if (android_log_write_list_begin(mContext) < 0) {
+ return false;
+ }
+ write(itr.first);
+ write(itr.second);
+ if (android_log_write_list_end(mContext) < 0) {
+ return false;
+ }
+ }
+
+ for (const auto& itr : string_map) {
+ if (android_log_write_list_begin(mContext) < 0) {
+ return false;
+ }
+ write(itr.first);
+ write(itr.second.c_str());
+ if (android_log_write_list_end(mContext) < 0) {
+ return false;
+ }
+ }
+
+ for (const auto& itr : float_map) {
+ if (android_log_write_list_begin(mContext) < 0) {
+ return false;
+ }
+ write(itr.first);
+ write(itr.second);
+ if (android_log_write_list_end(mContext) < 0) {
+ return false;
+ }
+ }
+
+ if (android_log_write_list_end(mContext) < 0) {
+ return false;
+ }
+ return true;
+ }
+ return false;
+}
+
bool LogEvent::write(const std::vector<AttributionNodeInternal>& nodes) {
if (mContext) {
if (android_log_write_list_begin(mContext) < 0) {
@@ -225,6 +275,7 @@ void LogEvent::init(android_log_context context) {
int i = 0;
int depth = -1;
int pos[] = {1, 1, 1};
+ bool isKeyValuePairAtom = false;
do {
elem = android_log_read_next(context);
switch ((int)elem.type) {
@@ -232,6 +283,7 @@ void LogEvent::init(android_log_context context) {
// elem at [0] is EVENT_TYPE_LIST, [1] is the timestamp, [2] is tag id.
if (i == 2) {
mTagId = elem.data.int32;
+ isKeyValuePairAtom = (mTagId == android::util::KEY_VALUE_PAIRS_ATOM);
} else {
if (depth < 0 || depth > 2) {
return;
@@ -249,6 +301,11 @@ void LogEvent::init(android_log_context context) {
return;
}
+ // Handles the oneof field in KeyValuePair atom.
+ if (isKeyValuePairAtom && depth == 2) {
+ pos[depth] = 4;
+ }
+
mValues.push_back(FieldValue(Field(mTagId, pos, depth), Value(elem.data.float32)));
pos[depth]++;
@@ -260,6 +317,10 @@ void LogEvent::init(android_log_context context) {
return;
}
+ // Handles the oneof field in KeyValuePair atom.
+ if (isKeyValuePairAtom && depth == 2) {
+ pos[depth] = 3;
+ }
mValues.push_back(FieldValue(Field(mTagId, pos, depth),
Value(string(elem.data.string, elem.len))));
@@ -274,6 +335,10 @@ void LogEvent::init(android_log_context context) {
ALOGE("Depth > 2. Not supported!");
return;
}
+ // Handles the oneof field in KeyValuePair atom.
+ if (isKeyValuePairAtom && depth == 2) {
+ pos[depth] = 2;
+ }
mValues.push_back(
FieldValue(Field(mTagId, pos, depth), Value((int64_t)elem.data.int64)));
diff --git a/cmds/statsd/src/logd/LogEvent.h b/cmds/statsd/src/logd/LogEvent.h
index 9ed09dd12fbd..2ee6bdf7c7ba 100644
--- a/cmds/statsd/src/logd/LogEvent.h
+++ b/cmds/statsd/src/logd/LogEvent.h
@@ -119,6 +119,9 @@ public:
bool write(float value);
bool write(const std::vector<AttributionNodeInternal>& nodes);
bool write(const AttributionNodeInternal& node);
+ bool writeKeyValuePairs(const std::map<int32_t, int64_t>& int_map,
+ const std::map<int32_t, std::string>& string_map,
+ const std::map<int32_t, float>& float_map);
/**
* Return a string representation of this event.
diff --git a/cmds/statsd/src/metrics/GaugeMetricProducer.cpp b/cmds/statsd/src/metrics/GaugeMetricProducer.cpp
index 284c4511a16f..bcfcd7a4f06e 100644
--- a/cmds/statsd/src/metrics/GaugeMetricProducer.cpp
+++ b/cmds/statsd/src/metrics/GaugeMetricProducer.cpp
@@ -367,13 +367,26 @@ void GaugeMetricProducer::onSlicedConditionMayChangeLocked(bool overallCondition
}
std::shared_ptr<vector<FieldValue>> GaugeMetricProducer::getGaugeFields(const LogEvent& event) {
+ std::shared_ptr<vector<FieldValue>> gaugeFields;
if (mFieldMatchers.size() > 0) {
- std::shared_ptr<vector<FieldValue>> gaugeFields = std::make_shared<vector<FieldValue>>();
+ gaugeFields = std::make_shared<vector<FieldValue>>();
filterGaugeValues(mFieldMatchers, event.getValues(), gaugeFields.get());
- return gaugeFields;
} else {
- return std::make_shared<vector<FieldValue>>(event.getValues());
+ gaugeFields = std::make_shared<vector<FieldValue>>(event.getValues());
+ }
+ // Trim all dimension fields from output. Dimensions will appear in output report and will
+ // benefit from dictionary encoding. For large pulled atoms, this can give the benefit of
+ // optional repeated field.
+ for (const auto& field : mDimensionsInWhat) {
+ for (auto it = gaugeFields->begin(); it != gaugeFields->end();) {
+ if (it->mField.matches(field)) {
+ it = gaugeFields->erase(it);
+ } else {
+ it++;
+ }
+ }
}
+ return gaugeFields;
}
void GaugeMetricProducer::onDataPulled(const std::vector<std::shared_ptr<LogEvent>>& allData) {
diff --git a/cmds/statsd/src/metrics/GaugeMetricProducer.h b/cmds/statsd/src/metrics/GaugeMetricProducer.h
index 15be1d7c470b..e3da5db4b90e 100644
--- a/cmds/statsd/src/metrics/GaugeMetricProducer.h
+++ b/cmds/statsd/src/metrics/GaugeMetricProducer.h
@@ -175,6 +175,7 @@ private:
FRIEND_TEST(GaugeMetricProducerTest, TestPulledEventsAnomalyDetection);
FRIEND_TEST(GaugeMetricProducerTest, TestFirstBucket);
FRIEND_TEST(GaugeMetricProducerTest, TestPullOnTrigger);
+ FRIEND_TEST(GaugeMetricProducerTest, TestRemoveDimensionInOutput);
};
} // namespace statsd
diff --git a/cmds/statsd/tests/LogEvent_test.cpp b/cmds/statsd/tests/LogEvent_test.cpp
index acfa151c6f95..6e3b04ce6b3b 100644
--- a/cmds/statsd/tests/LogEvent_test.cpp
+++ b/cmds/statsd/tests/LogEvent_test.cpp
@@ -89,6 +89,89 @@ TEST(LogEventTest, TestLogParsing) {
EXPECT_EQ((float)1.1, item7.mValue.float_value);
}
+TEST(LogEventTest, TestKeyValuePairsAtomParsing) {
+ LogEvent event1(83, 2000);
+ std::map<int32_t, int64_t> int_map;
+ std::map<int32_t, std::string> string_map;
+ std::map<int32_t, float> float_map;
+
+ int_map[11] = 123L;
+ int_map[22] = 345L;
+
+ string_map[1] = "test2";
+ string_map[2] = "test1";
+
+ float_map[111] = 2.2f;
+ float_map[222] = 1.1f;
+
+ EXPECT_TRUE(event1.writeKeyValuePairs(int_map, string_map, float_map));
+ event1.init();
+
+ EXPECT_EQ(83, event1.GetTagId());
+ const auto& items = event1.getValues();
+ EXPECT_EQ((size_t)12, items.size());
+
+ const FieldValue& item0 = event1.getValues()[0];
+ EXPECT_EQ(0x2010101, item0.mField.getField());
+ EXPECT_EQ(Type::INT, item0.mValue.getType());
+ EXPECT_EQ(11, item0.mValue.int_value);
+
+ const FieldValue& item1 = event1.getValues()[1];
+ EXPECT_EQ(0x2010182, item1.mField.getField());
+ EXPECT_EQ(Type::LONG, item1.mValue.getType());
+ EXPECT_EQ(123L, item1.mValue.long_value);
+
+ const FieldValue& item2 = event1.getValues()[2];
+ EXPECT_EQ(0x2010201, item2.mField.getField());
+ EXPECT_EQ(Type::INT, item2.mValue.getType());
+ EXPECT_EQ(22, item2.mValue.int_value);
+
+ const FieldValue& item3 = event1.getValues()[3];
+ EXPECT_EQ(0x2010282, item3.mField.getField());
+ EXPECT_EQ(Type::LONG, item3.mValue.getType());
+ EXPECT_EQ(345L, item3.mValue.long_value);
+
+ const FieldValue& item4 = event1.getValues()[4];
+ EXPECT_EQ(0x2010301, item4.mField.getField());
+ EXPECT_EQ(Type::INT, item4.mValue.getType());
+ EXPECT_EQ(1, item4.mValue.int_value);
+
+ const FieldValue& item5 = event1.getValues()[5];
+ EXPECT_EQ(0x2010383, item5.mField.getField());
+ EXPECT_EQ(Type::STRING, item5.mValue.getType());
+ EXPECT_EQ("test2", item5.mValue.str_value);
+
+ const FieldValue& item6 = event1.getValues()[6];
+ EXPECT_EQ(0x2010401, item6.mField.getField());
+ EXPECT_EQ(Type::INT, item6.mValue.getType());
+ EXPECT_EQ(2, item6.mValue.int_value);
+
+ const FieldValue& item7 = event1.getValues()[7];
+ EXPECT_EQ(0x2010483, item7.mField.getField());
+ EXPECT_EQ(Type::STRING, item7.mValue.getType());
+ EXPECT_EQ("test1", item7.mValue.str_value);
+
+ const FieldValue& item8 = event1.getValues()[8];
+ EXPECT_EQ(0x2010501, item8.mField.getField());
+ EXPECT_EQ(Type::INT, item8.mValue.getType());
+ EXPECT_EQ(111, item8.mValue.int_value);
+
+ const FieldValue& item9 = event1.getValues()[9];
+ EXPECT_EQ(0x2010584, item9.mField.getField());
+ EXPECT_EQ(Type::FLOAT, item9.mValue.getType());
+ EXPECT_EQ(2.2f, item9.mValue.float_value);
+
+ const FieldValue& item10 = event1.getValues()[10];
+ EXPECT_EQ(0x2018601, item10.mField.getField());
+ EXPECT_EQ(Type::INT, item10.mValue.getType());
+ EXPECT_EQ(222, item10.mValue.int_value);
+
+ const FieldValue& item11 = event1.getValues()[11];
+ EXPECT_EQ(0x2018684, item11.mField.getField());
+ EXPECT_EQ(Type::FLOAT, item11.mValue.getType());
+ EXPECT_EQ(1.1f, item11.mValue.float_value);
+}
+
TEST(LogEventTest, TestLogParsing2) {
LogEvent event1(1, 2000);
@@ -158,7 +241,7 @@ TEST(LogEventTest, TestLogParsing2) {
EXPECT_EQ((float)1.1, item7.mValue.float_value);
}
-TEST(LogEventTest, TestKeyValuePairsAtomParsing) {
+TEST(LogEventTest, TestKeyValuePairsEvent) {
std::map<int32_t, int64_t> int_map;
std::map<int32_t, std::string> string_map;
std::map<int32_t, float> float_map;
diff --git a/cmds/statsd/tests/e2e/GaugeMetric_e2e_pull_test.cpp b/cmds/statsd/tests/e2e/GaugeMetric_e2e_pull_test.cpp
index d98395e78467..ea6eb3f3d712 100644
--- a/cmds/statsd/tests/e2e/GaugeMetric_e2e_pull_test.cpp
+++ b/cmds/statsd/tests/e2e/GaugeMetric_e2e_pull_test.cpp
@@ -48,6 +48,7 @@ StatsdConfig CreateStatsdConfig(const GaugeMetric::SamplingType sampling_type) {
*gaugeMetric->mutable_dimensions_in_what() =
CreateDimensions(android::util::TEMPERATURE, {2/* sensor name field */ });
gaugeMetric->set_bucket(FIVE_MINUTES);
+ config.set_hash_strings_in_metric_report(false);
return config;
}
@@ -150,7 +151,7 @@ TEST(GaugeMetricE2eTest, TestRandomSamplePulledEvents) {
EXPECT_EQ(1, data.bucket_info(0).wall_clock_timestamp_nanos_size());
EXPECT_EQ(baseTimeNs + 2 * bucketSizeNs, data.bucket_info(0).start_bucket_elapsed_nanos());
EXPECT_EQ(baseTimeNs + 3 * bucketSizeNs, data.bucket_info(0).end_bucket_elapsed_nanos());
- EXPECT_FALSE(data.bucket_info(0).atom(0).temperature().sensor_name().empty());
+ EXPECT_TRUE(data.bucket_info(0).atom(0).temperature().sensor_name().empty());
EXPECT_GT(data.bucket_info(0).atom(0).temperature().temperature_dc(), 0);
EXPECT_EQ(1, data.bucket_info(1).atom_size());
@@ -159,7 +160,7 @@ TEST(GaugeMetricE2eTest, TestRandomSamplePulledEvents) {
EXPECT_EQ(configAddedTimeNs + 55, data.bucket_info(0).elapsed_timestamp_nanos(0));
EXPECT_EQ(baseTimeNs + 3 * bucketSizeNs, data.bucket_info(1).start_bucket_elapsed_nanos());
EXPECT_EQ(baseTimeNs + 4 * bucketSizeNs, data.bucket_info(1).end_bucket_elapsed_nanos());
- EXPECT_FALSE(data.bucket_info(1).atom(0).temperature().sensor_name().empty());
+ EXPECT_TRUE(data.bucket_info(1).atom(0).temperature().sensor_name().empty());
EXPECT_GT(data.bucket_info(1).atom(0).temperature().temperature_dc(), 0);
EXPECT_EQ(1, data.bucket_info(2).atom_size());
@@ -168,7 +169,7 @@ TEST(GaugeMetricE2eTest, TestRandomSamplePulledEvents) {
data.bucket_info(2).elapsed_timestamp_nanos(0));
EXPECT_EQ(baseTimeNs + 4 * bucketSizeNs, data.bucket_info(2).start_bucket_elapsed_nanos());
EXPECT_EQ(baseTimeNs + 5 * bucketSizeNs, data.bucket_info(2).end_bucket_elapsed_nanos());
- EXPECT_FALSE(data.bucket_info(2).atom(0).temperature().sensor_name().empty());
+ EXPECT_TRUE(data.bucket_info(2).atom(0).temperature().sensor_name().empty());
EXPECT_GT(data.bucket_info(2).atom(0).temperature().temperature_dc(), 0);
EXPECT_EQ(1, data.bucket_info(3).atom_size());
@@ -177,7 +178,7 @@ TEST(GaugeMetricE2eTest, TestRandomSamplePulledEvents) {
data.bucket_info(3).elapsed_timestamp_nanos(0));
EXPECT_EQ(baseTimeNs + 5 * bucketSizeNs, data.bucket_info(3).start_bucket_elapsed_nanos());
EXPECT_EQ(baseTimeNs + 6 * bucketSizeNs, data.bucket_info(3).end_bucket_elapsed_nanos());
- EXPECT_FALSE(data.bucket_info(3).atom(0).temperature().sensor_name().empty());
+ EXPECT_TRUE(data.bucket_info(3).atom(0).temperature().sensor_name().empty());
EXPECT_GT(data.bucket_info(3).atom(0).temperature().temperature_dc(), 0);
EXPECT_EQ(1, data.bucket_info(4).atom_size());
@@ -186,7 +187,7 @@ TEST(GaugeMetricE2eTest, TestRandomSamplePulledEvents) {
data.bucket_info(4).elapsed_timestamp_nanos(0));
EXPECT_EQ(baseTimeNs + 7 * bucketSizeNs, data.bucket_info(4).start_bucket_elapsed_nanos());
EXPECT_EQ(baseTimeNs + 8 * bucketSizeNs, data.bucket_info(4).end_bucket_elapsed_nanos());
- EXPECT_FALSE(data.bucket_info(4).atom(0).temperature().sensor_name().empty());
+ EXPECT_TRUE(data.bucket_info(4).atom(0).temperature().sensor_name().empty());
EXPECT_GT(data.bucket_info(4).atom(0).temperature().temperature_dc(), 0);
EXPECT_EQ(1, data.bucket_info(5).atom_size());
@@ -195,7 +196,7 @@ TEST(GaugeMetricE2eTest, TestRandomSamplePulledEvents) {
data.bucket_info(5).elapsed_timestamp_nanos(0));
EXPECT_EQ(baseTimeNs + 8 * bucketSizeNs, data.bucket_info(5).start_bucket_elapsed_nanos());
EXPECT_EQ(baseTimeNs + 9 * bucketSizeNs, data.bucket_info(5).end_bucket_elapsed_nanos());
- EXPECT_FALSE(data.bucket_info(5).atom(0).temperature().sensor_name().empty());
+ EXPECT_TRUE(data.bucket_info(5).atom(0).temperature().sensor_name().empty());
EXPECT_GT(data.bucket_info(5).atom(0).temperature().temperature_dc(), 0);
}
@@ -273,7 +274,7 @@ TEST(GaugeMetricE2eTest, TestAllConditionChangesSamplePulledEvents) {
EXPECT_EQ(1, data.bucket_info(0).wall_clock_timestamp_nanos_size());
EXPECT_EQ(baseTimeNs + 2 * bucketSizeNs, data.bucket_info(0).start_bucket_elapsed_nanos());
EXPECT_EQ(baseTimeNs + 3 * bucketSizeNs, data.bucket_info(0).end_bucket_elapsed_nanos());
- EXPECT_FALSE(data.bucket_info(0).atom(0).temperature().sensor_name().empty());
+ EXPECT_TRUE(data.bucket_info(0).atom(0).temperature().sensor_name().empty());
EXPECT_GT(data.bucket_info(0).atom(0).temperature().temperature_dc(), 0);
EXPECT_EQ(1, data.bucket_info(1).atom_size());
@@ -282,7 +283,7 @@ TEST(GaugeMetricE2eTest, TestAllConditionChangesSamplePulledEvents) {
EXPECT_EQ(configAddedTimeNs + 55, data.bucket_info(0).elapsed_timestamp_nanos(0));
EXPECT_EQ(baseTimeNs + 3 * bucketSizeNs, data.bucket_info(1).start_bucket_elapsed_nanos());
EXPECT_EQ(baseTimeNs + 4 * bucketSizeNs, data.bucket_info(1).end_bucket_elapsed_nanos());
- EXPECT_FALSE(data.bucket_info(1).atom(0).temperature().sensor_name().empty());
+ EXPECT_TRUE(data.bucket_info(1).atom(0).temperature().sensor_name().empty());
EXPECT_GT(data.bucket_info(1).atom(0).temperature().temperature_dc(), 0);
EXPECT_EQ(2, data.bucket_info(2).atom_size());
@@ -293,9 +294,9 @@ TEST(GaugeMetricE2eTest, TestAllConditionChangesSamplePulledEvents) {
data.bucket_info(2).elapsed_timestamp_nanos(1));
EXPECT_EQ(baseTimeNs + 7 * bucketSizeNs, data.bucket_info(2).start_bucket_elapsed_nanos());
EXPECT_EQ(baseTimeNs + 8 * bucketSizeNs, data.bucket_info(2).end_bucket_elapsed_nanos());
- EXPECT_FALSE(data.bucket_info(2).atom(0).temperature().sensor_name().empty());
+ EXPECT_TRUE(data.bucket_info(2).atom(0).temperature().sensor_name().empty());
EXPECT_GT(data.bucket_info(2).atom(0).temperature().temperature_dc(), 0);
- EXPECT_FALSE(data.bucket_info(2).atom(1).temperature().sensor_name().empty());
+ EXPECT_TRUE(data.bucket_info(2).atom(1).temperature().sensor_name().empty());
EXPECT_GT(data.bucket_info(2).atom(1).temperature().temperature_dc(), 0);
}
@@ -377,7 +378,7 @@ TEST(GaugeMetricE2eTest, TestRandomSamplePulledEvent_LateAlarm) {
EXPECT_EQ(1, data.bucket_info(0).wall_clock_timestamp_nanos_size());
EXPECT_EQ(baseTimeNs + 2 * bucketSizeNs, data.bucket_info(0).start_bucket_elapsed_nanos());
EXPECT_EQ(baseTimeNs + 3 * bucketSizeNs, data.bucket_info(0).end_bucket_elapsed_nanos());
- EXPECT_FALSE(data.bucket_info(0).atom(0).temperature().sensor_name().empty());
+ EXPECT_TRUE(data.bucket_info(0).atom(0).temperature().sensor_name().empty());
EXPECT_GT(data.bucket_info(0).atom(0).temperature().temperature_dc(), 0);
EXPECT_EQ(1, data.bucket_info(1).atom_size());
@@ -386,7 +387,7 @@ TEST(GaugeMetricE2eTest, TestRandomSamplePulledEvent_LateAlarm) {
EXPECT_EQ(configAddedTimeNs + 55, data.bucket_info(0).elapsed_timestamp_nanos(0));
EXPECT_EQ(baseTimeNs + 5 * bucketSizeNs, data.bucket_info(1).start_bucket_elapsed_nanos());
EXPECT_EQ(baseTimeNs + 6 * bucketSizeNs, data.bucket_info(1).end_bucket_elapsed_nanos());
- EXPECT_FALSE(data.bucket_info(1).atom(0).temperature().sensor_name().empty());
+ EXPECT_TRUE(data.bucket_info(1).atom(0).temperature().sensor_name().empty());
EXPECT_GT(data.bucket_info(1).atom(0).temperature().temperature_dc(), 0);
EXPECT_EQ(1, data.bucket_info(2).atom_size());
@@ -395,7 +396,7 @@ TEST(GaugeMetricE2eTest, TestRandomSamplePulledEvent_LateAlarm) {
data.bucket_info(2).elapsed_timestamp_nanos(0));
EXPECT_EQ(baseTimeNs + 6 * bucketSizeNs, data.bucket_info(2).start_bucket_elapsed_nanos());
EXPECT_EQ(baseTimeNs + 7 * bucketSizeNs, data.bucket_info(2).end_bucket_elapsed_nanos());
- EXPECT_FALSE(data.bucket_info(2).atom(0).temperature().sensor_name().empty());
+ EXPECT_TRUE(data.bucket_info(2).atom(0).temperature().sensor_name().empty());
EXPECT_GT(data.bucket_info(2).atom(0).temperature().temperature_dc(), 0);
}
diff --git a/cmds/statsd/tests/metrics/GaugeMetricProducer_test.cpp b/cmds/statsd/tests/metrics/GaugeMetricProducer_test.cpp
index 9471faa89547..bf58b9c7e4d4 100644
--- a/cmds/statsd/tests/metrics/GaugeMetricProducer_test.cpp
+++ b/cmds/statsd/tests/metrics/GaugeMetricProducer_test.cpp
@@ -95,6 +95,8 @@ TEST(GaugeMetricProducerTest, TestPulledEventsNoCondition) {
data->clear();
shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucketStartTimeNs + 10);
event->write(3);
+ event->write("some value");
+ event->write(11);
event->init();
data->push_back(event);
return true;
@@ -600,9 +602,109 @@ TEST(GaugeMetricProducerTest, TestPullOnTrigger) {
EXPECT_EQ(10, it->mValue.int_value);
EXPECT_EQ(1UL, gaugeProducer.mPastBuckets.size());
EXPECT_EQ(3UL, gaugeProducer.mPastBuckets.begin()->second.back().mGaugeAtoms.size());
- EXPECT_EQ(3, gaugeProducer.mPastBuckets.begin()->second.back().mGaugeAtoms[0].mFields->begin()->mValue.int_value);
- EXPECT_EQ(4, gaugeProducer.mPastBuckets.begin()->second.back().mGaugeAtoms[1].mFields->begin()->mValue.int_value);
- EXPECT_EQ(5, gaugeProducer.mPastBuckets.begin()->second.back().mGaugeAtoms[2].mFields->begin()->mValue.int_value);
+ EXPECT_EQ(3, gaugeProducer.mPastBuckets.begin()
+ ->second.back()
+ .mGaugeAtoms[0]
+ .mFields->begin()
+ ->mValue.int_value);
+ EXPECT_EQ(4, gaugeProducer.mPastBuckets.begin()
+ ->second.back()
+ .mGaugeAtoms[1]
+ .mFields->begin()
+ ->mValue.int_value);
+ EXPECT_EQ(5, gaugeProducer.mPastBuckets.begin()
+ ->second.back()
+ .mGaugeAtoms[2]
+ .mFields->begin()
+ ->mValue.int_value);
+}
+
+TEST(GaugeMetricProducerTest, TestRemoveDimensionInOutput) {
+ GaugeMetric metric;
+ metric.set_id(metricId);
+ metric.set_bucket(ONE_MINUTE);
+ metric.set_sampling_type(GaugeMetric::ALL_CONDITION_CHANGES);
+ metric.mutable_gauge_fields_filter()->set_include_all(true);
+ auto dimensionMatcher = metric.mutable_dimensions_in_what();
+ // use field 1 as dimension.
+ dimensionMatcher->set_field(tagId);
+ dimensionMatcher->add_child()->set_field(1);
+
+ sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
+
+ sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
+ EXPECT_CALL(*pullerManager, Pull(tagId, _, _))
+ .WillOnce(Invoke([](int tagId, int64_t timeNs,
+ vector<std::shared_ptr<LogEvent>>* data) {
+ data->clear();
+ shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucketStartTimeNs + 3);
+ event->write(3);
+ event->write(4);
+ event->init();
+ data->push_back(event);
+ return true;
+ }))
+ .WillOnce(Invoke([](int tagId, int64_t timeNs,
+ vector<std::shared_ptr<LogEvent>>* data) {
+ data->clear();
+ shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucketStartTimeNs + 10);
+ event->write(4);
+ event->write(5);
+ event->init();
+ data->push_back(event);
+ return true;
+ }))
+ .WillOnce(Invoke([](int tagId, int64_t timeNs,
+ vector<std::shared_ptr<LogEvent>>* data) {
+ data->clear();
+ shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucketStartTimeNs + 20);
+ event->write(4);
+ event->write(6);
+ event->init();
+ data->push_back(event);
+ return true;
+ }));
+
+ int triggerId = 5;
+ GaugeMetricProducer gaugeProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, wizard,
+ tagId, triggerId, tagId, bucketStartTimeNs, bucketStartTimeNs,
+ pullerManager);
+
+ vector<shared_ptr<LogEvent>> allData;
+ allData.clear();
+
+ EXPECT_EQ(1UL, gaugeProducer.mCurrentSlicedBucket->size());
+ LogEvent trigger(triggerId, bucketStartTimeNs + 10);
+ trigger.init();
+ gaugeProducer.onMatchedLogEvent(1 /*log matcher index*/, trigger);
+ EXPECT_EQ(2UL, gaugeProducer.mCurrentSlicedBucket->size());
+ EXPECT_EQ(1UL, gaugeProducer.mCurrentSlicedBucket->begin()->second.size());
+ trigger.setElapsedTimestampNs(bucketStartTimeNs + 20);
+ gaugeProducer.onMatchedLogEvent(1 /*log matcher index*/, trigger);
+ EXPECT_EQ(2UL, gaugeProducer.mCurrentSlicedBucket->begin()->second.size());
+
+ allData.clear();
+ shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucket2StartTimeNs + 1);
+ event->write(4);
+ event->write(11);
+ event->init();
+ allData.push_back(event);
+
+ gaugeProducer.onDataPulled(allData);
+ EXPECT_EQ(1UL, gaugeProducer.mCurrentSlicedBucket->size());
+ auto it = gaugeProducer.mCurrentSlicedBucket->begin()->second.front().mFields->begin();
+ EXPECT_EQ(INT, it->mValue.getType());
+ EXPECT_EQ(11, it->mValue.int_value);
+ EXPECT_EQ(2UL, gaugeProducer.mPastBuckets.size());
+ auto bucketIt = gaugeProducer.mPastBuckets.begin();
+ EXPECT_EQ(1UL, bucketIt->second.back().mGaugeAtoms.size());
+ EXPECT_EQ(3, bucketIt->first.getDimensionKeyInWhat().getValues().begin()->mValue.int_value);
+ EXPECT_EQ(4, bucketIt->second.back().mGaugeAtoms[0].mFields->begin()->mValue.int_value);
+ bucketIt++;
+ EXPECT_EQ(2UL, bucketIt->second.back().mGaugeAtoms.size());
+ EXPECT_EQ(4, bucketIt->first.getDimensionKeyInWhat().getValues().begin()->mValue.int_value);
+ EXPECT_EQ(5, bucketIt->second.back().mGaugeAtoms[0].mFields->begin()->mValue.int_value);
+ EXPECT_EQ(6, bucketIt->second.back().mGaugeAtoms[1].mFields->begin()->mValue.int_value);
}
} // namespace statsd
diff --git a/config/boot-image-profile.txt b/config/boot-image-profile.txt
index cdcdc46cc2fd..04b33b18dce4 100644
--- a/config/boot-image-profile.txt
+++ b/config/boot-image-profile.txt
@@ -11818,6 +11818,7 @@ HPLlibcore/io/BlockGuardOs;->readlink(Ljava/lang/String;)Ljava/lang/String;
HPLlibcore/io/BlockGuardOs;->rename(Ljava/lang/String;Ljava/lang/String;)V
HPLlibcore/io/BlockGuardOs;->sendto(Ljava/io/FileDescriptor;[BIIILjava/net/SocketAddress;)I
HPLlibcore/io/BlockGuardOs;->write(Ljava/io/FileDescriptor;Ljava/nio/ByteBuffer;)I
+HPLlibcore/io/ForwardingOs;->android_fdsan_exchange_owner_tag(Ljava/io/FileDescriptor;JJ)V
HPLlibcore/io/ForwardingOs;->munlock(JJ)V
HPLlibcore/io/ForwardingOs;->munmap(JJ)V
HPLlibcore/io/ForwardingOs;->setsockoptByte(Ljava/io/FileDescriptor;III)V
@@ -51619,6 +51620,7 @@ HSPLlibcore/io/IoTracker;->trackIo(ILlibcore/io/IoTracker$Mode;)V
HSPLlibcore/io/IoUtils$FileReader;-><init>(Ljava/lang/String;)V
HSPLlibcore/io/IoUtils$FileReader;->readFully()Llibcore/io/IoUtils$FileReader;
HSPLlibcore/io/IoUtils$FileReader;->toByteArray()[B
+HSPLlibcore/io/IoUtils;->acquireRawFd(Ljava/io/FileDescriptor;)I
HSPLlibcore/io/IoUtils;->canOpenReadOnly(Ljava/lang/String;)Z
HSPLlibcore/io/IoUtils;->close(Ljava/io/FileDescriptor;)V
HSPLlibcore/io/IoUtils;->closeQuietly(Ljava/io/FileDescriptor;)V
@@ -51626,6 +51628,7 @@ HSPLlibcore/io/IoUtils;->closeQuietly(Ljava/lang/AutoCloseable;)V
HSPLlibcore/io/IoUtils;->readFileAsByteArray(Ljava/lang/String;)[B
HSPLlibcore/io/IoUtils;->readFileAsString(Ljava/lang/String;)Ljava/lang/String;
HSPLlibcore/io/IoUtils;->setBlocking(Ljava/io/FileDescriptor;Z)V
+HSPLlibcore/io/IoUtils;->setFdOwner(Ljava/io/FileDescriptor;Ljava/lang/Object;)V
HSPLlibcore/io/Linux;->read(Ljava/io/FileDescriptor;[BII)I
HSPLlibcore/io/Linux;->recvfrom(Ljava/io/FileDescriptor;[BIIILjava/net/InetSocketAddress;)I
HSPLlibcore/io/Linux;->sendto(Ljava/io/FileDescriptor;[BIIILjava/net/InetAddress;I)I
diff --git a/core/java/android/accessibilityservice/AccessibilityService.java b/core/java/android/accessibilityservice/AccessibilityService.java
index 5b73eaa9cd17..446e6cc0769c 100644
--- a/core/java/android/accessibilityservice/AccessibilityService.java
+++ b/core/java/android/accessibilityservice/AccessibilityService.java
@@ -399,7 +399,7 @@ public abstract class AccessibilityService extends Service {
@IntDef(prefix = { "SHOW_MODE_" }, value = {
SHOW_MODE_AUTO,
SHOW_MODE_HIDDEN,
- SHOW_MODE_WITH_HARD_KEYBOARD
+ SHOW_MODE_IGNORE_HARD_KEYBOARD
})
public @interface SoftKeyboardShowMode {}
@@ -419,7 +419,7 @@ public abstract class AccessibilityService extends Service {
* Allow the soft keyboard to be shown, even if a hard keyboard is connected
* @see SoftKeyboardController
*/
- public static final int SHOW_MODE_WITH_HARD_KEYBOARD = 2;
+ public static final int SHOW_MODE_IGNORE_HARD_KEYBOARD = 2;
/**
* Mask used to cover the show modes supported in public API
@@ -1205,7 +1205,7 @@ public abstract class AccessibilityService extends Service {
*
* @see AccessibilityService#SHOW_MODE_AUTO
* @see AccessibilityService#SHOW_MODE_HIDDEN
- * @see AccessibilityService#SHOW_MODE_WITH_HARD_KEYBOARD
+ * @see AccessibilityService#SHOW_MODE_IGNORE_HARD_KEYBOARD
*/
public static final class SoftKeyboardController {
private final AccessibilityService mService;
@@ -1354,7 +1354,7 @@ public abstract class AccessibilityService extends Service {
*
* @see AccessibilityService#SHOW_MODE_AUTO
* @see AccessibilityService#SHOW_MODE_HIDDEN
- * @see AccessibilityService#SHOW_MODE_WITH_HARD_KEYBOARD
+ * @see AccessibilityService#SHOW_MODE_IGNORE_HARD_KEYBOARD
*/
@SoftKeyboardShowMode
public int getShowMode() {
@@ -1384,7 +1384,7 @@ public abstract class AccessibilityService extends Service {
*
* @see AccessibilityService#SHOW_MODE_AUTO
* @see AccessibilityService#SHOW_MODE_HIDDEN
- * @see AccessibilityService#SHOW_MODE_WITH_HARD_KEYBOARD
+ * @see AccessibilityService#SHOW_MODE_IGNORE_HARD_KEYBOARD
*/
public boolean setShowMode(@SoftKeyboardShowMode int showMode) {
final IAccessibilityServiceConnection connection =
diff --git a/core/java/android/accounts/Account.java b/core/java/android/accounts/Account.java
index f07f5ece7bc1..d3b2238d8b69 100644
--- a/core/java/android/accounts/Account.java
+++ b/core/java/android/accounts/Account.java
@@ -20,13 +20,14 @@ import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.UnsupportedAppUsage;
import android.content.Context;
-import android.os.Parcelable;
import android.os.Parcel;
+import android.os.Parcelable;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.text.TextUtils;
import android.util.ArraySet;
import android.util.Log;
+
import com.android.internal.annotations.GuardedBy;
import java.util.Set;
@@ -45,6 +46,7 @@ public class Account implements Parcelable {
public final String name;
public final String type;
+ private String mSafeName;
@UnsupportedAppUsage
private final @Nullable String accessId;
@@ -135,4 +137,37 @@ public class Account implements Parcelable {
public String toString() {
return "Account {name=" + name + ", type=" + type + "}";
}
+
+ /**
+ * Return a string representation of the account that is safe to print
+ * to logs and other places where PII should be avoided.
+ * @hide
+ */
+ public String toSafeString() {
+ if (mSafeName == null) {
+ mSafeName = toSafeName(name, 'x');
+ }
+ return "Account {name=" + mSafeName + ", type=" + type + "}";
+ }
+
+ /**
+ * Given a name, replace all letter or digits with the replacement char.
+ * @param name The input name string.
+ * @param replacement the replacement character.
+ * @return the string after replacement.
+ * @hide
+ */
+ public static String toSafeName(String name, char replacement) {
+ final StringBuilder builder = new StringBuilder(64);
+ final int len = name.length();
+ for (int i = 0; i < len; i++) {
+ final char c = name.charAt(i);
+ if (Character.isLetterOrDigit(c)) {
+ builder.append(replacement);
+ } else {
+ builder.append(c);
+ }
+ }
+ return builder.toString();
+ }
}
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index bf2d86096773..041a5b071032 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -1461,7 +1461,7 @@ public class Activity extends ContextThemeWrapper
*/
@Override
public AutofillId autofillClientGetNextAutofillId() {
- return new AutofillId(getNextAutofillId());
+ return new AutofillId(getAutofillManager(), getNextAutofillId());
}
/**
diff --git a/core/java/android/app/INotificationManager.aidl b/core/java/android/app/INotificationManager.aidl
index 3171e3e3b992..4f004d93e3bf 100644
--- a/core/java/android/app/INotificationManager.aidl
+++ b/core/java/android/app/INotificationManager.aidl
@@ -165,4 +165,9 @@ interface INotificationManager
void applyRestore(in byte[] payload, int user);
ParceledListSlice getAppActiveNotifications(String callingPkg, int userId);
+
+ void setNotificationDelegate(String callingPkg, String delegate);
+ void revokeNotificationDelegate(String callingPkg);
+ String getNotificationDelegate(String callingPkg);
+ boolean canNotifyAsPackage(String callingPkg, String targetPkg);
}
diff --git a/core/java/android/app/NotificationManager.java b/core/java/android/app/NotificationManager.java
index 4b25b8b6e1e0..b96b39df9aa0 100644
--- a/core/java/android/app/NotificationManager.java
+++ b/core/java/android/app/NotificationManager.java
@@ -18,6 +18,7 @@ package android.app;
import android.annotation.IntDef;
import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.annotation.SdkConstant;
import android.annotation.SystemService;
import android.annotation.TestApi;
@@ -352,7 +353,7 @@ public class NotificationManager {
}
/**
- * Post a notification to be shown in the status bar. If a notification with
+ * Posts a notification to be shown in the status bar. If a notification with
* the same tag and id has already been posted by your application and has not yet been
* canceled, it will be replaced by the updated information.
*
@@ -376,6 +377,42 @@ public class NotificationManager {
}
/**
+ * Posts a notification as a specified package to be shown in the status bar. If a notification
+ * with the same tag and id has already been posted for that package and has not yet been
+ * canceled, it will be replaced by the updated information.
+ *
+ * All {@link android.service.notification.NotificationListenerService listener services} will
+ * be granted {@link Intent#FLAG_GRANT_READ_URI_PERMISSION} access to any {@link Uri uris}
+ * provided on this notification or the
+ * {@link NotificationChannel} this notification is posted to using
+ * {@link Context#grantUriPermission(String, Uri, int)}. Permission will be revoked when the
+ * notification is canceled, or you can revoke permissions with
+ * {@link Context#revokeUriPermission(Uri, int)}.
+ *
+ * @param targetPackage The package to post the notification as. The package must have granted
+ * you access to post notifications on their behalf with
+ * {@link #setNotificationDelegate(String)}.
+ * @param tag A string identifier for this notification. May be {@code null}.
+ * @param id An identifier for this notification. The pair (tag, id) must be unique
+ * within your application.
+ * @param notification A {@link Notification} object describing what to
+ * show the user. Must not be null.
+ */
+ public void notifyAsPackage(@NonNull String targetPackage, @NonNull String tag, int id,
+ Notification notification) {
+ INotificationManager service = getService();
+ String sender = mContext.getPackageName();
+
+ try {
+ if (localLOGV) Log.v(TAG, sender + ": notify(" + id + ", " + notification + ")");
+ service.enqueueNotificationWithTag(targetPackage, sender, tag, id,
+ fixNotification(notification), mContext.getUser().getIdentifier());
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
* @hide
*/
@UnsupportedAppUsage
@@ -383,6 +420,18 @@ public class NotificationManager {
{
INotificationManager service = getService();
String pkg = mContext.getPackageName();
+
+ try {
+ if (localLOGV) Log.v(TAG, pkg + ": notify(" + id + ", " + notification + ")");
+ service.enqueueNotificationWithTag(pkg, mContext.getOpPackageName(), tag, id,
+ fixNotification(notification), user.getIdentifier());
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ private Notification fixNotification(Notification notification) {
+ String pkg = mContext.getPackageName();
// Fix the notification as best we can.
Notification.addFieldsFromContext(mContext, notification);
@@ -400,19 +449,12 @@ public class NotificationManager {
+ notification);
}
}
- if (localLOGV) Log.v(TAG, pkg + ": notify(" + id + ", " + notification + ")");
+
notification.reduceImageSizes(mContext);
ActivityManager am = (ActivityManager) mContext.getSystemService(Context.ACTIVITY_SERVICE);
boolean isLowRam = am.isLowRamDevice();
- final Notification copy = Builder.maybeCloneStrippedForDelivery(notification, isLowRam,
- mContext);
- try {
- service.enqueueNotificationWithTag(pkg, mContext.getOpPackageName(), tag, id,
- copy, user.getIdentifier());
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
+ return Builder.maybeCloneStrippedForDelivery(notification, isLowRam, mContext);
}
private void fixLegacySmallIcon(Notification n, String pkg) {
@@ -474,6 +516,72 @@ public class NotificationManager {
}
/**
+ * Allows a package to post notifications on your behalf using
+ * {@link #notifyAsPackage(String, String, int, Notification)}.
+ *
+ * This can be used to allow persistent processes to post notifications based on messages
+ * received on your behalf from the cloud, without your process having to wake up.
+ *
+ * You can check if you have an allowed delegate with {@link #getNotificationDelegate()} and
+ * revoke your delegate with {@link #revokeNotificationDelegate()}.
+ *
+ * @param delegate Package name of the app which can send notifications on your behalf.
+ */
+ public void setNotificationDelegate(@NonNull String delegate) {
+ INotificationManager service = getService();
+ String pkg = mContext.getPackageName();
+ if (localLOGV) Log.v(TAG, pkg + ": cancelAll()");
+ try {
+ service.setNotificationDelegate(pkg, delegate);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Revokes permission for your {@link #setNotificationDelegate(String) notification delegate}
+ * to post notifications on your behalf.
+ */
+ public void revokeNotificationDelegate() {
+ INotificationManager service = getService();
+ String pkg = mContext.getPackageName();
+ try {
+ service.revokeNotificationDelegate(pkg);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Returns the {@link #setNotificationDelegate(String) delegate} that can post notifications on
+ * your behalf, if there currently is one.
+ */
+ public @Nullable String getNotificationDelegate() {
+ INotificationManager service = getService();
+ String pkg = mContext.getPackageName();
+ try {
+ return service.getNotificationDelegate(pkg);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Returns whether you are allowed to post notifications on behalf of a given package, with
+ * {@link #notifyAsPackage(String, String, int, Notification)}.
+ *
+ * See {@link #setNotificationDelegate(String)}.
+ */
+ public boolean canNotifyAsPackage(String pkg) {
+ INotificationManager service = getService();
+ try {
+ return service.canNotifyAsPackage(mContext.getPackageName(), pkg);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
* Creates a group container for {@link NotificationChannel} objects.
*
* This can be used to rename an existing group.
diff --git a/core/java/android/app/admin/DeviceAdminInfo.java b/core/java/android/app/admin/DeviceAdminInfo.java
index 5fe1af0a18ba..beb1c78388c9 100644
--- a/core/java/android/app/admin/DeviceAdminInfo.java
+++ b/core/java/android/app/admin/DeviceAdminInfo.java
@@ -74,12 +74,10 @@ public final class DeviceAdminInfo implements Parcelable {
* that the user can select, via {@link DevicePolicyManager#setPasswordQuality}
* and {@link DevicePolicyManager#setPasswordMinimumLength}.
*
- * <p>To control this policy, the device admin must have a "limit-password"
- * tag in the "uses-policies" section of its meta-data.
- *
- * <p>This policy is deprecated for use by a device admin. In future releases, it will
- * only be possible for a device owner or profile owner to enforce constraints on user
- * passwords.
+ * <p>To control this policy, the device admin must be a device owner or profile owner,
+ * and must have a "limit-password" tag in the "uses-policies" section of its meta-data.
+ * If used by a device owner, the policy only affects the primary user and its profiles,
+ * but not any secondary users on the device.
*/
public static final int USES_POLICY_LIMIT_PASSWORD = 0;
@@ -139,11 +137,10 @@ public final class DeviceAdminInfo implements Parcelable {
* A type of policy that this device admin can use: force the user to
* change their password after an administrator-defined time limit.
*
- * <p>To control this policy, the device admin must have an "expire-password"
- * tag in the "uses-policies" section of its meta-data.
- *
- * <p>This policy is deprecated for use by a device admin. In future releases, it will
- * only be possible for a device owner or profile owner to enforce password expiry.
+ * <p>To control this policy, the device admin must be a device owner or profile owner,
+ * and must have an "expire-password" tag in the "uses-policies" section of its meta-data.
+ * If used by a device owner, the policy only affects the primary user and its profiles,
+ * but not any secondary users on the device.
*/
public static final int USES_POLICY_EXPIRE_PASSWORD = 6;
@@ -158,23 +155,19 @@ public final class DeviceAdminInfo implements Parcelable {
/**
* A type of policy that this device admin can use: disables use of all device cameras.
*
- * <p>To control this policy, the device admin must have a "disable-camera"
- * tag in the "uses-policies" section of its meta-data.
- *
- * <p>This policy is deprecated for use by a device admin. In future releases, it will
- * only be possible for a device owner or profile owner to disable use of the camera.
+ * <p>To control this policy, the device admin must be a device owner or profile owner,
+ * and must have a "disable-camera" tag in the "uses-policies" section of its meta-data.
+ * If used by a device owner, the policy affects all users on the device.
*/
public static final int USES_POLICY_DISABLE_CAMERA = 8;
/**
* A type of policy that this device admin can use: disables use of keyguard features.
*
- * <p>To control this policy, the device admin must have a "disable-keyguard-features"
- * tag in the "uses-policies" section of its meta-data.
- *
- * <p>This policy is deprecated for use by a device admin. In future releases, it will
- * only be possible for a device owner or profile owner to disable use of keyguard
- * features.
+ * <p>To control this policy, the device admin must be a device owner or profile owner,
+ * and must have a "disable-keyguard-features" tag in the "uses-policies" section of its
+ * meta-data. If used by a device owner, the policy only affects the primary user and
+ * its profiles, but not any secondary users on the device.
*/
public static final int USES_POLICY_DISABLE_KEYGUARD_FEATURES = 9;
diff --git a/core/java/android/app/assist/AssistStructure.java b/core/java/android/app/assist/AssistStructure.java
index 173b7667897e..ee6a81d9b6e1 100644
--- a/core/java/android/app/assist/AssistStructure.java
+++ b/core/java/android/app/assist/AssistStructure.java
@@ -32,6 +32,7 @@ import android.view.ViewStructure.HtmlInfo.Builder;
import android.view.WindowManager;
import android.view.WindowManagerGlobal;
import android.view.autofill.AutofillId;
+import android.view.autofill.AutofillManager;
import android.view.autofill.AutofillValue;
import com.android.internal.util.Preconditions;
@@ -72,6 +73,8 @@ public class AssistStructure implements Parcelable {
boolean mHaveData;
ComponentName mActivityComponent;
+ // Not written to parcel, only used to set session id on virtual node children
+ private final int mAutofillSessionId;
private boolean mIsHomeActivity;
private int mFlags;
@@ -1846,11 +1849,13 @@ public class AssistStructure implements Parcelable {
@Override
public void setAutofillId(@NonNull AutofillId id) {
mNode.mAutofillId = id;
+ mNode.mAutofillId.setSessionId(mAssist.mAutofillSessionId);
}
@Override
public void setAutofillId(@NonNull AutofillId parentId, int virtualId) {
mNode.mAutofillId = new AutofillId(parentId, virtualId);
+ mNode.mAutofillId.setSessionId(mAssist.mAutofillSessionId);
}
@Override
@@ -2040,6 +2045,8 @@ public class AssistStructure implements Parcelable {
public AssistStructure(Activity activity, boolean forAutoFill, int flags) {
mHaveData = true;
mActivityComponent = activity.getComponentName();
+ final AutofillManager afm = activity.getSystemService(AutofillManager.class);
+ mAutofillSessionId = afm == null ? AutofillManager.NO_SESSION : afm.getSessionId();
mFlags = flags;
ArrayList<ViewRootImpl> views = WindowManagerGlobal.getInstance().getRootViews(
activity.getActivityToken());
@@ -2056,6 +2063,7 @@ public class AssistStructure implements Parcelable {
public AssistStructure() {
mHaveData = true;
mActivityComponent = null;
+ mAutofillSessionId = AutofillManager.NO_SESSION;
mFlags = 0;
}
@@ -2063,6 +2071,7 @@ public class AssistStructure implements Parcelable {
public AssistStructure(Parcel in) {
mIsHomeActivity = in.readInt() == 1;
mReceiveChannel = in.readStrongBinder();
+ mAutofillSessionId = AutofillManager.NO_SESSION;
}
/**
@@ -2082,6 +2091,10 @@ public class AssistStructure implements Parcelable {
ensureData();
}
Log.i(TAG, "Activity: " + mActivityComponent.flattenToShortString());
+ if (mAutofillSessionId != AutofillManager.NO_SESSION) {
+ Log.i(TAG, "Autofill Session ID: " + mAutofillSessionId);
+ }
+
Log.i(TAG, "Sanitize on write: " + mSanitizeOnWrite);
Log.i(TAG, "Flags: " + mFlags);
final int N = getWindowNodeCount();
diff --git a/core/java/android/appwidget/AppWidgetProviderInfo.java b/core/java/android/appwidget/AppWidgetProviderInfo.java
index 53315cce82dd..d148afb32b02 100644
--- a/core/java/android/appwidget/AppWidgetProviderInfo.java
+++ b/core/java/android/appwidget/AppWidgetProviderInfo.java
@@ -400,7 +400,7 @@ public class AppWidgetProviderInfo implements Parcelable {
that.initialLayout = this.initialLayout;
that.initialKeyguardLayout = this.initialKeyguardLayout;
that.configure = this.configure == null ? null : this.configure.clone();
- that.label = this.label == null ? null : this.label.substring(0);
+ that.label = this.label;
that.icon = this.icon;
that.previewImage = this.previewImage;
that.autoAdvanceViewId = this.autoAdvanceViewId;
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index 5b0e85632b90..1b4878c5e89f 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -3276,11 +3276,14 @@ public abstract class PackageManager {
@PermissionInfoFlags int flags) throws NameNotFoundException;
/**
- * Returns true if some permissions are individually controlled
+ * Returns true if some permissions are individually controlled.
+ *
+ * <p>The user usually grants and revokes permission-groups. If this option is set some
+ * dangerous system permissions can be revoked/granted by the user separately from their group.
*
* @hide
*/
- @TestApi
+ @TestApi @SystemApi
public abstract boolean arePermissionsIndividuallyControlled();
/**
diff --git a/core/java/android/inputmethodservice/AbstractInputMethodService.java b/core/java/android/inputmethodservice/AbstractInputMethodService.java
index 185215a5ce75..b0fca006d1e2 100644
--- a/core/java/android/inputmethodservice/AbstractInputMethodService.java
+++ b/core/java/android/inputmethodservice/AbstractInputMethodService.java
@@ -252,4 +252,12 @@ public abstract class AbstractInputMethodService extends Service
return;
}
+ /**
+ * Called when the user took some actions that should be taken into consideration to update the
+ * MRU list for input method rotation.
+ *
+ * @hide
+ */
+ public void notifyUserActionIfNecessary() {
+ }
}
diff --git a/core/java/android/inputmethodservice/InputMethodService.java b/core/java/android/inputmethodservice/InputMethodService.java
index ea7d42ee79a9..2d12b867949a 100644
--- a/core/java/android/inputmethodservice/InputMethodService.java
+++ b/core/java/android/inputmethodservice/InputMethodService.java
@@ -22,6 +22,7 @@ import static android.view.WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACK
import static java.lang.annotation.RetentionPolicy.SOURCE;
+import android.annotation.AnyThread;
import android.annotation.CallSuper;
import android.annotation.DrawableRes;
import android.annotation.IntDef;
@@ -42,7 +43,6 @@ import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
-import android.os.RemoteException;
import android.os.ResultReceiver;
import android.os.SystemClock;
import android.provider.Settings;
@@ -80,8 +80,10 @@ import android.widget.ImageButton;
import android.widget.LinearLayout;
import android.widget.TextView;
+import com.android.internal.annotations.GuardedBy;
import com.android.internal.inputmethod.IInputContentUriToken;
import com.android.internal.inputmethod.IInputMethodPrivilegedOperations;
+import com.android.internal.inputmethod.InputMethodPrivilegedOperations;
import java.io.FileDescriptor;
import java.io.PrintWriter;
@@ -346,7 +348,7 @@ public class InputMethodService extends AbstractInputMethodService {
private static final int BACK_DISPOSITION_MAX = BACK_DISPOSITION_ADJUST_NOTHING;
InputMethodManager mImm;
- private IInputMethodPrivilegedOperations mPrivOps;
+ private InputMethodPrivilegedOperations mPrivOps = new InputMethodPrivilegedOperations();
@UnsupportedAppUsage
int mTheme = 0;
@@ -402,6 +404,10 @@ public class InputMethodService extends AbstractInputMethodService {
@BackDispositionMode
int mBackDisposition;
+ private Object mLock = new Object();
+ @GuardedBy("mLock")
+ private boolean mNotifyUserActionSent;
+
/**
* {@code true} when the previous IME had non-empty inset at the bottom of the screen and we
* have not shown our own window yet. In this situation, the previous inset continues to be
@@ -457,11 +463,8 @@ public class InputMethodService extends AbstractInputMethodService {
@Override
public final void initializeInternal(IBinder token,
IInputMethodPrivilegedOperations privilegedOperations) {
- if (mToken != null) {
- throw new IllegalStateException("initializeInternal() must be called at most once."
- + " privOps=" + privilegedOperations);
- }
- mPrivOps = privilegedOperations;
+ mPrivOps.set(privilegedOperations);
+ mImm.registerInputMethodPrivOps(token, mPrivOps);
attachToken(token);
}
@@ -540,12 +543,7 @@ public class InputMethodService extends AbstractInputMethodService {
public void dispatchStartInputWithToken(@Nullable InputConnection inputConnection,
@NonNull EditorInfo editorInfo, boolean restarting,
@NonNull IBinder startInputToken) {
- try {
- mPrivOps.reportStartInput(startInputToken);
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
-
+ mPrivOps.reportStartInput(startInputToken);
// This needs to be dispatched to interface methods rather than doStartInput().
// Otherwise IME developers who have overridden those interface methods will lose
// notifications.
@@ -602,19 +600,12 @@ public class InputMethodService extends AbstractInputMethodService {
@MainThread
@Override
public void changeInputMethodSubtype(InputMethodSubtype subtype) {
- onCurrentInputMethodSubtypeChanged(subtype);
+ dispatchOnCurrentInputMethodSubtypeChanged(subtype);
}
}
private void setImeWindowStatus(int visibilityFlags, int backDisposition) {
- if (mPrivOps == null) {
- return;
- }
- try {
- mPrivOps.setImeWindowStatus(visibilityFlags, backDisposition);
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
+ mPrivOps.setImeWindowStatus(visibilityFlags, backDisposition);
}
/**
@@ -1016,6 +1007,11 @@ public class InputMethodService extends AbstractInputMethodService {
mSettingsObserver.unregister();
mSettingsObserver = null;
}
+ if (mToken != null) {
+ // This is completely optional, but allows us to show more explicit error messages
+ // when IME developers are doing something unsupported.
+ mImm.unregisterInputMethodPrivOps(mToken);
+ }
}
/**
@@ -1186,7 +1182,7 @@ public class InputMethodService extends AbstractInputMethodService {
* used input method and subtype.
*/
public final boolean switchToPreviousInputMethod() {
- return mImm.switchToPreviousInputMethodInternal(mToken);
+ return mPrivOps.switchToPreviousInputMethod();
}
/**
@@ -1198,7 +1194,7 @@ public class InputMethodService extends AbstractInputMethodService {
* input method and subtype.
*/
public final boolean switchToNextInputMethod(boolean onlyCurrentIme) {
- return mImm.switchToNextInputMethodInternal(mToken, onlyCurrentIme);
+ return mPrivOps.switchToNextInputMethod(onlyCurrentIme);
}
/**
@@ -1211,7 +1207,7 @@ public class InputMethodService extends AbstractInputMethodService {
* between IMEs and subtypes.
*/
public final boolean shouldOfferSwitchingToNextInputMethod() {
- return mImm.shouldOfferSwitchingToNextInputMethodInternal(mToken);
+ return mPrivOps.shouldOfferSwitchingToNextInputMethod();
}
public boolean getCurrentInputStarted() {
@@ -1223,14 +1219,7 @@ public class InputMethodService extends AbstractInputMethodService {
}
private void reportFullscreenMode() {
- if (mPrivOps == null) {
- return;
- }
- try {
- mPrivOps.reportFullscreenMode(mIsFullscreen);
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
+ mPrivOps.reportFullscreenMode(mIsFullscreen);
}
/**
@@ -1536,12 +1525,12 @@ public class InputMethodService extends AbstractInputMethodService {
public void showStatusIcon(@DrawableRes int iconResId) {
mStatusIcon = iconResId;
- mImm.showStatusIconInternal(mToken, getPackageName(), iconResId);
+ mPrivOps.updateStatusIcon(getPackageName(), iconResId);
}
public void hideStatusIcon() {
mStatusIcon = 0;
- mImm.hideStatusIconInternal(mToken);
+ mPrivOps.updateStatusIcon(null, 0);
}
/**
@@ -1552,7 +1541,7 @@ public class InputMethodService extends AbstractInputMethodService {
* @param id Unique identifier of the new input method to start.
*/
public void switchInputMethod(String id) {
- mImm.setInputMethodInternal(mToken, id);
+ mPrivOps.setInputMethod(id);
}
/**
@@ -1564,7 +1553,7 @@ public class InputMethodService extends AbstractInputMethodService {
* @param subtype The new subtype of the new input method to be switched to.
*/
public final void switchInputMethod(String id, InputMethodSubtype subtype) {
- mImm.setInputMethodAndSubtypeInternal(mToken, id, subtype);
+ mPrivOps.setInputMethodAndSubtype(id, subtype);
}
public void setExtractView(View view) {
@@ -1945,14 +1934,7 @@ public class InputMethodService extends AbstractInputMethodService {
* <p>TODO: We probably need to reconsider how IME should be handled.</p>
*/
private void clearLastInputMethodWindowForTransition() {
- if (mPrivOps == null) {
- return;
- }
- try {
- mPrivOps.clearLastInputMethodWindowForTransition();
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
+ mPrivOps.clearLastInputMethodWindowForTransition();
}
/**
@@ -2162,7 +2144,7 @@ public class InputMethodService extends AbstractInputMethodService {
* @param flags Provides additional operating flags.
*/
public void requestHideSelf(int flags) {
- mImm.hideSoftInputFromInputMethodInternal(mToken, flags);
+ mPrivOps.hideMySoftInput(flags);
}
/**
@@ -2174,7 +2156,7 @@ public class InputMethodService extends AbstractInputMethodService {
* @param flags Provides additional operating flags.
*/
public final void requestShowSelf(int flags) {
- mImm.showSoftInputFromInputMethodInternal(mToken, flags);
+ mPrivOps.showMySoftInput(flags);
}
private boolean handleBack(boolean doIt) {
@@ -2816,6 +2798,13 @@ public class InputMethodService extends AbstractInputMethodService {
}
}
+ private void dispatchOnCurrentInputMethodSubtypeChanged(InputMethodSubtype newSubtype) {
+ synchronized (mLock) {
+ mNotifyUserActionSent = false;
+ }
+ onCurrentInputMethodSubtypeChanged(newSubtype);
+ }
+
// TODO: Handle the subtype change event
/**
* Called when the subtype was changed.
@@ -2872,6 +2861,22 @@ public class InputMethodService extends AbstractInputMethodService {
}
/**
+ * {@inheritDoc}
+ * @hide
+ */
+ @AnyThread
+ @Override
+ public final void notifyUserActionIfNecessary() {
+ synchronized (mLock) {
+ if (mNotifyUserActionSent) {
+ return;
+ }
+ mPrivOps.notifyUserActionAsync();
+ mNotifyUserActionSent = true;
+ }
+ }
+
+ /**
* Allow the receiver of {@link InputContentInfo} to obtain a temporary read-only access
* permission to the content.
*
@@ -2885,23 +2890,15 @@ public class InputMethodService extends AbstractInputMethodService {
*/
private void exposeContentInternal(@NonNull InputContentInfo inputContentInfo,
@NonNull EditorInfo editorInfo) {
- if (mPrivOps == null) {
- return;
- }
- final IInputContentUriToken uriToken;
final Uri contentUri = inputContentInfo.getContentUri();
- try {
- uriToken = mPrivOps.createInputContentUriToken(contentUri, editorInfo.packageName);
- if (uriToken == null) {
- return;
- }
- } catch (RemoteException e) {
+ final IInputContentUriToken uriToken =
+ mPrivOps.createInputContentUriToken(contentUri, editorInfo.packageName);
+ if (uriToken == null) {
Log.e(TAG, "createInputContentAccessToken failed. contentUri=" + contentUri.toString()
- + " packageName=" + editorInfo.packageName, e);
+ + " packageName=" + editorInfo.packageName);
return;
}
inputContentInfo.setUriToken(uriToken);
- return;
}
private static int mapToImeWindowStatus(boolean isInputViewShown) {
diff --git a/core/java/android/os/Process.java b/core/java/android/os/Process.java
index 7caf0b103534..5cd2ffcbc0a5 100644
--- a/core/java/android/os/Process.java
+++ b/core/java/android/os/Process.java
@@ -16,6 +16,8 @@
package android.os;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.annotation.TestApi;
import android.system.Os;
import android.system.OsConstants;
@@ -475,6 +477,7 @@ public class Process {
* @param instructionSet null-ok the instruction set to use.
* @param appDataDir null-ok the data directory of the app.
* @param invokeWith null-ok the command to invoke with.
+ * @param packageName null-ok the name of the package this process belongs to.
* @param zygoteArgs Additional arguments to supply to the zygote process.
*
* @return An object that describes the result of the attempt to start the process.
@@ -482,36 +485,36 @@ public class Process {
*
* {@hide}
*/
- public static final ProcessStartResult start(final String processClass,
- final String niceName,
- int uid, int gid, int[] gids,
+ public static final ProcessStartResult start(@NonNull final String processClass,
+ @Nullable final String niceName,
+ int uid, int gid, @Nullable int[] gids,
int runtimeFlags, int mountExternal,
int targetSdkVersion,
- String seInfo,
- String abi,
- String instructionSet,
- String appDataDir,
- String invokeWith,
- String packageName,
- String[] zygoteArgs) {
+ @Nullable String seInfo,
+ @NonNull String abi,
+ @Nullable String instructionSet,
+ @Nullable String appDataDir,
+ @Nullable String invokeWith,
+ @Nullable String packageName,
+ @Nullable String[] zygoteArgs) {
return zygoteProcess.start(processClass, niceName, uid, gid, gids,
runtimeFlags, mountExternal, targetSdkVersion, seInfo,
abi, instructionSet, appDataDir, invokeWith, packageName, zygoteArgs);
}
/** @hide */
- public static final ProcessStartResult startWebView(final String processClass,
- final String niceName,
- int uid, int gid, int[] gids,
+ public static final ProcessStartResult startWebView(@NonNull final String processClass,
+ @Nullable final String niceName,
+ int uid, int gid, @Nullable int[] gids,
int runtimeFlags, int mountExternal,
int targetSdkVersion,
- String seInfo,
- String abi,
- String instructionSet,
- String appDataDir,
- String invokeWith,
- String packageName,
- String[] zygoteArgs) {
+ @Nullable String seInfo,
+ @NonNull String abi,
+ @Nullable String instructionSet,
+ @Nullable String appDataDir,
+ @Nullable String invokeWith,
+ @Nullable String packageName,
+ @Nullable String[] zygoteArgs) {
return WebViewZygote.getProcess().start(processClass, niceName, uid, gid, gids,
runtimeFlags, mountExternal, targetSdkVersion, seInfo,
abi, instructionSet, appDataDir, invokeWith, packageName, zygoteArgs);
diff --git a/core/java/android/os/StatsLogEventWrapper.java b/core/java/android/os/StatsLogEventWrapper.java
index 7b3ea57ba0e9..b13bcac699ed 100644
--- a/core/java/android/os/StatsLogEventWrapper.java
+++ b/core/java/android/os/StatsLogEventWrapper.java
@@ -127,6 +127,15 @@ public final class StatsLogEventWrapper implements Parcelable {
}
/**
+ * Adds a boolean by adding either a 1 or 0 to the output.
+ */
+ public void writeBoolean(boolean val) {
+ int toWrite = val ? 1 : 0;
+ mStorage.write(EVENT_TYPE_INT);
+ write4Bytes(toWrite);
+ }
+
+ /**
* Writes the stored fields to a byte array. Will first write a new-line character to denote
* END_LIST before writing contents to byte array.
*/
diff --git a/core/java/android/os/ZygoteProcess.java b/core/java/android/os/ZygoteProcess.java
index 732d3778ec6d..99181acb03c7 100644
--- a/core/java/android/os/ZygoteProcess.java
+++ b/core/java/android/os/ZygoteProcess.java
@@ -16,6 +16,8 @@
package android.os;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.net.LocalSocket;
import android.net.LocalSocketAddress;
import android.util.Log;
@@ -212,23 +214,24 @@ public class ZygoteProcess {
* @param instructionSet null-ok the instruction set to use.
* @param appDataDir null-ok the data directory of the app.
* @param invokeWith null-ok the command to invoke with.
+ * @param packageName null-ok the name of the package this process belongs to.
* @param zygoteArgs Additional arguments to supply to the zygote process.
*
* @return An object that describes the result of the attempt to start the process.
* @throws RuntimeException on fatal start failure
*/
- public final Process.ProcessStartResult start(final String processClass,
+ public final Process.ProcessStartResult start(@NonNull final String processClass,
final String niceName,
- int uid, int gid, int[] gids,
+ int uid, int gid, @Nullable int[] gids,
int runtimeFlags, int mountExternal,
int targetSdkVersion,
- String seInfo,
- String abi,
- String instructionSet,
- String appDataDir,
- String invokeWith,
- String packageName,
- String[] zygoteArgs) {
+ @Nullable String seInfo,
+ @NonNull String abi,
+ @Nullable String instructionSet,
+ @Nullable String appDataDir,
+ @Nullable String invokeWith,
+ @Nullable String packageName,
+ @Nullable String[] zygoteArgs) {
try {
return startViaZygote(processClass, niceName, uid, gid, gids,
runtimeFlags, mountExternal, targetSdkVersion, seInfo,
@@ -351,24 +354,25 @@ public class ZygoteProcess {
* @param appDataDir null-ok the data directory of the app.
* @param startChildZygote Start a sub-zygote. This creates a new zygote process
* that has its state cloned from this zygote process.
+ * @param packageName null-ok the name of the package this process belongs to.
* @param extraArgs Additional arguments to supply to the zygote process.
* @return An object that describes the result of the attempt to start the process.
* @throws ZygoteStartFailedEx if process start failed for any reason
*/
- private Process.ProcessStartResult startViaZygote(final String processClass,
- final String niceName,
+ private Process.ProcessStartResult startViaZygote(@NonNull final String processClass,
+ @Nullable final String niceName,
final int uid, final int gid,
- final int[] gids,
+ @Nullable final int[] gids,
int runtimeFlags, int mountExternal,
int targetSdkVersion,
- String seInfo,
- String abi,
- String instructionSet,
- String appDataDir,
- String invokeWith,
+ @Nullable String seInfo,
+ @NonNull String abi,
+ @Nullable String instructionSet,
+ @Nullable String appDataDir,
+ @Nullable String invokeWith,
boolean startChildZygote,
- String packageName,
- String[] extraArgs)
+ @Nullable String packageName,
+ @Nullable String[] extraArgs)
throws ZygoteStartFailedEx {
ArrayList<String> argsForZygote = new ArrayList<String>();
diff --git a/core/java/android/preference/SeekBarVolumizer.java b/core/java/android/preference/SeekBarVolumizer.java
index e8daf2120151..a871425518e7 100644
--- a/core/java/android/preference/SeekBarVolumizer.java
+++ b/core/java/android/preference/SeekBarVolumizer.java
@@ -104,7 +104,7 @@ public class SeekBarVolumizer implements OnSeekBarChangeListener, Handler.Callba
@UnsupportedAppUsage
public SeekBarVolumizer(Context context, int streamType, Uri defaultUri, Callback callback) {
- this(context, streamType, defaultUri, callback, true /* playSample */);
+ this(context, streamType, defaultUri, callback, false /* playSample */);
}
public SeekBarVolumizer(
diff --git a/core/java/android/service/autofill/CharSequenceTransformation.java b/core/java/android/service/autofill/CharSequenceTransformation.java
index f52ac8505289..fa6bd65c0fd4 100644
--- a/core/java/android/service/autofill/CharSequenceTransformation.java
+++ b/core/java/android/service/autofill/CharSequenceTransformation.java
@@ -78,7 +78,7 @@ public final class CharSequenceTransformation extends InternalTransformation imp
int childViewId) throws Exception {
final StringBuilder converted = new StringBuilder();
final int size = mFields.size();
- if (sDebug) Log.d(TAG, size + " multiple fields on id " + childViewId);
+ if (sDebug) Log.d(TAG, size + " fields on id " + childViewId);
for (Entry<AutofillId, Pair<Pattern, String>> entry : mFields.entrySet()) {
final AutofillId id = entry.getKey();
final Pair<Pattern, String> field = entry.getValue();
diff --git a/core/java/android/service/notification/NotificationAssistantService.java b/core/java/android/service/notification/NotificationAssistantService.java
index 3b820ca1e165..26240c572898 100644
--- a/core/java/android/service/notification/NotificationAssistantService.java
+++ b/core/java/android/service/notification/NotificationAssistantService.java
@@ -52,6 +52,9 @@ import java.util.List;
* {@link #onNotificationEnqueued(StatusBarNotification)} will only be called for notifications
* sent to the current user, and {@link Adjustment adjuments} will only be accepted for the
* current user.
+ * <p>
+ * All callbacks are called on the main thread.
+ * </p>
*
* @hide
*/
diff --git a/core/java/android/service/notification/NotificationListenerService.java b/core/java/android/service/notification/NotificationListenerService.java
index 1b588f470971..d9ed2aafc9cd 100644
--- a/core/java/android/service/notification/NotificationListenerService.java
+++ b/core/java/android/service/notification/NotificationListenerService.java
@@ -91,6 +91,10 @@ import java.util.List;
* notification listeners running in a work profile. A
* {@link android.app.admin.DevicePolicyManager} might block notifications originating from a work
* profile.</p>
+ * <p>
+ * From {@link Build.VERSION_CODES#N} onward all callbacks are called on the main thread. Prior
+ * to N, there is no guarantee on what thread the callback will happen.
+ * </p>
*/
public abstract class NotificationListenerService extends Service {
diff --git a/core/java/android/service/notification/StatusBarNotification.java b/core/java/android/service/notification/StatusBarNotification.java
index dd97d524d829..84826e0f6824 100644
--- a/core/java/android/service/notification/StatusBarNotification.java
+++ b/core/java/android/service/notification/StatusBarNotification.java
@@ -18,7 +18,7 @@ package android.service.notification;
import android.annotation.UnsupportedAppUsage;
import android.app.Notification;
-import android.app.NotificationChannel;
+import android.app.NotificationManager;
import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
@@ -261,7 +261,7 @@ public class StatusBarNotification implements Parcelable {
return this.user.getIdentifier();
}
- /** The package of the app that posted the notification. */
+ /** The package that the notification belongs to. */
public String getPackageName() {
return pkg;
}
@@ -277,14 +277,18 @@ public class StatusBarNotification implements Parcelable {
return tag;
}
- /** The notifying app's calling uid. @hide */
- @UnsupportedAppUsage
+ /**
+ * The notifying app's ({@link #getPackageName()}'s) uid.
+ */
public int getUid() {
return uid;
}
- /** The package used for AppOps tracking. @hide */
- @UnsupportedAppUsage
+ /** The package that posted the notification.
+ *<p>
+ * Might be different from {@link #getPackageName()} if the app owning the notification has
+ * a {@link NotificationManager#setNotificationDelegate(String) notification delegate}.
+ */
public String getOpPkg() {
return opPkg;
}
diff --git a/core/java/android/text/FontConfig.java b/core/java/android/text/FontConfig.java
index 9e0fee337bc7..19c55d5f497d 100644
--- a/core/java/android/text/FontConfig.java
+++ b/core/java/android/text/FontConfig.java
@@ -181,7 +181,8 @@ public final class FontConfig {
public static final class Family {
private final @NonNull String mName;
private final @NonNull Font[] mFonts;
- private final @NonNull String[] mLanguages;
+ // Comma separated BCP47 complient locale strings
+ private final @NonNull String mLanguages;
/** @hide */
@Retention(SOURCE)
@@ -219,7 +220,7 @@ public final class FontConfig {
// See frameworks/minikin/include/minikin/FontFamily.h
private final @Variant int mVariant;
- public Family(@NonNull String name, @NonNull Font[] fonts, @NonNull String[] languages,
+ public Family(@NonNull String name, @NonNull Font[] fonts, @NonNull String languages,
@Variant int variant) {
mName = name;
mFonts = fonts;
@@ -244,9 +245,9 @@ public final class FontConfig {
}
/**
- * Returns the languages for this family. May be null.
+ * Returns the comma separated BCP47 complient languages for this family. May be null.
*/
- public @Nullable String[] getLanguages() {
+ public @NonNull String getLanguages() {
return mLanguages;
}
diff --git a/core/java/android/text/Hyphenator.java b/core/java/android/text/Hyphenator.java
index 4f1488e1029f..e4200ac0bc6c 100644
--- a/core/java/android/text/Hyphenator.java
+++ b/core/java/android/text/Hyphenator.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2015 The Android Open Source Project
+ * Copyright (C) 2018 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -16,15 +16,145 @@
package android.text;
+import android.annotation.IntDef;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
/**
- * Hyphenator just initializes the native implementation of automatic hyphenation,
- * in essence finding valid hyphenation opportunities in a word.
+ * Provides constants and pack/unpack methods for the HyphenEdit.
+ *
+ * Hyphenator provides constant values for start of line and end of line modification.
+ * For example, by passing {@link #END_HYPHEN_EDIT_INSERT_HYPHEN} like as follows, HYPHEN(U+2010)
+ * character is appended at the end of line.
+ *
+ * <pre>
+ * <code>
+ * Paint paint = new Paint();
+ * paint.setHyphenEdit(Hyphenator.packHyphenEdit(
+ * Hyphenator.START_HYPHEN_EDIT_NO_EDIT,
+ * Hyphenator.END_HYPHEN_EDIT_INSERT_HYPHEN));
+ * paint.measureText("abc", 0, 3); // Returns the width of "abc‐"
+ * Canvas.drawText("abc", 0, 3, 0f, 0f, paint); // Draws "abc‐"
+ * </code>
+ * </pre>
*
- * @hide
+ * @see android.graphics.Paint#setHyphenEdit(int)
*/
public class Hyphenator {
+ private Hyphenator() {}
+
+ /** @hide */
+ @IntDef(prefix = { "START_HYPHEN_EDIT_" }, value = {
+ START_HYPHEN_EDIT_NO_EDIT,
+ START_HYPHEN_EDIT_INSERT_HYPHEN,
+ START_HYPHEN_EDIT_INSERT_ZWJ
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface StartHyphenEdit {}
+
+ /**
+ * An integer representing the starting of the line has no modification for hyphenation.
+ */
+ public static final int START_HYPHEN_EDIT_NO_EDIT = 0x00;
+
+ /**
+ * An integer representing the starting of the line has normal hyphen character (U+002D).
+ */
+ public static final int START_HYPHEN_EDIT_INSERT_HYPHEN = 0x01;
+
+ /**
+ * An integer representing the starting of the line has Zero-Width-Joiner (U+200D).
+ */
+ public static final int START_HYPHEN_EDIT_INSERT_ZWJ = 0x02;
+
+ /** @hide */
+ @IntDef(prefix = { "END_HYPHEN_EDIT_" }, value = {
+ END_HYPHEN_EDIT_NO_EDIT,
+ END_HYPHEN_EDIT_REPLACE_WITH_HYPHEN,
+ END_HYPHEN_EDIT_INSERT_HYPHEN,
+ END_HYPHEN_EDIT_INSERT_ARMENIAN_HYPHEN,
+ END_HYPHEN_EDIT_INSERT_MAQAF,
+ END_HYPHEN_EDIT_INSERT_UCAS_HYPHEN,
+ END_HYPHEN_EDIT_INSERT_ZWJ_AND_HYPHEN
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface EndHyphenEdit {}
+
+ /**
+ * An integer representing the end of the line has no modification for hyphenation.
+ */
+ public static final int END_HYPHEN_EDIT_NO_EDIT = 0x00;
+
+ /**
+ * An integer representing the character at the end of the line is replaced with hyphen
+ * character (U+002D).
+ */
+ public static final int END_HYPHEN_EDIT_REPLACE_WITH_HYPHEN = 0x01;
+
+ /**
+ * An integer representing the end of the line has normal hyphen character (U+002D).
+ */
+ public static final int END_HYPHEN_EDIT_INSERT_HYPHEN = 0x02;
+
+ /**
+ * An integer representing the end of the line has Armentian hyphen (U+058A).
+ */
+ public static final int END_HYPHEN_EDIT_INSERT_ARMENIAN_HYPHEN = 0x03;
+
+ /**
+ * An integer representing the end of the line has maqaf (Hebrew hyphen, U+05BE).
+ */
+ public static final int END_HYPHEN_EDIT_INSERT_MAQAF = 0x04;
+
+ /**
+ * An integer representing the end of the line has Canadian Syllabics hyphen (U+1400).
+ */
+ public static final int END_HYPHEN_EDIT_INSERT_UCAS_HYPHEN = 0x05;
+
+ /**
+ * An integer representing the end of the line has Zero-Width-Joiner (U+200D) followed by normal
+ * hyphen character (U+002D).
+ */
+ public static final int END_HYPHEN_EDIT_INSERT_ZWJ_AND_HYPHEN = 0x06;
+
+ // Following three constants are used for packing start hyphen edit and end hyphen edit into
+ // single integer. Following encodings must be the same as the minikin's one.
+ // See frameworks/minikin/include/Hyphenator.h for more details.
+ private static final int END_HYPHEN_EDIT_MASK = 0x07; // 0b00111
+ private static final int START_HYPHEN_EDIT_MASK = 0x18; // 0b11000
+ private static final int START_HYPHEN_EDIT_SHIFT = 0x03;
+
+ /**
+ * Extract start hyphen edit from packed value.
+ */
+ public static @StartHyphenEdit int unpackStartHyphenEdit(int hyphenEdit) {
+ return (hyphenEdit & START_HYPHEN_EDIT_MASK) >> START_HYPHEN_EDIT_SHIFT;
+ }
+
+ /**
+ * Extract end hyphen edit from packed value.
+ */
+ public static @EndHyphenEdit int unpackEndHyphenEdit(int hyphenEdit) {
+ return hyphenEdit & END_HYPHEN_EDIT_MASK;
+ }
+
+ /**
+ * Pack the start hyphen edit and end hyphen edit into single integer.
+ */
+ public static int packHyphenEdit(@StartHyphenEdit int startHyphenEdit,
+ @EndHyphenEdit int endHyphenEdit) {
+ return ((startHyphenEdit << START_HYPHEN_EDIT_SHIFT) & START_HYPHEN_EDIT_MASK)
+ | (endHyphenEdit & END_HYPHEN_EDIT_MASK);
+ }
+
+
+ /**
+ * @hide
+ */
public static void init() {
nInit();
}
+
private static native void nInit();
}
diff --git a/core/java/android/text/StaticLayout.java b/core/java/android/text/StaticLayout.java
index 128f860d4838..5adb1cad4ef2 100644
--- a/core/java/android/text/StaticLayout.java
+++ b/core/java/android/text/StaticLayout.java
@@ -1216,11 +1216,19 @@ public class StaticLayout extends Layout {
}
/**
+ * Returns the packed hyphen edit value for this line.
+ *
+ * You can extract start hyphen edit and end hyphen edit by using
+ * {@link Hyphenator#unpackStartHyphenEdit(int)} and
+ * {@link Hyphenator#unpackEndHyphenEdit(int)}.
+ *
+ * @param lineNumber a line number
+ * @return A packed hyphen edit value.
* @hide
*/
@Override
- public int getHyphen(int line) {
- return mLines[mColumns * line + HYPHEN] & HYPHEN_MASK;
+ public int getHyphen(int lineNumber) {
+ return mLines[mColumns * lineNumber + HYPHEN] & HYPHEN_MASK;
}
/**
diff --git a/core/java/android/text/TextLine.java b/core/java/android/text/TextLine.java
index 9667b10683a8..bf2d600456bc 100644
--- a/core/java/android/text/TextLine.java
+++ b/core/java/android/text/TextLine.java
@@ -1053,13 +1053,16 @@ public class TextLine {
return runIsRtl ? -ret : ret;
}
- private int adjustHyphenEdit(int start, int limit, int hyphenEdit) {
- int result = hyphenEdit;
+ private int adjustHyphenEdit(int start, int limit, int packedHyphenEdit) {
+ int result = packedHyphenEdit;
// Only draw hyphens on first or last run in line. Disable them otherwise.
if (start > 0) { // not the first run
- result &= ~Paint.HYPHENEDIT_MASK_START_OF_LINE;
+ result = Hyphenator.packHyphenEdit(Hyphenator.START_HYPHEN_EDIT_NO_EDIT,
+ Hyphenator.unpackEndHyphenEdit(packedHyphenEdit));
}
if (limit < mLen) { // not the last run
+ result = Hyphenator.packHyphenEdit(Hyphenator.unpackStartHyphenEdit(packedHyphenEdit),
+ Hyphenator.END_HYPHEN_EDIT_NO_EDIT);
result &= ~Paint.HYPHENEDIT_MASK_END_OF_LINE;
}
return result;
diff --git a/core/java/android/transition/Fade.java b/core/java/android/transition/Fade.java
index 38b89dc4193f..41d80fce2a6e 100644
--- a/core/java/android/transition/Fade.java
+++ b/core/java/android/transition/Fade.java
@@ -94,7 +94,7 @@ public class Fade extends Visibility {
* @param fadingMode The behavior of this transition, a combination of
* {@link #IN} and {@link #OUT}.
*/
- public Fade(int fadingMode) {
+ public Fade(@VisibilityMode int fadingMode) {
setMode(fadingMode);
}
diff --git a/core/java/android/transition/Slide.java b/core/java/android/transition/Slide.java
index 9cf321014ff8..14a513b07dc8 100644
--- a/core/java/android/transition/Slide.java
+++ b/core/java/android/transition/Slide.java
@@ -147,7 +147,7 @@ public class Slide extends Visibility {
/**
* Constructor using the provided slide edge direction.
*/
- public Slide(int slideEdge) {
+ public Slide(@GravityFlag int slideEdge) {
setSlideEdge(slideEdge);
}
diff --git a/core/java/android/transition/Visibility.java b/core/java/android/transition/Visibility.java
index 77c652ecf5f9..319f080bbe63 100644
--- a/core/java/android/transition/Visibility.java
+++ b/core/java/android/transition/Visibility.java
@@ -52,9 +52,11 @@ public abstract class Visibility extends Transition {
/** @hide */
@Retention(RetentionPolicy.SOURCE)
- @IntDef(flag = true, prefix = { "MODE_" }, value = {
+ @IntDef(flag = true, value = {
MODE_IN,
- MODE_OUT
+ MODE_OUT,
+ Fade.IN,
+ Fade.OUT
})
@interface VisibilityMode {}
diff --git a/core/java/android/util/TypedValue.java b/core/java/android/util/TypedValue.java
index 964017396bbd..ea4464daf1e2 100644
--- a/core/java/android/util/TypedValue.java
+++ b/core/java/android/util/TypedValue.java
@@ -232,7 +232,9 @@ public class TypedValue {
};
/**
- * Determine if a value is a color by comparing {@link type} to {@link #TYPE_FIRST_COLOR_INT}
+ * Determine if a value is a color.
+ *
+ * This works by comparing {@link #type} to {@link #TYPE_FIRST_COLOR_INT}
* and {@link #TYPE_LAST_COLOR_INT}.
*
* @return true if this value is a color
diff --git a/core/java/android/view/SurfaceView.java b/core/java/android/view/SurfaceView.java
index 274dd2f8bcee..514a11ebf713 100644
--- a/core/java/android/view/SurfaceView.java
+++ b/core/java/android/view/SurfaceView.java
@@ -545,7 +545,8 @@ public class SurfaceView extends View implements ViewRootImpl.WindowStoppedCallb
mScreenRect.offset(surfaceInsets.left, surfaceInsets.top);
if (creating) {
- mSurfaceSession = new SurfaceSession(viewRoot.mSurface);
+ viewRoot.createBoundsSurface(mSubLayer);
+ mSurfaceSession = new SurfaceSession(viewRoot.mBoundsSurface);
mDeferredDestroySurfaceControl = mSurfaceControl;
updateOpaqueFlag();
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 9bc53ed5a851..4a619062765f 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -8251,7 +8251,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
if (mAutofillId == null) {
// The autofill id needs to be unique, but its value doesn't matter,
// so it's better to reuse the accessibility id to save space.
- mAutofillId = new AutofillId(getAutofillViewId());
+ mAutofillId = new AutofillId(getAutofillManager(), getAutofillViewId());
}
return mAutofillId;
}
@@ -8313,11 +8313,15 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
// Ignore reset because it was never explicitly set before.
return;
}
- mAutofillId = id;
if (id != null) {
+ // Must create a new id so the session id is preserved.
+ final int oldSessionId = mAutofillId.getSessionId();
mAutofillViewId = id.getViewId();
+ mAutofillId = new AutofillId(mAutofillViewId);
+ mAutofillId.setSessionId(oldSessionId);
mPrivateFlags3 |= PFLAG3_AUTOFILLID_EXPLICITLY_SET;
} else {
+ mAutofillId = null;
mAutofillViewId = NO_ID;
mPrivateFlags3 &= ~PFLAG3_AUTOFILLID_EXPLICITLY_SET;
}
@@ -8607,8 +8611,11 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
structure.setContextClickable(true);
}
if (forAutofill) {
- structure.setAutofillId(new AutofillId(getAutofillId(),
- AccessibilityNodeInfo.getVirtualDescendantId(info.getSourceNodeId())));
+ final AutofillId autofillId = new AutofillId(getAutofillId(),
+ AccessibilityNodeInfo.getVirtualDescendantId(info.getSourceNodeId()));
+ final AutofillManager afm = getAutofillManager();
+ autofillId.setSessionId(afm == null ? AutofillManager.NO_SESSION : afm.getSessionId());
+ structure.setAutofillId(autofillId);
}
CharSequence cname = info.getClassName();
structure.setClassName(cname != null ? cname.toString() : null);
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 1351f6f1ef26..16d202b8af1d 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -81,6 +81,7 @@ import android.util.SparseArray;
import android.util.TimeUtils;
import android.util.TypedValue;
import android.view.Surface.OutOfResourcesException;
+import android.view.SurfaceControl.Transaction;
import android.view.ThreadedRenderer.FrameDrawingCallback;
import android.view.View.AttachInfo;
import android.view.View.FocusDirection;
@@ -342,6 +343,7 @@ public final class ViewRootImpl implements ViewParent,
final Rect mTempRect; // used in the transaction to not thrash the heap.
final Rect mVisRect; // used to retrieve visible rect of focused view.
+ private final Rect mTempBoundsRect = new Rect(); // used to set the size of the bounds surface.
// This is used to reduce the race between window focus changes being dispatched from
// the window manager and input events coming through the input system.
@@ -404,6 +406,18 @@ public final class ViewRootImpl implements ViewParent,
@UnsupportedAppUsage
public final Surface mSurface = new Surface();
+ /**
+ * Child surface of {@code mSurface} with the same bounds as its parent, and crop bounds
+ * are set to the parent's bounds adjusted for surface insets. This surface is created when
+ * {@link ViewRootImpl#createBoundsSurface(int)} is called.
+ * By parenting to this bounds surface, child surfaces can ensure they do not draw into the
+ * surface inset regions set by the parent window.
+ */
+ public final Surface mBoundsSurface = new Surface();
+ private SurfaceSession mSurfaceSession;
+ private SurfaceControl mBoundsSurfaceControl;
+ private final Transaction mTransaction = new Transaction();
+
@UnsupportedAppUsage
boolean mAdded;
boolean mAddedTouchMode;
@@ -1390,12 +1404,79 @@ public final class ViewRootImpl implements ViewParent,
}
if (mStopped) {
- mSurface.release();
+ destroySurface();
}
}
}
/**
+ * Creates a surface as a child of {@code mSurface} with the same bounds as its parent and
+ * crop bounds set to the parent's bounds adjusted for surface insets.
+ *
+ * @param zOrderLayer Z order relative to the parent surface.
+ */
+ public void createBoundsSurface(int zOrderLayer) {
+ if (mSurfaceSession == null) {
+ mSurfaceSession = new SurfaceSession(mSurface);
+ }
+ if (mBoundsSurfaceControl != null && mBoundsSurface.isValid()) {
+ return; // surface control for bounds surface already exists.
+ }
+
+ mBoundsSurfaceControl = new SurfaceControl.Builder(mSurfaceSession)
+ .setName("Bounds for - " + getTitle().toString())
+ .setSize(mWidth, mHeight)
+ .build();
+
+ setBoundsSurfaceSizeAndCrop();
+ mTransaction.setLayer(mBoundsSurfaceControl, zOrderLayer)
+ .show(mBoundsSurfaceControl)
+ .apply();
+ mBoundsSurface.copyFrom(mBoundsSurfaceControl);
+ }
+
+ private void setBoundsSurfaceSizeAndCrop() {
+ // mWinFrame is already adjusted for surface insets. So offset it and use it as
+ // the cropping bounds.
+ mTempBoundsRect.set(mWinFrame);
+ mTempBoundsRect.offsetTo(mWindowAttributes.surfaceInsets.left,
+ mWindowAttributes.surfaceInsets.top);
+ mTransaction.setWindowCrop(mBoundsSurfaceControl, mTempBoundsRect);
+
+ // Expand the bounds by the surface insets to get the size of surface.
+ mTempBoundsRect.inset(-mWindowAttributes.surfaceInsets.left,
+ -mWindowAttributes.surfaceInsets.top,
+ -mWindowAttributes.surfaceInsets.right,
+ -mWindowAttributes.surfaceInsets.bottom);
+ mTransaction.setSize(mBoundsSurfaceControl, mTempBoundsRect.width(),
+ mTempBoundsRect.height());
+ }
+
+ /**
+ * Called after window layout to update the bounds surface. If the surface insets have
+ * changed or the surface has resized, update the bounds surface.
+ */
+ private void updateBoundsSurface() {
+ if (mBoundsSurfaceControl != null && mSurface.isValid()) {
+ setBoundsSurfaceSizeAndCrop();
+ mTransaction.deferTransactionUntilSurface(mBoundsSurfaceControl,
+ mSurface, mSurface.getNextFrameNumber())
+ .apply();
+ }
+ }
+
+ private void destroySurface() {
+ mSurface.release();
+ mSurfaceSession = null;
+
+ if (mBoundsSurfaceControl != null) {
+ mBoundsSurfaceControl.destroy();
+ mBoundsSurface.release();
+ mBoundsSurfaceControl = null;
+ }
+ }
+
+ /**
* Block the input events during an Activity Transition. The KEYCODE_BACK event is allowed
* through to allow quick reversal of the Activity Transition.
*
@@ -2350,6 +2431,10 @@ public final class ViewRootImpl implements ViewParent,
maybeHandleWindowMove(frame);
}
+ if (surfaceChanged) {
+ updateBoundsSurface();
+ }
+
final boolean didLayout = layoutRequested && (!mStopped || mReportNextDraw);
boolean triggerGlobalLayoutListener = didLayout
|| mAttachInfo.mRecomputeGlobalAttributes;
@@ -3860,7 +3945,7 @@ public final class ViewRootImpl implements ViewParent,
mView = null;
mAttachInfo.mRootView = null;
- mSurface.release();
+ destroySurface();
if (mInputQueueCallback != null && mInputQueue != null) {
mInputQueueCallback.onInputQueueDestroyed(mInputQueue);
@@ -6809,7 +6894,7 @@ public final class ViewRootImpl implements ViewParent,
}
}
- mSurface.release();
+ destroySurface();
}
}
diff --git a/core/java/android/view/autofill/AutofillId.java b/core/java/android/view/autofill/AutofillId.java
index cb1d89c54d9a..5ae91a543a52 100644
--- a/core/java/android/view/autofill/AutofillId.java
+++ b/core/java/android/view/autofill/AutofillId.java
@@ -15,6 +15,10 @@
*/
package android.view.autofill;
+import static android.view.autofill.Helper.sDebug;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.annotation.TestApi;
import android.os.Parcel;
import android.os.Parcelable;
@@ -28,6 +32,7 @@ public final class AutofillId implements Parcelable {
private final int mViewId;
private final boolean mVirtual;
private final int mVirtualId;
+ private int mSessionId = AutofillManager.NO_SESSION;
/** @hide */
@TestApi
@@ -38,18 +43,26 @@ public final class AutofillId implements Parcelable {
}
/** @hide */
+ // NOTE: caller must set sessionId
@TestApi
- public AutofillId(AutofillId parent, int virtualChildId) {
+ public AutofillId(@NonNull AutofillId parent, int virtualChildId) {
mVirtual = true;
mViewId = parent.mViewId;
mVirtualId = virtualChildId;
}
/** @hide */
- public AutofillId(int parentId, int virtualChildId) {
+ public AutofillId(int sessionId, int parentId, int virtualChildId) {
mVirtual = true;
mViewId = parentId;
mVirtualId = virtualChildId;
+ mSessionId = sessionId;
+ }
+
+ /** @hide */
+ public AutofillId(@Nullable AutofillManager afm, int id) {
+ this(id);
+ mSessionId = afm == null ? AutofillManager.NO_SESSION : afm.getSessionId();
}
/** @hide */
@@ -67,6 +80,16 @@ public final class AutofillId implements Parcelable {
return mVirtual;
}
+ /** @hide */
+ public int getSessionId() {
+ return mSessionId;
+ }
+
+ /** @hide */
+ public void setSessionId(int sessionId) {
+ this.mSessionId = sessionId;
+ }
+
/////////////////////////////////
// Object "contract" methods. //
/////////////////////////////////
@@ -77,6 +100,7 @@ public final class AutofillId implements Parcelable {
int result = 1;
result = prime * result + mViewId;
result = prime * result + mVirtualId;
+ result = prime * result + mSessionId;
return result;
}
@@ -88,6 +112,7 @@ public final class AutofillId implements Parcelable {
final AutofillId other = (AutofillId) obj;
if (mViewId != other.mViewId) return false;
if (mVirtualId != other.mVirtualId) return false;
+ if (mSessionId != other.mSessionId) return false;
return true;
}
@@ -97,6 +122,9 @@ public final class AutofillId implements Parcelable {
if (mVirtual) {
builder.append(':').append(mVirtualId);
}
+ if (mSessionId != AutofillManager.NO_SESSION && sDebug) {
+ builder.append('<').append(mSessionId).append('>');
+ }
return builder.toString();
}
@@ -110,12 +138,14 @@ public final class AutofillId implements Parcelable {
parcel.writeInt(mViewId);
parcel.writeInt(mVirtual ? 1 : 0);
parcel.writeInt(mVirtualId);
+ parcel.writeInt(mSessionId);
}
private AutofillId(Parcel parcel) {
mViewId = parcel.readInt();
mVirtual = parcel.readInt() == 1;
mVirtualId = parcel.readInt();
+ mSessionId = parcel.readInt();
}
public static final Parcelable.Creator<AutofillId> CREATOR =
diff --git a/core/java/android/view/autofill/AutofillManager.java b/core/java/android/view/autofill/AutofillManager.java
index 9419e93d0066..612888ef7eca 100644
--- a/core/java/android/view/autofill/AutofillManager.java
+++ b/core/java/android/view/autofill/AutofillManager.java
@@ -916,7 +916,7 @@ public final class AutofillManager {
boolean isVisible, boolean virtual) {
synchronized (mLock) {
if (mEnabled && isActiveLocked()) {
- final AutofillId id = virtual ? getAutofillId(view, virtualId)
+ final AutofillId id = virtual ? getAutofillIdLocked(view, virtualId)
: view.getAutofillId();
if (sVerbose) Log.v(TAG, "visibility changed for " + id + ": " + isVisible);
if (!isVisible && mFillableIds != null) {
@@ -976,7 +976,7 @@ public final class AutofillManager {
@GuardedBy("mLock")
private AutofillCallback notifyViewEnteredLocked(View view, int virtualId, Rect bounds,
int flags) {
- final AutofillId id = getAutofillId(view, virtualId);
+ final AutofillId id = getAutofillIdLocked(view, virtualId);
AutofillCallback callback = null;
if (shouldIgnoreViewEnteredLocked(id, flags)) return callback;
@@ -1033,7 +1033,7 @@ public final class AutofillManager {
if (mEnabled && isActiveLocked()) {
// don't notify exited when Activity is already in background
if (!isClientDisablingEnterExitEvent()) {
- final AutofillId id = getAutofillId(view, virtualId);
+ final AutofillId id = getAutofillIdLocked(view, virtualId);
// Update focus on existing session.
updateSessionLocked(id, null, null, ACTION_VIEW_EXITED, 0);
@@ -1116,7 +1116,7 @@ public final class AutofillManager {
return;
}
- final AutofillId id = getAutofillId(view, virtualId);
+ final AutofillId id = getAutofillIdLocked(view, virtualId);
updateSessionLocked(id, null, value, ACTION_VALUE_CHANGED, 0);
}
}
@@ -1137,7 +1137,11 @@ public final class AutofillManager {
* @param virtualId id identifying the virtual child inside the parent view.
*/
public void notifyViewClicked(@NonNull View view, int virtualId) {
- notifyViewClicked(getAutofillId(view, virtualId));
+ final AutofillId id;
+ synchronized (mLock) {
+ id = getAutofillIdLocked(view, virtualId);
+ }
+ notifyViewClicked(id);
}
private void notifyViewClicked(AutofillId id) {
@@ -1534,8 +1538,9 @@ public final class AutofillManager {
return id;
}
- private static AutofillId getAutofillId(View parent, int virtualId) {
- return new AutofillId(parent.getAutofillViewId(), virtualId);
+ @GuardedBy("mLock")
+ private AutofillId getAutofillIdLocked(View parent, int virtualId) {
+ return new AutofillId(mSessionId, parent.getAutofillViewId(), virtualId);
}
@GuardedBy("mLock")
@@ -1566,6 +1571,8 @@ public final class AutofillManager {
mSessionId = receiver.getIntResult();
if (mSessionId != NO_SESSION) {
mState = STATE_ACTIVE;
+ // Need to update the view's autofill id with the session
+ id.setSessionId(mSessionId);
}
client.autofillClientResetableStateAvailable();
} catch (RemoteException e) {
@@ -2210,6 +2217,13 @@ public final class AutofillManager {
return getStateAsString(mState);
}
+ /** @hide */
+ public int getSessionId() {
+ synchronized (mLock) {
+ return mSessionId;
+ }
+ }
+
@NonNull
private static String getStateAsString(int state) {
switch (state) {
diff --git a/core/java/android/view/inputmethod/InputMethodManager.java b/core/java/android/view/inputmethod/InputMethodManager.java
index baac4cd0de9a..c51c5e2173e2 100644
--- a/core/java/android/view/inputmethod/InputMethodManager.java
+++ b/core/java/android/view/inputmethod/InputMethodManager.java
@@ -18,6 +18,7 @@ package android.view.inputmethod;
import static android.Manifest.permission.WRITE_SECURE_SETTINGS;
+import android.annotation.DrawableRes;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.RequiresFeature;
@@ -29,6 +30,7 @@ import android.content.Context;
import android.content.pm.PackageManager;
import android.graphics.Rect;
import android.inputmethodservice.InputMethodService;
+import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
@@ -55,6 +57,8 @@ import android.view.ViewRootImpl;
import android.view.WindowManager.LayoutParams.SoftInputModeFlags;
import android.view.autofill.AutofillManager;
+import com.android.internal.inputmethod.InputMethodPrivilegedOperations;
+import com.android.internal.inputmethod.InputMethodPrivilegedOperationsRegistry;
import com.android.internal.os.SomeArgs;
import com.android.internal.view.IInputConnectionWrapper;
import com.android.internal.view.IInputContext;
@@ -350,28 +354,6 @@ public final class InputMethodManager {
int mCursorCandEnd;
/**
- * Represents an invalid action notification sequence number.
- * {@link com.android.server.InputMethodManagerService} always issues a positive integer for
- * action notification sequence numbers. Thus {@code -1} is guaranteed to be different from any
- * valid sequence number.
- */
- private static final int NOT_AN_ACTION_NOTIFICATION_SEQUENCE_NUMBER = -1;
- /**
- * The next sequence number that is to be sent to
- * {@link com.android.server.InputMethodManagerService} via
- * {@link IInputMethodManager#notifyUserAction(int)} at once when a user action is observed.
- */
- private int mNextUserActionNotificationSequenceNumber =
- NOT_AN_ACTION_NOTIFICATION_SEQUENCE_NUMBER;
-
- /**
- * The last sequence number that is already sent to
- * {@link com.android.server.InputMethodManagerService}.
- */
- private int mLastSentUserActionNotificationSequenceNumber =
- NOT_AN_ACTION_NOTIFICATION_SEQUENCE_NUMBER;
-
- /**
* The instance that has previously been sent to the input method.
*/
private CursorAnchorInfo mCursorAnchorInfo = null;
@@ -405,6 +387,9 @@ public final class InputMethodManager {
final Pool<PendingEvent> mPendingEventPool = new SimplePool<>(20);
final SparseArray<PendingEvent> mPendingEvents = new SparseArray<>(20);
+ private final InputMethodPrivilegedOperationsRegistry mPrivOpsRegistry =
+ new InputMethodPrivilegedOperationsRegistry();
+
// -----------------------------------------------------------
static final int MSG_DUMP = 1;
@@ -414,7 +399,6 @@ public final class InputMethodManager {
static final int MSG_SEND_INPUT_EVENT = 5;
static final int MSG_TIMEOUT_INPUT_EVENT = 6;
static final int MSG_FLUSH_INPUT_EVENT = 7;
- static final int MSG_SET_USER_ACTION_NOTIFICATION_SEQUENCE_NUMBER = 9;
static final int MSG_REPORT_FULLSCREEN_MODE = 10;
private static boolean isAutofillUIShowing(View servedView) {
@@ -551,12 +535,6 @@ public final class InputMethodManager {
finishedInputEvent(msg.arg1, false, false);
return;
}
- case MSG_SET_USER_ACTION_NOTIFICATION_SEQUENCE_NUMBER: {
- synchronized (mH) {
- mNextUserActionNotificationSequenceNumber = msg.arg1;
- }
- return;
- }
case MSG_REPORT_FULLSCREEN_MODE: {
final boolean fullscreen = msg.arg1 != 0;
InputConnection ic = null;
@@ -599,11 +577,6 @@ public final class InputMethodManager {
}
@Override
- protected void onUserAction() {
- mParentInputMethodManager.notifyUserAction();
- }
-
- @Override
public String toString() {
return "ControlledInputConnectionWrapper{"
+ "connection=" + getInputConnection()
@@ -650,12 +623,6 @@ public final class InputMethodManager {
}
@Override
- public void setUserActionNotificationSequenceNumber(int sequenceNumber) {
- mH.obtainMessage(MSG_SET_USER_ACTION_NOTIFICATION_SEQUENCE_NUMBER, sequenceNumber, 0)
- .sendToTarget();
- }
-
- @Override
public void reportFullscreenMode(boolean fullscreen) {
mH.obtainMessage(MSG_REPORT_FULLSCREEN_MODE, fullscreen ? 1 : 0, 0)
.sendToTarget();
@@ -771,19 +738,8 @@ public final class InputMethodManager {
* class are intended for app developers interacting with the IME.
*/
@Deprecated
- public void showStatusIcon(IBinder imeToken, String packageName, int iconId) {
- showStatusIconInternal(imeToken, packageName, iconId);
- }
-
- /**
- * @hide
- */
- public void showStatusIconInternal(IBinder imeToken, String packageName, int iconId) {
- try {
- mService.updateStatusIcon(imeToken, packageName, iconId);
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
+ public void showStatusIcon(IBinder imeToken, String packageName, @DrawableRes int iconId) {
+ mPrivOpsRegistry.get(imeToken).updateStatusIcon(packageName, iconId);
}
/**
@@ -793,18 +749,7 @@ public final class InputMethodManager {
*/
@Deprecated
public void hideStatusIcon(IBinder imeToken) {
- hideStatusIconInternal(imeToken);
- }
-
- /**
- * @hide
- */
- public void hideStatusIconInternal(IBinder imeToken) {
- try {
- mService.updateStatusIcon(imeToken, null, 0);
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
+ mPrivOpsRegistry.get(imeToken).updateStatusIcon(null, 0);
}
/** @hide */
@@ -1370,8 +1315,6 @@ public final class InputMethodManager {
mBindSequence = res.sequence;
mCurMethod = res.method;
mCurId = res.id;
- mNextUserActionNotificationSequenceNumber =
- res.userActionNotificationSequenceNumber;
} else if (res.channel != null && res.channel != mCurChannel) {
res.channel.dispose();
}
@@ -1845,18 +1788,18 @@ public final class InputMethodManager {
*/
@Deprecated
public void setInputMethod(IBinder token, String id) {
- setInputMethodInternal(token, id);
- }
-
- /**
- * @hide
- */
- public void setInputMethodInternal(IBinder token, String id) {
- try {
- mService.setInputMethod(token, id);
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
+ if (token == null) {
+ // Note: null token is allowed for callers that have WRITE_SECURE_SETTINGS permission.
+ // Thus we cannot always rely on mPrivOpsRegistry unfortunately.
+ // TODO(Bug 114488811): Consider deprecating null token rule.
+ try {
+ mService.setInputMethod(token, id);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ return;
}
+ mPrivOpsRegistry.get(token).setInputMethod(id);
}
/**
@@ -1874,19 +1817,18 @@ public final class InputMethodManager {
*/
@Deprecated
public void setInputMethodAndSubtype(IBinder token, String id, InputMethodSubtype subtype) {
- setInputMethodAndSubtypeInternal(token, id, subtype);
- }
-
- /**
- * @hide
- */
- public void setInputMethodAndSubtypeInternal(
- IBinder token, String id, InputMethodSubtype subtype) {
- try {
- mService.setInputMethodAndSubtype(token, id, subtype);
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
+ if (token == null) {
+ // Note: null token is allowed for callers that have WRITE_SECURE_SETTINGS permission.
+ // Thus we cannot always rely on mPrivOpsRegistry unfortunately.
+ // TODO(Bug 114488811): Consider deprecating null token rule.
+ try {
+ mService.setInputMethodAndSubtype(token, id, subtype);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ return;
}
+ mPrivOpsRegistry.get(token).setInputMethodAndSubtype(id, subtype);
}
/**
@@ -1906,18 +1848,7 @@ public final class InputMethodManager {
*/
@Deprecated
public void hideSoftInputFromInputMethod(IBinder token, int flags) {
- hideSoftInputFromInputMethodInternal(token, flags);
- }
-
- /**
- * @hide
- */
- public void hideSoftInputFromInputMethodInternal(IBinder token, int flags) {
- try {
- mService.hideMySoftInput(token, flags);
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
+ mPrivOpsRegistry.get(token).hideMySoftInput(flags);
}
/**
@@ -1938,18 +1869,7 @@ public final class InputMethodManager {
*/
@Deprecated
public void showSoftInputFromInputMethod(IBinder token, int flags) {
- showSoftInputFromInputMethodInternal(token, flags);
- }
-
- /**
- * @hide
- */
- public void showSoftInputFromInputMethodInternal(IBinder token, int flags) {
- try {
- mService.showMySoftInput(token, flags);
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
+ mPrivOpsRegistry.get(token).showMySoftInput(flags);
}
/**
@@ -2147,15 +2067,13 @@ public final class InputMethodManager {
* @hide
*/
public void showInputMethodPicker(boolean showAuxiliarySubtypes) {
- synchronized (mH) {
- try {
- final int mode = showAuxiliarySubtypes ?
- SHOW_IM_PICKER_MODE_INCLUDE_AUXILIARY_SUBTYPES:
- SHOW_IM_PICKER_MODE_EXCLUDE_AUXILIARY_SUBTYPES;
- mService.showInputMethodPickerFromClient(mClient, mode);
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
+ final int mode = showAuxiliarySubtypes
+ ? SHOW_IM_PICKER_MODE_INCLUDE_AUXILIARY_SUBTYPES
+ : SHOW_IM_PICKER_MODE_EXCLUDE_AUXILIARY_SUBTYPES;
+ try {
+ mService.showInputMethodPickerFromClient(mClient, mode);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
}
}
@@ -2193,12 +2111,10 @@ public final class InputMethodManager {
* subtypes of all input methods will be shown.
*/
public void showInputMethodAndSubtypeEnabler(String imiId) {
- synchronized (mH) {
- try {
- mService.showInputMethodAndSubtypeEnablerFromClient(mClient, imiId);
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
+ try {
+ mService.showInputMethodAndSubtypeEnablerFromClient(mClient, imiId);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
}
}
@@ -2223,48 +2139,25 @@ public final class InputMethodManager {
*/
@RequiresPermission(WRITE_SECURE_SETTINGS)
public boolean setCurrentInputMethodSubtype(InputMethodSubtype subtype) {
- synchronized (mH) {
- try {
- return mService.setCurrentInputMethodSubtype(subtype);
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
+ try {
+ return mService.setCurrentInputMethodSubtype(subtype);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
}
}
/**
* Notify that a user took some action with this input method.
+ *
+ * @deprecated Just kept to avoid possible app compat issue.
* @hide
*/
- @UnsupportedAppUsage
+ @Deprecated
+ @UnsupportedAppUsage(trackingBug = 114740982, maxTargetSdk = Build.VERSION_CODES.P)
public void notifyUserAction() {
- synchronized (mH) {
- if (mLastSentUserActionNotificationSequenceNumber ==
- mNextUserActionNotificationSequenceNumber) {
- if (DEBUG) {
- Log.w(TAG, "Ignoring notifyUserAction as it has already been sent."
- + " mLastSentUserActionNotificationSequenceNumber: "
- + mLastSentUserActionNotificationSequenceNumber
- + " mNextUserActionNotificationSequenceNumber: "
- + mNextUserActionNotificationSequenceNumber);
- }
- return;
- }
- try {
- if (DEBUG) {
- Log.w(TAG, "notifyUserAction: "
- + " mLastSentUserActionNotificationSequenceNumber: "
- + mLastSentUserActionNotificationSequenceNumber
- + " mNextUserActionNotificationSequenceNumber: "
- + mNextUserActionNotificationSequenceNumber);
- }
- mService.notifyUserAction(mNextUserActionNotificationSequenceNumber);
- mLastSentUserActionNotificationSequenceNumber =
- mNextUserActionNotificationSequenceNumber;
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
- }
+ Log.w(TAG, "notifyUserAction() is a hidden method, which is now just a stub method"
+ + " that does nothing. Leave comments in b.android.com/114740982 if your "
+ + " application still depends on the previous behavior of this method.");
}
/**
@@ -2313,12 +2206,10 @@ public final class InputMethodManager {
*/
@UnsupportedAppUsage
public int getInputMethodWindowVisibleHeight() {
- synchronized (mH) {
- try {
- return mService.getInputMethodWindowVisibleHeight();
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
+ try {
+ return mService.getInputMethodWindowVisibleHeight();
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
}
}
@@ -2336,20 +2227,17 @@ public final class InputMethodManager {
*/
@Deprecated
public boolean switchToLastInputMethod(IBinder imeToken) {
- return switchToPreviousInputMethodInternal(imeToken);
- }
-
- /**
- * @hide
- */
- public boolean switchToPreviousInputMethodInternal(IBinder imeToken) {
- synchronized (mH) {
+ if (imeToken == null) {
+ // Note: null token is allowed for callers that have WRITE_SECURE_SETTINGS permission.
+ // Thus we cannot always rely on mPrivOpsRegistry unfortunately.
+ // TODO(Bug 114488811): Consider deprecating null token rule.
try {
return mService.switchToPreviousInputMethod(imeToken);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
+ return mPrivOpsRegistry.get(imeToken).switchToPreviousInputMethod();
}
/**
@@ -2367,20 +2255,17 @@ public final class InputMethodManager {
*/
@Deprecated
public boolean switchToNextInputMethod(IBinder imeToken, boolean onlyCurrentIme) {
- return switchToNextInputMethodInternal(imeToken, onlyCurrentIme);
- }
-
- /**
- * @hide
- */
- public boolean switchToNextInputMethodInternal(IBinder imeToken, boolean onlyCurrentIme) {
- synchronized (mH) {
+ if (imeToken == null) {
+ // Note: null token is allowed for callers that have WRITE_SECURE_SETTINGS permission.
+ // Thus we cannot always rely on mPrivOpsRegistry unfortunately.
+ // TODO(Bug 114488811): Consider deprecating null token rule.
try {
return mService.switchToNextInputMethod(imeToken, onlyCurrentIme);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
+ return mPrivOpsRegistry.get(imeToken).switchToNextInputMethod(onlyCurrentIme);
}
/**
@@ -2399,20 +2284,7 @@ public final class InputMethodManager {
*/
@Deprecated
public boolean shouldOfferSwitchingToNextInputMethod(IBinder imeToken) {
- return shouldOfferSwitchingToNextInputMethodInternal(imeToken);
- }
-
- /**
- * @hide
- */
- public boolean shouldOfferSwitchingToNextInputMethodInternal(IBinder imeToken) {
- synchronized (mH) {
- try {
- return mService.shouldOfferSwitchingToNextInputMethod(imeToken);
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
- }
+ return mPrivOpsRegistry.get(imeToken).shouldOfferSwitchingToNextInputMethod();
}
/**
@@ -2441,22 +2313,18 @@ public final class InputMethodManager {
* @param subtypes subtypes will be added as additional subtypes of the current input method.
*/
public void setAdditionalInputMethodSubtypes(String imiId, InputMethodSubtype[] subtypes) {
- synchronized (mH) {
- try {
- mService.setAdditionalInputMethodSubtypes(imiId, subtypes);
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
+ try {
+ mService.setAdditionalInputMethodSubtypes(imiId, subtypes);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
}
}
public InputMethodSubtype getLastInputMethodSubtype() {
- synchronized (mH) {
- try {
- return mService.getLastInputMethodSubtype();
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
+ try {
+ return mService.getLastInputMethodSubtype();
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
}
}
@@ -2490,10 +2358,6 @@ public final class InputMethodManager {
+ " mCursorSelEnd=" + mCursorSelEnd
+ " mCursorCandStart=" + mCursorCandStart
+ " mCursorCandEnd=" + mCursorCandEnd);
- p.println(" mNextUserActionNotificationSequenceNumber="
- + mNextUserActionNotificationSequenceNumber
- + " mLastSentUserActionNotificationSequenceNumber="
- + mLastSentUserActionNotificationSequenceNumber);
}
/**
@@ -2556,4 +2420,34 @@ public final class InputMethodManager {
sb.append(",temporaryDetach=" + view.isTemporarilyDetached());
return sb.toString();
}
+
+ /**
+ * Called by {@link InputMethodService} so that API calls to deprecated ones defined in this
+ * class can be forwarded to {@link InputMethodPrivilegedOperations}.
+ *
+ * <p>Note: this method does not hold strong references to {@code token} and {@code ops}. The
+ * registry entry will be automatically cleared after {@code token} is garbage collected.</p>
+ *
+ * @param token IME token that is associated with {@code ops}
+ * @param ops {@link InputMethodPrivilegedOperations} that is associated with {@code token}
+ * @hide
+ */
+ public void registerInputMethodPrivOps(IBinder token, InputMethodPrivilegedOperations ops) {
+ mPrivOpsRegistry.put(token, ops);
+ }
+
+ /**
+ * Called from {@link InputMethodService#onDestroy()} to make sure that deprecated IME APIs
+ * defined in this class can no longer access to {@link InputMethodPrivilegedOperations}.
+ *
+ * <p>Note: Calling this method is optional, but at least gives more explict error message in
+ * logcat when IME developers are doing something unsupported (e.g. trying to call IME APIs
+ * after {@link InputMethodService#onDestroy()}).</p>
+ *
+ * @param token IME token to be removed.
+ * @hide
+ */
+ public void unregisterInputMethodPrivOps(IBinder token) {
+ mPrivOpsRegistry.remove(token);
+ }
}
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index 31b1d9924e05..0645a162f377 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -63,6 +63,7 @@ import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.Typeface;
import android.graphics.drawable.Drawable;
+import android.graphics.fonts.Font;
import android.graphics.fonts.FontVariationAxis;
import android.icu.text.DecimalFormatSymbols;
import android.os.AsyncTask;
@@ -2068,7 +2069,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
*/
private void setTypefaceFromAttrs(@Nullable Typeface typeface, @Nullable String familyName,
@XMLTypefaceAttr int typefaceIndex, @Typeface.Style int style,
- @IntRange(from = -1, to = Typeface.MAX_WEIGHT) int weight) {
+ @IntRange(from = -1, to = Font.FONT_WEIGHT_MAX) int weight) {
if (typeface == null && familyName != null) {
// Lookup normal Typeface from system font map.
final Typeface normalTypeface = Typeface.create(familyName, Typeface.NORMAL);
@@ -2095,9 +2096,9 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
}
private void resolveStyleAndSetTypeface(@NonNull Typeface typeface, @Typeface.Style int style,
- @IntRange(from = -1, to = Typeface.MAX_WEIGHT) int weight) {
+ @IntRange(from = -1, to = Font.FONT_WEIGHT_MAX) int weight) {
if (weight >= 0) {
- weight = Math.min(Typeface.MAX_WEIGHT, weight);
+ weight = Math.min(Font.FONT_WEIGHT_MAX, weight);
final boolean italic = (style & Typeface.ITALIC) != 0;
setTypeface(Typeface.create(typeface, weight, italic));
} else {
@@ -3528,6 +3529,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
boolean mHasLetterSpacing = false;
float mLetterSpacing = 0;
String mFontFeatureSettings = null;
+ String mFontVariationSettings = null;
@Override
public String toString() {
@@ -3555,6 +3557,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
+ " mHasLetterSpacing:" + mHasLetterSpacing + "\n"
+ " mLetterSpacing:" + mLetterSpacing + "\n"
+ " mFontFeatureSettings:" + mFontFeatureSettings + "\n"
+ + " mFontVariationSettings:" + mFontVariationSettings + "\n"
+ "}";
}
}
@@ -3598,6 +3601,8 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
com.android.internal.R.styleable.TextAppearance_letterSpacing);
sAppearanceValues.put(com.android.internal.R.styleable.TextView_fontFeatureSettings,
com.android.internal.R.styleable.TextAppearance_fontFeatureSettings);
+ sAppearanceValues.put(com.android.internal.R.styleable.TextView_fontVariationSettings,
+ com.android.internal.R.styleable.TextAppearance_fontVariationSettings);
}
/**
@@ -3700,6 +3705,9 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
case com.android.internal.R.styleable.TextAppearance_fontFeatureSettings:
attributes.mFontFeatureSettings = appearance.getString(attr);
break;
+ case com.android.internal.R.styleable.TextAppearance_fontVariationSettings:
+ attributes.mFontVariationSettings = appearance.getString(attr);
+ break;
default:
}
}
@@ -3756,6 +3764,10 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
if (attributes.mFontFeatureSettings != null) {
setFontFeatureSettings(attributes.mFontFeatureSettings);
}
+
+ if (attributes.mFontVariationSettings != null) {
+ setFontVariationSettings(attributes.mFontVariationSettings);
+ }
}
/**
diff --git a/core/java/com/android/internal/app/procstats/AssociationState.java b/core/java/com/android/internal/app/procstats/AssociationState.java
index 115ba180ea67..3842f6659704 100644
--- a/core/java/com/android/internal/app/procstats/AssociationState.java
+++ b/core/java/com/android/internal/app/procstats/AssociationState.java
@@ -20,8 +20,8 @@ package com.android.internal.app.procstats;
import android.os.Parcel;
import android.os.SystemClock;
import android.os.UserHandle;
-import android.service.procstats.ProcessStatsAssociationStateProto;
-import android.service.procstats.ProcessStatsStateProto;
+import android.service.procstats.PackageAssociationProcessStatsProto;
+import android.service.procstats.PackageAssociationSourceProcessStatsProto;
import android.util.ArrayMap;
import android.util.Slog;
import android.util.TimeUtils;
@@ -662,22 +662,23 @@ public final class AssociationState {
public void writeToProto(ProtoOutputStream proto, long fieldId, long now) {
final long token = proto.start(fieldId);
- proto.write(ProcessStatsAssociationStateProto.COMPONENT_NAME, mName);
+ proto.write(PackageAssociationProcessStatsProto.COMPONENT_NAME, mName);
+
final int NSRC = mSources.size();
for (int isrc = 0; isrc < NSRC; isrc++) {
final SourceKey key = mSources.keyAt(isrc);
final SourceState src = mSources.valueAt(isrc);
- final long sourceToken = proto.start(ProcessStatsAssociationStateProto.SOURCES);
- proto.write(ProcessStatsAssociationStateProto.Source.PROCESS, key.mProcess);
- proto.write(ProcessStatsAssociationStateProto.Source.UID, key.mUid);
- proto.write(ProcessStatsAssociationStateProto.Source.TOTAL_COUNT, src.mCount);
+ final long sourceToken = proto.start(PackageAssociationProcessStatsProto.SOURCES);
+ proto.write(PackageAssociationSourceProcessStatsProto.PROCESS_NAME, key.mProcess);
+ proto.write(PackageAssociationSourceProcessStatsProto.PROCESS_UID, key.mUid);
+ proto.write(PackageAssociationSourceProcessStatsProto.TOTAL_COUNT, src.mCount);
long duration = src.mDuration;
if (src.mNesting > 0) {
duration += now - src.mStartUptime;
}
- proto.write(ProcessStatsAssociationStateProto.Source.TOTAL_DURATION_MS, duration);
+ proto.write(PackageAssociationSourceProcessStatsProto.TOTAL_DURATION_MS, duration);
if (src.mActiveCount != 0) {
- proto.write(ProcessStatsAssociationStateProto.Source.ACTIVE_COUNT,
+ proto.write(PackageAssociationSourceProcessStatsProto.ACTIVE_COUNT,
src.mActiveCount);
}
final long timeNow = src.mActiveStartUptime != 0 ? (now-src.mActiveStartUptime) : 0;
@@ -690,16 +691,26 @@ public final class AssociationState {
duration += timeNow;
}
final int procState = SparseMappingTable.getIdFromKey(dkey);
- DumpUtils.printProcStateDurationProto(proto,
- ProcessStatsAssociationStateProto.Source.ACTIVE_STATES,
- procState, duration);
+ final long stateToken = proto.start(
+ PackageAssociationSourceProcessStatsProto.ACTIVE_STATE_STATS);
+ DumpUtils.printProto(proto,
+ PackageAssociationSourceProcessStatsProto.StateStats.PROCESS_STATE,
+ DumpUtils.STATE_PROTO_ENUMS, procState, 1);
+ proto.write(PackageAssociationSourceProcessStatsProto.StateStats.DURATION_MS,
+ duration);
+ proto.end(stateToken);
}
} else {
duration = src.mActiveDuration + timeNow;
if (duration != 0) {
- DumpUtils.printProcStateDurationProto(proto,
- ProcessStatsAssociationStateProto.Source.ACTIVE_STATES,
- src.mActiveProcState, duration);
+ final long stateToken = proto.start(
+ PackageAssociationSourceProcessStatsProto.ACTIVE_STATE_STATS);
+ DumpUtils.printProto(proto,
+ PackageAssociationSourceProcessStatsProto.StateStats.PROCESS_STATE,
+ DumpUtils.STATE_PROTO_ENUMS, src.mActiveProcState, 1);
+ proto.write(PackageAssociationSourceProcessStatsProto.StateStats.DURATION_MS,
+ duration);
+ proto.end(stateToken);
}
}
proto.end(sourceToken);
diff --git a/core/java/com/android/internal/app/procstats/DumpUtils.java b/core/java/com/android/internal/app/procstats/DumpUtils.java
index 701391d9b3c5..eda04a6a322a 100644
--- a/core/java/com/android/internal/app/procstats/DumpUtils.java
+++ b/core/java/com/android/internal/app/procstats/DumpUtils.java
@@ -17,6 +17,7 @@
package com.android.internal.app.procstats;
import android.os.UserHandle;
+import android.service.procstats.ProcessStatsEnums;
import android.service.procstats.ProcessStatsStateProto;
import android.util.TimeUtils;
import android.util.proto.ProtoOutputStream;
@@ -107,20 +108,24 @@ public final class DumpUtils {
STATE_TAGS[STATE_CACHED_EMPTY] = "e";
STATE_PROTO_ENUMS = new int[STATE_COUNT];
- STATE_PROTO_ENUMS[STATE_PERSISTENT] = ProcessStatsStateProto.PERSISTENT;
- STATE_PROTO_ENUMS[STATE_TOP] = ProcessStatsStateProto.TOP;
- STATE_PROTO_ENUMS[STATE_IMPORTANT_FOREGROUND] = ProcessStatsStateProto.IMPORTANT_FOREGROUND;
- STATE_PROTO_ENUMS[STATE_IMPORTANT_BACKGROUND] = ProcessStatsStateProto.IMPORTANT_BACKGROUND;
- STATE_PROTO_ENUMS[STATE_BACKUP] = ProcessStatsStateProto.BACKUP;
- STATE_PROTO_ENUMS[STATE_SERVICE] = ProcessStatsStateProto.SERVICE;
- STATE_PROTO_ENUMS[STATE_SERVICE_RESTARTING] = ProcessStatsStateProto.SERVICE_RESTARTING;
- STATE_PROTO_ENUMS[STATE_RECEIVER] = ProcessStatsStateProto.RECEIVER;
- STATE_PROTO_ENUMS[STATE_HEAVY_WEIGHT] = ProcessStatsStateProto.HEAVY_WEIGHT;
- STATE_PROTO_ENUMS[STATE_HOME] = ProcessStatsStateProto.HOME;
- STATE_PROTO_ENUMS[STATE_LAST_ACTIVITY] = ProcessStatsStateProto.LAST_ACTIVITY;
- STATE_PROTO_ENUMS[STATE_CACHED_ACTIVITY] = ProcessStatsStateProto.CACHED_ACTIVITY;
- STATE_PROTO_ENUMS[STATE_CACHED_ACTIVITY_CLIENT] = ProcessStatsStateProto.CACHED_ACTIVITY_CLIENT;
- STATE_PROTO_ENUMS[STATE_CACHED_EMPTY] = ProcessStatsStateProto.CACHED_EMPTY;
+ STATE_PROTO_ENUMS[STATE_PERSISTENT] = ProcessStatsEnums.PROCESS_STATE_PERSISTENT;
+ STATE_PROTO_ENUMS[STATE_TOP] = ProcessStatsEnums.PROCESS_STATE_TOP;
+ STATE_PROTO_ENUMS[STATE_IMPORTANT_FOREGROUND] =
+ ProcessStatsEnums.PROCESS_STATE_IMPORTANT_FOREGROUND;
+ STATE_PROTO_ENUMS[STATE_IMPORTANT_BACKGROUND] =
+ ProcessStatsEnums.PROCESS_STATE_IMPORTANT_BACKGROUND;
+ STATE_PROTO_ENUMS[STATE_BACKUP] = ProcessStatsEnums.PROCESS_STATE_BACKUP;
+ STATE_PROTO_ENUMS[STATE_SERVICE] = ProcessStatsEnums.PROCESS_STATE_SERVICE;
+ STATE_PROTO_ENUMS[STATE_SERVICE_RESTARTING] =
+ ProcessStatsEnums.PROCESS_STATE_SERVICE_RESTARTING;
+ STATE_PROTO_ENUMS[STATE_RECEIVER] = ProcessStatsEnums.PROCESS_STATE_RECEIVER;
+ STATE_PROTO_ENUMS[STATE_HEAVY_WEIGHT] = ProcessStatsEnums.PROCESS_STATE_HEAVY_WEIGHT;
+ STATE_PROTO_ENUMS[STATE_HOME] = ProcessStatsEnums.PROCESS_STATE_HOME;
+ STATE_PROTO_ENUMS[STATE_LAST_ACTIVITY] = ProcessStatsEnums.PROCESS_STATE_LAST_ACTIVITY;
+ STATE_PROTO_ENUMS[STATE_CACHED_ACTIVITY] = ProcessStatsEnums.PROCESS_STATE_CACHED_ACTIVITY;
+ STATE_PROTO_ENUMS[STATE_CACHED_ACTIVITY_CLIENT] =
+ ProcessStatsEnums.PROCESS_STATE_CACHED_ACTIVITY_CLIENT;
+ STATE_PROTO_ENUMS[STATE_CACHED_EMPTY] = ProcessStatsEnums.PROCESS_STATE_CACHED_EMPTY;
}
public static final String[] ADJ_SCREEN_NAMES_CSV = new String[] {
@@ -138,8 +143,8 @@ public final class DumpUtils {
};
static final int[] ADJ_SCREEN_PROTO_ENUMS = new int[] {
- ProcessStatsStateProto.OFF,
- ProcessStatsStateProto.ON
+ ProcessStatsEnums.SCREEN_STATE_OFF,
+ ProcessStatsEnums.SCREEN_STATE_ON
};
static final String[] ADJ_MEM_TAGS = new String[] {
@@ -147,10 +152,10 @@ public final class DumpUtils {
};
static final int[] ADJ_MEM_PROTO_ENUMS = new int[] {
- ProcessStatsStateProto.NORMAL,
- ProcessStatsStateProto.MODERATE,
- ProcessStatsStateProto.LOW,
- ProcessStatsStateProto.CRITICAL
+ ProcessStatsEnums.MEMORY_STATE_NORMAL,
+ ProcessStatsEnums.MEMORY_STATE_MODERATE,
+ ProcessStatsEnums.MEMORY_STATE_LOW,
+ ProcessStatsEnums.MEMORY_STATE_CRITICAL
};
static final String CSV_SEP = "\t";
@@ -278,7 +283,6 @@ public final class DumpUtils {
DumpUtils.STATE_PROTO_ENUMS, procState, 1);
proto.write(ProcessStatsStateProto.DURATION_MS, duration);
proto.end(stateToken);
-
}
public static void printProcStateTagAndValue(PrintWriter pw, int state, long value) {
diff --git a/core/java/com/android/internal/app/procstats/ProcessState.java b/core/java/com/android/internal/app/procstats/ProcessState.java
index d7f47363e4b7..4071c82e6202 100644
--- a/core/java/com/android/internal/app/procstats/ProcessState.java
+++ b/core/java/com/android/internal/app/procstats/ProcessState.java
@@ -31,36 +31,38 @@ import android.util.TimeUtils;
import android.util.proto.ProtoOutputStream;
import android.util.proto.ProtoUtils;
-import com.android.internal.app.procstats.ProcessStats.PackageState;
-import com.android.internal.app.procstats.ProcessStats.ProcessStateHolder;
-import com.android.internal.app.procstats.ProcessStats.TotalMemoryUseCollection;
-import static com.android.internal.app.procstats.ProcessStats.PSS_SAMPLE_COUNT;
-import static com.android.internal.app.procstats.ProcessStats.PSS_MINIMUM;
+
import static com.android.internal.app.procstats.ProcessStats.PSS_AVERAGE;
+import static com.android.internal.app.procstats.ProcessStats.PSS_COUNT;
import static com.android.internal.app.procstats.ProcessStats.PSS_MAXIMUM;
-import static com.android.internal.app.procstats.ProcessStats.PSS_RSS_MINIMUM;
+import static com.android.internal.app.procstats.ProcessStats.PSS_MINIMUM;
import static com.android.internal.app.procstats.ProcessStats.PSS_RSS_AVERAGE;
import static com.android.internal.app.procstats.ProcessStats.PSS_RSS_MAXIMUM;
-import static com.android.internal.app.procstats.ProcessStats.PSS_USS_MINIMUM;
+import static com.android.internal.app.procstats.ProcessStats.PSS_RSS_MINIMUM;
+import static com.android.internal.app.procstats.ProcessStats.PSS_SAMPLE_COUNT;
import static com.android.internal.app.procstats.ProcessStats.PSS_USS_AVERAGE;
import static com.android.internal.app.procstats.ProcessStats.PSS_USS_MAXIMUM;
-import static com.android.internal.app.procstats.ProcessStats.PSS_COUNT;
-import static com.android.internal.app.procstats.ProcessStats.STATE_NOTHING;
-import static com.android.internal.app.procstats.ProcessStats.STATE_PERSISTENT;
-import static com.android.internal.app.procstats.ProcessStats.STATE_TOP;
-import static com.android.internal.app.procstats.ProcessStats.STATE_IMPORTANT_FOREGROUND;
-import static com.android.internal.app.procstats.ProcessStats.STATE_IMPORTANT_BACKGROUND;
+import static com.android.internal.app.procstats.ProcessStats.PSS_USS_MINIMUM;
import static com.android.internal.app.procstats.ProcessStats.STATE_BACKUP;
-import static com.android.internal.app.procstats.ProcessStats.STATE_HEAVY_WEIGHT;
-import static com.android.internal.app.procstats.ProcessStats.STATE_SERVICE;
-import static com.android.internal.app.procstats.ProcessStats.STATE_SERVICE_RESTARTING;
-import static com.android.internal.app.procstats.ProcessStats.STATE_RECEIVER;
-import static com.android.internal.app.procstats.ProcessStats.STATE_HOME;
-import static com.android.internal.app.procstats.ProcessStats.STATE_LAST_ACTIVITY;
import static com.android.internal.app.procstats.ProcessStats.STATE_CACHED_ACTIVITY;
import static com.android.internal.app.procstats.ProcessStats.STATE_CACHED_ACTIVITY_CLIENT;
import static com.android.internal.app.procstats.ProcessStats.STATE_CACHED_EMPTY;
import static com.android.internal.app.procstats.ProcessStats.STATE_COUNT;
+import static com.android.internal.app.procstats.ProcessStats.STATE_HEAVY_WEIGHT;
+import static com.android.internal.app.procstats.ProcessStats.STATE_HOME;
+import static com.android.internal.app.procstats.ProcessStats.STATE_IMPORTANT_BACKGROUND;
+import static com.android.internal.app.procstats.ProcessStats.STATE_IMPORTANT_FOREGROUND;
+import static com.android.internal.app.procstats.ProcessStats.STATE_LAST_ACTIVITY;
+import static com.android.internal.app.procstats.ProcessStats.STATE_NOTHING;
+import static com.android.internal.app.procstats.ProcessStats.STATE_PERSISTENT;
+import static com.android.internal.app.procstats.ProcessStats.STATE_RECEIVER;
+import static com.android.internal.app.procstats.ProcessStats.STATE_SERVICE;
+import static com.android.internal.app.procstats.ProcessStats.STATE_SERVICE_RESTARTING;
+import static com.android.internal.app.procstats.ProcessStats.STATE_TOP;
+
+import com.android.internal.app.procstats.ProcessStats.PackageState;
+import com.android.internal.app.procstats.ProcessStats.ProcessStateHolder;
+import com.android.internal.app.procstats.ProcessStats.TotalMemoryUseCollection;
import java.io.PrintWriter;
import java.util.Comparator;
diff --git a/core/java/com/android/internal/app/procstats/ProcessStats.java b/core/java/com/android/internal/app/procstats/ProcessStats.java
index b6624a2ef4b0..f6e99ba90b86 100644
--- a/core/java/com/android/internal/app/procstats/ProcessStats.java
+++ b/core/java/com/android/internal/app/procstats/ProcessStats.java
@@ -2126,12 +2126,14 @@ public final class ProcessStats implements Parcelable {
for (int is = 0; is < mServices.size(); is++) {
final ServiceState serviceState = mServices.valueAt(is);
- serviceState.writeToProto(proto, ProcessStatsPackageProto.PROCESS_STATS, now);
+ serviceState.writeToProto(proto, ProcessStatsPackageProto.SERVICE_STATS,
+ now);
}
for (int ia=0; ia<mAssociations.size(); ia++) {
final AssociationState ascState = mAssociations.valueAt(ia);
- ascState.writeToProto(proto, ProcessStatsPackageProto.ASSOCIATION_STATS, now);
+ ascState.writeToProto(proto, ProcessStatsPackageProto.ASSOCIATION_STATS,
+ now);
}
proto.end(token);
diff --git a/core/java/com/android/internal/app/procstats/ServiceState.java b/core/java/com/android/internal/app/procstats/ServiceState.java
index 16975a441b40..72077c45356d 100644
--- a/core/java/com/android/internal/app/procstats/ServiceState.java
+++ b/core/java/com/android/internal/app/procstats/ServiceState.java
@@ -19,16 +19,13 @@ package com.android.internal.app.procstats;
import android.os.Parcel;
import android.os.SystemClock;
-import android.service.procstats.ProcessStatsProto;
-import android.service.procstats.ProcessStatsServiceStateProto;
-import android.service.procstats.ProcessStatsStateProto;
+import android.service.procstats.PackageServiceOperationStatsProto;
+import android.service.procstats.PackageServiceStatsProto;
+import android.service.procstats.ProcessStatsEnums;
import android.util.Slog;
-import android.util.SparseLongArray;
import android.util.TimeUtils;
import android.util.proto.ProtoOutputStream;
-import android.util.proto.ProtoUtils;
-import static com.android.internal.app.procstats.ProcessStats.PSS_SAMPLE_COUNT;
import static com.android.internal.app.procstats.ProcessStats.STATE_NOTHING;
import java.io.PrintWriter;
@@ -559,29 +556,45 @@ public final class ServiceState {
public void writeToProto(ProtoOutputStream proto, long fieldId, long now) {
final long token = proto.start(fieldId);
- proto.write(ProcessStatsServiceStateProto.SERVICE_NAME, mName);
- writeTypeToProto(proto, ProcessStatsServiceStateProto.RUNNING_OP,
+ proto.write(PackageServiceStatsProto.SERVICE_NAME, mName);
+
+ writeTypeToProto(proto, PackageServiceStatsProto.OPERATION_STATS,
+ ProcessStatsEnums.SERVICE_OPERATION_STATE_RUNNING,
ServiceState.SERVICE_RUN, mRunCount, mRunState, mRunStartTime, now);
- writeTypeToProto(proto, ProcessStatsServiceStateProto.STARTED_OP,
+
+ writeTypeToProto(proto, PackageServiceStatsProto.OPERATION_STATS,
+ ProcessStatsEnums.SERVICE_OPERATION_STATE_STARTED,
ServiceState.SERVICE_STARTED, mStartedCount, mStartedState, mStartedStartTime, now);
- writeTypeToProto(proto, ProcessStatsServiceStateProto.FOREGROUND_OP,
+
+ writeTypeToProto(proto, PackageServiceStatsProto.OPERATION_STATS,
+ ProcessStatsEnums.SERVICE_OPERATION_STATE_FOREGROUND,
ServiceState.SERVICE_FOREGROUND, mForegroundCount, mForegroundState,
mForegroundStartTime, now);
- writeTypeToProto(proto, ProcessStatsServiceStateProto.BOUND_OP,
+
+ writeTypeToProto(proto, PackageServiceStatsProto.OPERATION_STATS,
+ ProcessStatsEnums.SERVICE_OPERATION_STATE_BOUND,
ServiceState.SERVICE_BOUND, mBoundCount, mBoundState, mBoundStartTime, now);
- writeTypeToProto(proto, ProcessStatsServiceStateProto.EXECUTING_OP,
+
+ writeTypeToProto(proto, PackageServiceStatsProto.OPERATION_STATS,
+ ProcessStatsEnums.SERVICE_OPERATION_STATE_EXECUTING,
ServiceState.SERVICE_EXEC, mExecCount, mExecState, mExecStartTime, now);
+
proto.end(token);
}
- public void writeTypeToProto(ProtoOutputStream proto, long fieldId, int serviceType,
+ /**
+ * write the metrics to proto for each operation type.
+ */
+ public void writeTypeToProto(ProtoOutputStream proto, long fieldId, int opType, int serviceType,
int opCount, int curState, long curStartTime, long now) {
if (opCount <= 0) {
return;
}
final long token = proto.start(fieldId);
- proto.write(ProcessStatsServiceStateProto.OperationInfo.COUNT, opCount);
+ proto.write(PackageServiceOperationStatsProto.OPERATION, opType);
+ proto.write(PackageServiceOperationStatsProto.COUNT, opCount);
+
boolean didCurState = false;
final int N = mDurations.getKeyCount();
for (int i=0; i<N; i++) {
@@ -597,21 +610,22 @@ public final class ServiceState {
didCurState = true;
time += now - curStartTime;
}
- final long stateToken = proto.start(ProcessStatsServiceStateProto.OperationInfo.STATES);
+ final long stateToken = proto.start(PackageServiceOperationStatsProto.STATE_STATS);
DumpUtils.printProcStateAdjTagProto(proto,
- ProcessStatsStateProto.SCREEN_STATE,
- ProcessStatsStateProto.MEMORY_STATE,
+ PackageServiceOperationStatsProto.StateStats.SCREEN_STATE,
+ PackageServiceOperationStatsProto.StateStats.MEMORY_STATE,
type);
- proto.write(ProcessStatsStateProto.DURATION_MS, time);
+ proto.write(PackageServiceOperationStatsProto.StateStats.DURATION_MS, time);
proto.end(stateToken);
}
if (!didCurState && curState != STATE_NOTHING) {
- final long stateToken = proto.start(ProcessStatsServiceStateProto.OperationInfo.STATES);
+ final long stateToken = proto.start(PackageServiceOperationStatsProto.STATE_STATS);
DumpUtils.printProcStateAdjTagProto(proto,
- ProcessStatsStateProto.SCREEN_STATE,
- ProcessStatsStateProto.MEMORY_STATE,
+ PackageServiceOperationStatsProto.StateStats.SCREEN_STATE,
+ PackageServiceOperationStatsProto.StateStats.MEMORY_STATE,
curState);
- proto.write(ProcessStatsStateProto.DURATION_MS, now - curStartTime);
+ proto.write(PackageServiceOperationStatsProto.StateStats.DURATION_MS,
+ now - curStartTime);
proto.end(stateToken);
}
diff --git a/core/java/com/android/internal/inputmethod/IInputMethodPrivilegedOperations.aidl b/core/java/com/android/internal/inputmethod/IInputMethodPrivilegedOperations.aidl
index 449b4a560dc6..c32894dd04f9 100644
--- a/core/java/com/android/internal/inputmethod/IInputMethodPrivilegedOperations.aidl
+++ b/core/java/com/android/internal/inputmethod/IInputMethodPrivilegedOperations.aidl
@@ -17,6 +17,7 @@
package com.android.internal.inputmethod;
import android.net.Uri;
+import android.view.inputmethod.InputMethodSubtype;
import com.android.internal.inputmethod.IInputContentUriToken;
@@ -30,4 +31,14 @@ interface IInputMethodPrivilegedOperations {
void clearLastInputMethodWindowForTransition();
IInputContentUriToken createInputContentUriToken(in Uri contentUri, in String packageName);
void reportFullscreenMode(boolean fullscreen);
+ void setInputMethod(String id);
+ void setInputMethodAndSubtype(String id, in InputMethodSubtype subtype);
+ void hideMySoftInput(int flags);
+ void showMySoftInput(int flags);
+ void updateStatusIcon(String packageName, int iconId);
+ boolean switchToPreviousInputMethod();
+ boolean switchToNextInputMethod(boolean onlyCurrentIme);
+ boolean shouldOfferSwitchingToNextInputMethod();
+
+ oneway void notifyUserActionAsync();
}
diff --git a/core/java/com/android/internal/inputmethod/InputMethodPrivilegedOperations.java b/core/java/com/android/internal/inputmethod/InputMethodPrivilegedOperations.java
new file mode 100644
index 000000000000..f0e8dc59d09a
--- /dev/null
+++ b/core/java/com/android/internal/inputmethod/InputMethodPrivilegedOperations.java
@@ -0,0 +1,365 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.inputmethod;
+
+import android.annotation.AnyThread;
+import android.annotation.DrawableRes;
+import android.annotation.Nullable;
+import android.net.Uri;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.util.Log;
+import android.view.inputmethod.InputMethodSubtype;
+
+import com.android.internal.annotations.GuardedBy;
+
+/**
+ * A utility class to take care of boilerplate code around IPCs.
+ */
+public final class InputMethodPrivilegedOperations {
+ private static final String TAG = "InputMethodPrivilegedOperations";
+
+ private static final class OpsHolder {
+ @Nullable
+ @GuardedBy("this")
+ private IInputMethodPrivilegedOperations mPrivOps;
+
+ /**
+ * Sets {@link IInputMethodPrivilegedOperations}.
+ *
+ * <p>This method can be called only once.</p>
+ *
+ * @param privOps Binder interface to be set
+ */
+ @AnyThread
+ public synchronized void set(IInputMethodPrivilegedOperations privOps) {
+ if (mPrivOps != null) {
+ throw new IllegalStateException(
+ "IInputMethodPrivilegedOperations must be set at most once."
+ + " privOps=" + privOps);
+ }
+ mPrivOps = privOps;
+ }
+
+ /**
+ * A simplified version of {@link android.os.Debug#getCaller()}.
+ *
+ * @return method name of the caller.
+ */
+ @AnyThread
+ private static String getCallerMethodName() {
+ final StackTraceElement[] callStack = Thread.currentThread().getStackTrace();
+ if (callStack.length <= 4) {
+ return "<bottom of call stack>";
+ }
+ return callStack[4].getMethodName();
+ }
+
+ @AnyThread
+ @Nullable
+ public synchronized IInputMethodPrivilegedOperations getAndWarnIfNull() {
+ if (mPrivOps == null) {
+ Log.e(TAG, getCallerMethodName() + " is ignored."
+ + " Call it within attachToken() and InputMethodService.onDestroy()");
+ }
+ return mPrivOps;
+ }
+ }
+ private final OpsHolder mOps = new OpsHolder();
+
+ /**
+ * Sets {@link IInputMethodPrivilegedOperations}.
+ *
+ * <p>This method can be called only once.</p>
+ *
+ * @param privOps Binder interface to be set
+ */
+ @AnyThread
+ public void set(IInputMethodPrivilegedOperations privOps) {
+ mOps.set(privOps);
+ }
+
+ /**
+ * Calls {@link IInputMethodPrivilegedOperations#setImeWindowStatus(int, int)}.
+ *
+ * @param vis visibility flags
+ * @param backDisposition disposition flags
+ * @see android.inputmethodservice.InputMethodService#IME_ACTIVE
+ * @see android.inputmethodservice.InputMethodService#IME_VISIBLE
+ * @see android.inputmethodservice.InputMethodService#BACK_DISPOSITION_DEFAULT
+ * @see android.inputmethodservice.InputMethodService#BACK_DISPOSITION_ADJUST_NOTHING
+ */
+ @AnyThread
+ public void setImeWindowStatus(int vis, int backDisposition) {
+ final IInputMethodPrivilegedOperations ops = mOps.getAndWarnIfNull();
+ if (ops == null) {
+ return;
+ }
+ try {
+ ops.setImeWindowStatus(vis, backDisposition);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Calls {@link IInputMethodPrivilegedOperations#reportStartInput(IBinder)}.
+ *
+ * @param startInputToken {@link IBinder} token to distinguish startInput session
+ */
+ @AnyThread
+ public void reportStartInput(IBinder startInputToken) {
+ final IInputMethodPrivilegedOperations ops = mOps.getAndWarnIfNull();
+ if (ops == null) {
+ return;
+ }
+ try {
+ ops.reportStartInput(startInputToken);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Calls {@link IInputMethodPrivilegedOperations#clearLastInputMethodWindowForTransition()}.
+ */
+ @AnyThread
+ public void clearLastInputMethodWindowForTransition() {
+ final IInputMethodPrivilegedOperations ops = mOps.getAndWarnIfNull();
+ if (ops == null) {
+ return;
+ }
+ try {
+ ops.clearLastInputMethodWindowForTransition();
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Calls {@link IInputMethodPrivilegedOperations#createInputContentUriToken(Uri, String)}.
+ *
+ * @param contentUri Content URI to which a temporary read permission should be granted
+ * @param packageName Indicates what package needs to have a temporary read permission
+ * @return special Binder token that should be set to
+ * {@link android.view.inputmethod.InputContentInfo#setUriToken(IInputContentUriToken)}
+ */
+ @AnyThread
+ public IInputContentUriToken createInputContentUriToken(Uri contentUri, String packageName) {
+ final IInputMethodPrivilegedOperations ops = mOps.getAndWarnIfNull();
+ if (ops == null) {
+ return null;
+ }
+ try {
+ return ops.createInputContentUriToken(contentUri, packageName);
+ } catch (RemoteException e) {
+ // For historical reasons, this error was silently ignored.
+ // Note that the caller already logs error so we do not need additional Log.e() here.
+ // TODO(team): Check if it is safe to rethrow error here.
+ return null;
+ }
+ }
+
+ /**
+ * Calls {@link IInputMethodPrivilegedOperations#reportFullscreenMode(boolean)}.
+ *
+ * @param fullscreen {@code true} if the IME enters full screen mode
+ */
+ @AnyThread
+ public void reportFullscreenMode(boolean fullscreen) {
+ final IInputMethodPrivilegedOperations ops = mOps.getAndWarnIfNull();
+ if (ops == null) {
+ return;
+ }
+ try {
+ ops.reportFullscreenMode(fullscreen);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Calls {@link IInputMethodPrivilegedOperations#updateStatusIcon(String, int)}.
+ *
+ * @param packageName package name from which the status icon should be loaded
+ * @param iconResId resource ID of the icon to be loaded
+ */
+ @AnyThread
+ public void updateStatusIcon(String packageName, @DrawableRes int iconResId) {
+ final IInputMethodPrivilegedOperations ops = mOps.getAndWarnIfNull();
+ if (ops == null) {
+ return;
+ }
+ try {
+ ops.updateStatusIcon(packageName, iconResId);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Calls {@link IInputMethodPrivilegedOperations#setInputMethod(String)}.
+ *
+ * @param id IME ID of the IME to switch to
+ * @see android.view.inputmethod.InputMethodInfo#getId()
+ */
+ @AnyThread
+ public void setInputMethod(String id) {
+ final IInputMethodPrivilegedOperations ops = mOps.getAndWarnIfNull();
+ if (ops == null) {
+ return;
+ }
+ try {
+ ops.setInputMethod(id);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Calls {@link IInputMethodPrivilegedOperations#setInputMethodAndSubtype(String,
+ * InputMethodSubtype)}
+ *
+ * @param id IME ID of the IME to switch to
+ * @param subtype {@link InputMethodSubtype} to switch to
+ * @see android.view.inputmethod.InputMethodInfo#getId()
+ */
+ @AnyThread
+ public void setInputMethodAndSubtype(String id, InputMethodSubtype subtype) {
+ final IInputMethodPrivilegedOperations ops = mOps.getAndWarnIfNull();
+ if (ops == null) {
+ return;
+ }
+ try {
+ ops.setInputMethodAndSubtype(id, subtype);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Calls {@link IInputMethodPrivilegedOperations#hideMySoftInput(int)}
+ *
+ * @param flags additional operating flags
+ * @see android.view.inputmethod.InputMethodManager#HIDE_IMPLICIT_ONLY
+ * @see android.view.inputmethod.InputMethodManager#HIDE_NOT_ALWAYS
+ */
+ @AnyThread
+ public void hideMySoftInput(int flags) {
+ final IInputMethodPrivilegedOperations ops = mOps.getAndWarnIfNull();
+ if (ops == null) {
+ return;
+ }
+ try {
+ ops.hideMySoftInput(flags);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Calls {@link IInputMethodPrivilegedOperations#showMySoftInput(int)}
+ *
+ * @param flags additional operating flags
+ * @see android.view.inputmethod.InputMethodManager#SHOW_IMPLICIT
+ * @see android.view.inputmethod.InputMethodManager#SHOW_FORCED
+ */
+ @AnyThread
+ public void showMySoftInput(int flags) {
+ final IInputMethodPrivilegedOperations ops = mOps.getAndWarnIfNull();
+ if (ops == null) {
+ return;
+ }
+ try {
+ ops.showMySoftInput(flags);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Calls {@link IInputMethodPrivilegedOperations#switchToPreviousInputMethod()}
+ *
+ * @return {@code true} if handled
+ */
+ @AnyThread
+ public boolean switchToPreviousInputMethod() {
+ final IInputMethodPrivilegedOperations ops = mOps.getAndWarnIfNull();
+ if (ops == null) {
+ return false;
+ }
+ try {
+ return ops.switchToPreviousInputMethod();
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Calls {@link IInputMethodPrivilegedOperations#switchToNextInputMethod(boolean)}
+ *
+ * @param onlyCurrentIme {@code true} to switch to a {@link InputMethodSubtype} within the same
+ * IME
+ * @return {@code true} if handled
+ */
+ @AnyThread
+ public boolean switchToNextInputMethod(boolean onlyCurrentIme) {
+ final IInputMethodPrivilegedOperations ops = mOps.getAndWarnIfNull();
+ if (ops == null) {
+ return false;
+ }
+ try {
+ return ops.switchToNextInputMethod(onlyCurrentIme);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Calls {@link IInputMethodPrivilegedOperations#shouldOfferSwitchingToNextInputMethod()}
+ *
+ * @return {@code true} if the IEM should offer a way to globally switch IME
+ */
+ @AnyThread
+ public boolean shouldOfferSwitchingToNextInputMethod() {
+ final IInputMethodPrivilegedOperations ops = mOps.getAndWarnIfNull();
+ if (ops == null) {
+ return false;
+ }
+ try {
+ return ops.shouldOfferSwitchingToNextInputMethod();
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Calls {@link IInputMethodPrivilegedOperations#notifyUserActionAsync()}
+ */
+ @AnyThread
+ public void notifyUserActionAsync() {
+ final IInputMethodPrivilegedOperations ops = mOps.getAndWarnIfNull();
+ if (ops == null) {
+ return;
+ }
+ try {
+ ops.notifyUserActionAsync();
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+}
diff --git a/core/java/com/android/internal/inputmethod/InputMethodPrivilegedOperationsRegistry.java b/core/java/com/android/internal/inputmethod/InputMethodPrivilegedOperationsRegistry.java
new file mode 100644
index 000000000000..3255153ff754
--- /dev/null
+++ b/core/java/com/android/internal/inputmethod/InputMethodPrivilegedOperationsRegistry.java
@@ -0,0 +1,116 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.inputmethod;
+
+import android.annotation.AnyThread;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.os.IBinder;
+
+import com.android.internal.annotations.GuardedBy;
+
+import java.lang.ref.WeakReference;
+import java.util.WeakHashMap;
+
+/**
+ * A weak-reference-based mapper from IME token to {@link InputMethodPrivilegedOperations} that is
+ * used only to support deprecated IME APIs in {@link android.view.inputmethod.InputMethodManager}.
+ */
+public final class InputMethodPrivilegedOperationsRegistry {
+ private final Object mLock = new Object();
+ @GuardedBy("mLock")
+ private final WeakHashMap<IBinder, WeakReference<InputMethodPrivilegedOperations>>
+ mRegistry = new WeakHashMap<>();
+
+ @Nullable
+ private static InputMethodPrivilegedOperations sNop;
+
+ @NonNull
+ @AnyThread
+ private static InputMethodPrivilegedOperations getNopOps() {
+ // Strict thread-safety is not necessary because temporarily creating multiple nop instance
+ // is basically harmless
+ if (sNop == null) {
+ sNop = new InputMethodPrivilegedOperations();
+ }
+ return sNop;
+ }
+
+ /**
+ * Put a new entry to the registry.
+ *
+ * <p>Note: {@link InputMethodPrivilegedOperationsRegistry} does not hold strong reference to
+ * {@code token} and {@code ops}. The caller must be responsible for holding strong references
+ * to those objects, that is until {@link android.inputmethodservice.InputMethodService} is
+ * destroyed.</p>
+ *
+ * @param token IME token
+ * @param ops {@link InputMethodPrivilegedOperations} to be associated with the given IME token
+ */
+ @AnyThread
+ public void put(IBinder token, InputMethodPrivilegedOperations ops) {
+ synchronized (mLock) {
+ final WeakReference<InputMethodPrivilegedOperations> previousOps =
+ mRegistry.put(token, new WeakReference<>(ops));
+ if (previousOps != null) {
+ throw new IllegalStateException(previousOps.get() + " is already registered for "
+ + " this token=" + token + " newOps=" + ops);
+ }
+ }
+ }
+
+ /**
+ * Get a {@link InputMethodPrivilegedOperations} from the given IME token. If it is not
+ * available, return a fake instance that does nothing except for showing warning messages.
+ *
+ * @param token IME token
+ * @return real {@link InputMethodPrivilegedOperations} object if {@code token} is still valid.
+ * Otherwise a fake instance of {@link InputMethodPrivilegedOperations} hat does nothing
+ * except for showing warning messages
+ */
+ @NonNull
+ @AnyThread
+ public InputMethodPrivilegedOperations get(IBinder token) {
+ synchronized (mLock) {
+ final WeakReference<InputMethodPrivilegedOperations> wrapperRef = mRegistry.get(token);
+ if (wrapperRef == null) {
+ return getNopOps();
+ }
+ final InputMethodPrivilegedOperations wrapper = wrapperRef.get();
+ if (wrapper == null) {
+ return getNopOps();
+ }
+ return wrapper;
+ }
+ }
+
+ /**
+ * Explicitly removes the specified entry.
+ *
+ * <p>Note: Calling this method is optional. In general, {@link WeakHashMap} and
+ * {@link WeakReference} guarantee that the entry will be removed after specified binder proxies
+ * are garbage collected.</p>
+ *
+ * @param token IME token to be removed.
+ */
+ @AnyThread
+ public void remove(IBinder token) {
+ synchronized (mLock) {
+ mRegistry.remove(token);
+ }
+ }
+}
diff --git a/core/java/com/android/internal/os/ZygoteConnection.java b/core/java/com/android/internal/os/ZygoteConnection.java
index b60b43a8d45d..06c41d858f7c 100644
--- a/core/java/com/android/internal/os/ZygoteConnection.java
+++ b/core/java/com/android/internal/os/ZygoteConnection.java
@@ -22,6 +22,7 @@ import static android.system.OsConstants.POLLIN;
import static android.system.OsConstants.STDERR_FILENO;
import static android.system.OsConstants.STDIN_FILENO;
import static android.system.OsConstants.STDOUT_FILENO;
+
import static com.android.internal.os.ZygoteConnectionConstants.CONNECTION_TIMEOUT_MILLIS;
import static com.android.internal.os.ZygoteConnectionConstants.MAX_ZYGOTE_ARGC;
import static com.android.internal.os.ZygoteConnectionConstants.WRAPPED_PID_TIMEOUT_MILLIS;
@@ -36,12 +37,15 @@ import android.system.ErrnoException;
import android.system.Os;
import android.system.StructPollfd;
import android.util.Log;
+
import dalvik.system.VMRuntime;
+
+import libcore.io.IoUtils;
+
import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
-import java.io.EOFException;
import java.io.FileDescriptor;
import java.io.IOException;
import java.io.InputStreamReader;
@@ -49,8 +53,6 @@ import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Arrays;
-import libcore.io.IoUtils;
-
/**
* A connection that can make spawn requests.
*/
@@ -377,6 +379,7 @@ class ZygoteConnection {
* are the settings for current and max value.</i>
* <li> --instruction-set=<i>instruction-set-string</i> which instruction set to use/emulate.
* <li> --nice-name=<i>nice name to appear in ps</i>
+ * <li> --package-name=<i>package name this process belongs to</i>
* <li> --runtime-args indicates that the remaining arg list should
* be handed off to com.android.internal.os.RuntimeInit, rather than
* processed directly.
@@ -680,6 +683,9 @@ class ZygoteConnection {
}
expectRuntimeArgs = false;
} else if (arg.startsWith("--package-name=")) {
+ if (packageName != null) {
+ throw new IllegalArgumentException("Duplicate arg specified");
+ }
packageName = arg.substring(arg.indexOf('=') + 1);
} else {
break;
diff --git a/core/java/com/android/internal/view/IInputConnectionWrapper.java b/core/java/com/android/internal/view/IInputConnectionWrapper.java
index d4c4ab343a14..6f9c87ab8f5a 100644
--- a/core/java/com/android/internal/view/IInputConnectionWrapper.java
+++ b/core/java/com/android/internal/view/IInputConnectionWrapper.java
@@ -110,12 +110,6 @@ public abstract class IInputConnectionWrapper extends IInputContext.Stub {
abstract protected boolean isActive();
- /**
- * Called when the user took some actions that should be taken into consideration to update the
- * LRU list for input method rotation.
- */
- abstract protected void onUserAction();
-
public void getTextAfterCursor(int length, int flags, int seq, IInputContextCallback callback) {
dispatchMessage(obtainMessageIISC(DO_GET_TEXT_AFTER_CURSOR, length, flags, seq, callback));
}
@@ -342,7 +336,6 @@ public abstract class IInputConnectionWrapper extends IInputContext.Stub {
return;
}
ic.commitText((CharSequence)msg.obj, msg.arg1);
- onUserAction();
return;
}
case DO_SET_SELECTION: {
@@ -397,7 +390,6 @@ public abstract class IInputConnectionWrapper extends IInputContext.Stub {
return;
}
ic.setComposingText((CharSequence)msg.obj, msg.arg1);
- onUserAction();
return;
}
case DO_SET_COMPOSING_REGION: {
@@ -437,7 +429,6 @@ public abstract class IInputConnectionWrapper extends IInputContext.Stub {
return;
}
ic.sendKeyEvent((KeyEvent)msg.obj);
- onUserAction();
return;
}
case DO_CLEAR_META_KEY_STATES: {
diff --git a/core/java/com/android/internal/view/IInputMethodClient.aidl b/core/java/com/android/internal/view/IInputMethodClient.aidl
index 5c6dea88ac0e..2618356d7a09 100644
--- a/core/java/com/android/internal/view/IInputMethodClient.aidl
+++ b/core/java/com/android/internal/view/IInputMethodClient.aidl
@@ -27,6 +27,5 @@ oneway interface IInputMethodClient {
// unbindReason corresponds to InputMethodClient.UnbindReason.
void onUnbindMethod(int sequence, int unbindReason);
void setActive(boolean active, boolean fullscreen);
- void setUserActionNotificationSequenceNumber(int sequenceNumber);
void reportFullscreenMode(boolean fullscreen);
}
diff --git a/core/java/com/android/internal/view/IInputMethodManager.aidl b/core/java/com/android/internal/view/IInputMethodManager.aidl
index c08c8718230d..543f4a532307 100644
--- a/core/java/com/android/internal/view/IInputMethodManager.aidl
+++ b/core/java/com/android/internal/view/IInputMethodManager.aidl
@@ -63,22 +63,20 @@ interface IInputMethodManager {
int auxiliarySubtypeMode);
void showInputMethodAndSubtypeEnablerFromClient(in IInputMethodClient client, String topId);
boolean isInputMethodPickerShownForTest();
+ // TODO(Bug 114488811): this can be removed once we deprecate special null token rule.
void setInputMethod(in IBinder token, String id);
+ // TODO(Bug 114488811): this can be removed once we deprecate special null token rule.
void setInputMethodAndSubtype(in IBinder token, String id, in InputMethodSubtype subtype);
- void hideMySoftInput(in IBinder token, int flags);
- void showMySoftInput(in IBinder token, int flags);
- void updateStatusIcon(in IBinder token, String packageName, int iconId);
void registerSuggestionSpansForNotification(in SuggestionSpan[] spans);
boolean notifySuggestionPicked(in SuggestionSpan span, String originalString, int index);
InputMethodSubtype getCurrentInputMethodSubtype();
boolean setCurrentInputMethodSubtype(in InputMethodSubtype subtype);
+ // TODO(Bug 114488811): this can be removed once we deprecate special null token rule.
boolean switchToPreviousInputMethod(in IBinder token);
+ // TODO(Bug 114488811): this can be removed once we deprecate special null token rule.
boolean switchToNextInputMethod(in IBinder token, boolean onlyCurrentIme);
- boolean shouldOfferSwitchingToNextInputMethod(in IBinder token);
void setAdditionalInputMethodSubtypes(String id, in InputMethodSubtype[] subtypes);
// This is kept due to @UnsupportedAppUsage.
// TODO(Bug 113914148): Consider removing this.
int getInputMethodWindowVisibleHeight();
-
- oneway void notifyUserAction(int sequenceNumber);
}
diff --git a/core/java/com/android/internal/view/InputBindResult.java b/core/java/com/android/internal/view/InputBindResult.java
index 9d4383f40266..e03c1f8621be 100644
--- a/core/java/com/android/internal/view/InputBindResult.java
+++ b/core/java/com/android/internal/view/InputBindResult.java
@@ -171,20 +171,13 @@ public final class InputBindResult implements Parcelable {
*/
public final int sequence;
- /**
- * Sequence number of user action notification.
- */
- public final int userActionNotificationSequenceNumber;
-
public InputBindResult(@ResultCode int _result,
- IInputMethodSession _method, InputChannel _channel,
- String _id, int _sequence, int _userActionNotificationSequenceNumber) {
+ IInputMethodSession _method, InputChannel _channel, String _id, int _sequence) {
result = _result;
method = _method;
channel = _channel;
id = _id;
sequence = _sequence;
- userActionNotificationSequenceNumber = _userActionNotificationSequenceNumber;
}
InputBindResult(Parcel source) {
@@ -197,14 +190,12 @@ public final class InputBindResult implements Parcelable {
}
id = source.readString();
sequence = source.readInt();
- userActionNotificationSequenceNumber = source.readInt();
}
@Override
public String toString() {
return "InputBindResult{result=" + getResultString() + " method="+ method + " id=" + id
+ " sequence=" + sequence
- + " userActionNotificationSequenceNumber=" + userActionNotificationSequenceNumber
+ "}";
}
@@ -226,7 +217,6 @@ public final class InputBindResult implements Parcelable {
}
dest.writeString(id);
dest.writeInt(sequence);
- dest.writeInt(userActionNotificationSequenceNumber);
}
/**
@@ -285,7 +275,7 @@ public final class InputBindResult implements Parcelable {
}
private static InputBindResult error(@ResultCode int result) {
- return new InputBindResult(result, null, null, null, -1, -1);
+ return new InputBindResult(result, null, null, null, -1);
}
/**
diff --git a/core/java/com/android/internal/view/InputConnectionWrapper.java b/core/java/com/android/internal/view/InputConnectionWrapper.java
index 5b65bbe1e90e..3bd3072c0ebe 100644
--- a/core/java/com/android/internal/view/InputConnectionWrapper.java
+++ b/core/java/com/android/internal/view/InputConnectionWrapper.java
@@ -371,6 +371,7 @@ public class InputConnectionWrapper implements InputConnection {
public boolean commitText(CharSequence text, int newCursorPosition) {
try {
mIInputContext.commitText(text, newCursorPosition);
+ notifyUserActionIfNecessary();
return true;
} catch (RemoteException e) {
return false;
@@ -378,6 +379,16 @@ public class InputConnectionWrapper implements InputConnection {
}
@AnyThread
+ private void notifyUserActionIfNecessary() {
+ final AbstractInputMethodService inputMethodService = mInputMethodService.get();
+ if (inputMethodService == null) {
+ // This basically should not happen, because it's the the caller of this method.
+ return;
+ }
+ inputMethodService.notifyUserActionIfNecessary();
+ }
+
+ @AnyThread
public boolean commitCompletion(CompletionInfo text) {
if (isMethodMissing(MissingMethodFlags.COMMIT_CORRECTION)) {
// This method is not implemented.
@@ -449,6 +460,7 @@ public class InputConnectionWrapper implements InputConnection {
public boolean setComposingText(CharSequence text, int newCursorPosition) {
try {
mIInputContext.setComposingText(text, newCursorPosition);
+ notifyUserActionIfNecessary();
return true;
} catch (RemoteException e) {
return false;
@@ -489,6 +501,7 @@ public class InputConnectionWrapper implements InputConnection {
public boolean sendKeyEvent(KeyEvent event) {
try {
mIInputContext.sendKeyEvent(event);
+ notifyUserActionIfNecessary();
return true;
} catch (RemoteException e) {
return false;
diff --git a/core/java/com/android/server/AppWidgetBackupBridge.java b/core/java/com/android/server/AppWidgetBackupBridge.java
index 2ea2f794dac9..7d82d355e3eb 100644
--- a/core/java/com/android/server/AppWidgetBackupBridge.java
+++ b/core/java/com/android/server/AppWidgetBackupBridge.java
@@ -16,6 +16,8 @@
package com.android.server;
+import android.annotation.Nullable;
+
import java.util.List;
/**
@@ -37,6 +39,8 @@ public class AppWidgetBackupBridge {
: null;
}
+ /** Returns a byte array of widget data for the specified package or {@code null}. */
+ @Nullable
public static byte[] getWidgetState(String packageName, int userId) {
return (sAppWidgetService != null)
? sAppWidgetService.getWidgetState(packageName, userId)
diff --git a/core/jni/android/graphics/Bitmap.cpp b/core/jni/android/graphics/Bitmap.cpp
index 8083a6a27da7..0a252716b69e 100755
--- a/core/jni/android/graphics/Bitmap.cpp
+++ b/core/jni/android/graphics/Bitmap.cpp
@@ -1198,6 +1198,10 @@ static jobject Bitmap_copyPreserveInternalConfig(JNIEnv* env, jobject, jlong bit
static jobject Bitmap_createHardwareBitmap(JNIEnv* env, jobject, jobject graphicBuffer) {
sp<GraphicBuffer> buffer(graphicBufferForJavaObject(env, graphicBuffer));
+ // Bitmap::createFrom currently can only attach to a GraphicBuffer with PIXEL_FORMAT_RGBA_8888
+ // format and SRGB color space.
+ // To support any color space, we need to pass an additional ColorSpace argument to
+ // java Bitmap.createHardwareBitmap.
sk_sp<Bitmap> bitmap = Bitmap::createFrom(buffer);
if (!bitmap.get()) {
ALOGW("failed to create hardware bitmap from graphic buffer");
diff --git a/core/jni/android_media_AudioSystem.cpp b/core/jni/android_media_AudioSystem.cpp
index a72363cd4c3e..d4a84c15480b 100644
--- a/core/jni/android_media_AudioSystem.cpp
+++ b/core/jni/android_media_AudioSystem.cpp
@@ -70,6 +70,9 @@ static struct {
jfieldID mRole;
jfieldID mGains;
jfieldID mActiveConfig;
+ // Valid only if an AudioDevicePort
+ jfieldID mType;
+ jfieldID mAddress;
// other fields unused by JNI
} gAudioPortFields;
@@ -153,6 +156,9 @@ static jclass gAudioAttributesClass;
static struct {
jfieldID mUsage;
jfieldID mSource;
+ jfieldID mContentType;
+ jfieldID mFlags;
+ jfieldID mFormattedTags;
} gAudioAttributesFields;
static const char* const kEventHandlerClassPathName =
@@ -669,6 +675,26 @@ static void convertAudioGainConfigToNative(JNIEnv *env,
env->DeleteLocalRef(jValues);
}
+static jint convertAudioAttributesToNative(JNIEnv *env,
+ audio_attributes_t *nAudioAttributes,
+ const jobject jAudioAttributes)
+{
+ nAudioAttributes->usage = (audio_usage_t)env->GetIntField(jAudioAttributes,
+ gAudioAttributesFields.mUsage);
+ nAudioAttributes->source = (audio_source_t)env->GetIntField(jAudioAttributes,
+ gAudioAttributesFields.mSource);
+ nAudioAttributes->content_type = (audio_content_type_t)env->GetIntField(jAudioAttributes,
+ gAudioAttributesFields.mContentType);
+ nAudioAttributes->flags = env->GetIntField(jAudioAttributes,
+ gAudioAttributesFields.mFlags);
+ const jstring jtags = (jstring)env->GetObjectField(jAudioAttributes,
+ gAudioAttributesFields.mFormattedTags);
+ const char *tags = env->GetStringUTFChars(jtags, NULL);
+ strncpy(nAudioAttributes->tags, tags, AUDIO_ATTRIBUTES_TAGS_MAX_SIZE - 1);
+ env->ReleaseStringUTFChars(jtags, tags);
+ return (jint)AUDIO_JAVA_SUCCESS;
+}
+
static jint convertAudioPortConfigToNative(JNIEnv *env,
struct audio_port_config *nAudioPortConfig,
@@ -745,6 +771,42 @@ static jint convertAudioPortConfigToNative(JNIEnv *env,
return (jint)AUDIO_JAVA_SUCCESS;
}
+/**
+ * Extends convertAudioPortConfigToNative with extra device port info.
+ * Mix / Session specific info is not fulfilled.
+ */
+static jint convertAudioPortConfigToNativeWithDevicePort(JNIEnv *env,
+ struct audio_port_config *nAudioPortConfig,
+ const jobject jAudioPortConfig,
+ bool useConfigMask)
+{
+ jint jStatus = convertAudioPortConfigToNative(env,
+ nAudioPortConfig,
+ jAudioPortConfig,
+ useConfigMask);
+ if (jStatus != AUDIO_JAVA_SUCCESS) {
+ return jStatus;
+ }
+ // Supports AUDIO_PORT_TYPE_DEVICE only
+ if (nAudioPortConfig->type != AUDIO_PORT_TYPE_DEVICE) {
+ return (jint)AUDIO_JAVA_BAD_VALUE;
+ }
+
+ jobject jAudioDevicePort = env->GetObjectField(jAudioPortConfig,
+ gAudioPortConfigFields.mPort);
+ nAudioPortConfig->ext.device.type = env->GetIntField(jAudioDevicePort,
+ gAudioPortFields.mType);
+ jstring jDeviceAddress = (jstring)env->GetObjectField(jAudioDevicePort,
+ gAudioPortFields.mAddress);
+ const char *nDeviceAddress = env->GetStringUTFChars(jDeviceAddress, NULL);
+ strncpy(nAudioPortConfig->ext.device.address,
+ nDeviceAddress, AUDIO_DEVICE_MAX_ADDRESS_LEN - 1);
+ env->ReleaseStringUTFChars(jDeviceAddress, nDeviceAddress);
+ env->DeleteLocalRef(jDeviceAddress);
+ env->DeleteLocalRef(jAudioDevicePort);
+ return jStatus;
+}
+
static jint convertAudioPortConfigFromNative(JNIEnv *env,
jobject jAudioPort,
jobject *jAudioPortConfig,
@@ -1592,6 +1654,51 @@ android_media_AudioSystem_setAudioPortConfig(JNIEnv *env, jobject clazz,
return jStatus;
}
+/**
+ * Returns handle if the audio source is successfully started.
+ */
+static jint
+android_media_AudioSystem_startAudioSource(JNIEnv *env, jobject clazz,
+ jobject jAudioPortConfig,
+ jobject jAudioAttributes)
+{
+ ALOGV("startAudioSource");
+ if (jAudioPortConfig == NULL || jAudioAttributes == NULL) {
+ return AUDIO_JAVA_BAD_VALUE;
+ }
+ if (!env->IsInstanceOf(jAudioPortConfig, gAudioPortConfigClass)) {
+ return AUDIO_JAVA_BAD_VALUE;
+ }
+ if (!env->IsInstanceOf(jAudioAttributes, gAudioAttributesClass)) {
+ return AUDIO_JAVA_BAD_VALUE;
+ }
+ struct audio_port_config nAudioPortConfig = {};
+ jint jStatus = convertAudioPortConfigToNativeWithDevicePort(env,
+ &nAudioPortConfig, jAudioPortConfig, false);
+ if (jStatus != AUDIO_JAVA_SUCCESS) {
+ return jStatus;
+ }
+ audio_attributes_t nAudioAttributes = {};
+ jStatus = convertAudioAttributesToNative(env, &nAudioAttributes, jAudioAttributes);
+ if (jStatus != AUDIO_JAVA_SUCCESS) {
+ return jStatus;
+ }
+ audio_port_handle_t handle;
+ status_t status = AudioSystem::startAudioSource(&nAudioPortConfig, &nAudioAttributes, &handle);
+ ALOGV("AudioSystem::startAudioSource() returned %d handle %d", status, handle);
+ return handle > 0 ? handle : nativeToJavaStatus(status);
+}
+
+static jint
+android_media_AudioSystem_stopAudioSource(JNIEnv *env, jobject clazz, jint handle)
+{
+ ALOGV("stopAudioSource");
+ status_t status = AudioSystem::stopAudioSource(
+ static_cast <audio_port_handle_t>(handle));
+ ALOGV("AudioSystem::stopAudioSource() returned %d", status);
+ return nativeToJavaStatus(status);
+}
+
static void
android_media_AudioSystem_eventHandlerSetup(JNIEnv *env, jobject thiz, jobject weak_this)
{
@@ -1947,6 +2054,9 @@ static const JNINativeMethod gMethods[] = {
(void *)android_media_AudioSystem_listAudioPatches},
{"setAudioPortConfig", "(Landroid/media/AudioPortConfig;)I",
(void *)android_media_AudioSystem_setAudioPortConfig},
+ {"startAudioSource", "(Landroid/media/AudioPortConfig;Landroid/media/AudioAttributes;)I",
+ (void *)android_media_AudioSystem_startAudioSource},
+ {"stopAudioSource", "(I)I", (void *)android_media_AudioSystem_stopAudioSource},
{"getAudioHwSyncForSession", "(I)I",
(void *)android_media_AudioSystem_getAudioHwSyncForSession},
{"registerPolicyMixes", "(Ljava/util/ArrayList;Z)I",
@@ -2040,6 +2150,11 @@ int register_android_media_AudioSystem(JNIEnv *env)
gAudioDevicePortCstor = GetMethodIDOrDie(env, audioDevicePortClass, "<init>",
"(Landroid/media/AudioHandle;Ljava/lang/String;[I[I[I[I[Landroid/media/AudioGain;ILjava/lang/String;)V");
+ // When access AudioPort as AudioDevicePort
+ gAudioPortFields.mType = GetFieldIDOrDie(env, audioDevicePortClass, "mType", "I");
+ gAudioPortFields.mAddress = GetFieldIDOrDie(env, audioDevicePortClass, "mAddress",
+ "Ljava/lang/String;");
+
jclass audioMixPortClass = FindClassOrDie(env, "android/media/AudioMixPort");
gAudioMixPortClass = MakeGlobalRefOrDie(env, audioMixPortClass);
gAudioMixPortCstor = GetMethodIDOrDie(env, audioMixPortClass, "<init>",
@@ -2120,6 +2235,11 @@ int register_android_media_AudioSystem(JNIEnv *env)
gAudioAttributesClass = MakeGlobalRefOrDie(env, audioAttributesClass);
gAudioAttributesFields.mUsage = GetFieldIDOrDie(env, audioAttributesClass, "mUsage", "I");
gAudioAttributesFields.mSource = GetFieldIDOrDie(env, audioAttributesClass, "mSource", "I");
+ gAudioAttributesFields.mContentType = GetFieldIDOrDie(env,
+ audioAttributesClass, "mContentType", "I");
+ gAudioAttributesFields.mFlags = GetFieldIDOrDie(env, audioAttributesClass, "mFlags", "I");
+ gAudioAttributesFields.mFormattedTags = GetFieldIDOrDie(env,
+ audioAttributesClass, "mFormattedTags", "Ljava/lang/String;");
AudioSystem::setErrorCallback(android_media_AudioSystem_error_callback);
diff --git a/core/jni/android_view_ThreadedRenderer.cpp b/core/jni/android_view_ThreadedRenderer.cpp
index 4a1774279d28..3c59bd1e3856 100644
--- a/core/jni/android_view_ThreadedRenderer.cpp
+++ b/core/jni/android_view_ThreadedRenderer.cpp
@@ -1024,6 +1024,9 @@ static jobject android_view_ThreadedRenderer_createHardwareBitmapFromRenderNode(
// Continue I guess?
}
sk_sp<Bitmap> bitmap = Bitmap::createFrom(buffer);
+ // Bitmap::createFrom currently can only attach to a GraphicBuffer with PIXEL_FORMAT_RGBA_8888
+ // format and SRGB color space.
+ // To support any color space, we could extract it from BufferItem and pass it to Bitmap.
return bitmap::createBitmap(env, bitmap.release(),
android::bitmap::kBitmapCreateFlag_Premultiplied);
}
diff --git a/core/proto/android/service/procstats.proto b/core/proto/android/service/procstats.proto
index 736871f6bd39..ce19ce3519b2 100644
--- a/core/proto/android/service/procstats.proto
+++ b/core/proto/android/service/procstats.proto
@@ -21,6 +21,7 @@ option java_multiple_files = true;
option java_outer_classname = "ProcessStatsServiceProto";
import "frameworks/base/core/proto/android/util/common.proto";
+import "frameworks/base/core/proto/android/service/procstats_enum.proto";
import "frameworks/base/libs/incident/proto/android/privacy.proto";
/**
@@ -86,55 +87,12 @@ message ProcessStatsSectionProto {
message ProcessStatsStateProto {
option (android.msg_privacy).dest = DEST_AUTOMATIC;
- enum ScreenState {
- SCREEN_UNKNOWN = 0;
- OFF = 1;
- ON = 2;
- }
optional ScreenState screen_state = 1;
- enum MemoryState {
- MEMORY_UNKNOWN = 0;
- NORMAL = 1; // normal.
- MODERATE = 2; // moderate memory pressure.
- LOW = 3; // low memory.
- CRITICAL = 4; // critical memory.
- }
optional MemoryState memory_state = 2;
// this enum list is from frameworks/base/core/java/com/android/internal/app/procstats/ProcessStats.java
// and not frameworks/base/core/java/android/app/ActivityManager.java
- enum ProcessState {
- PROCESS_UNKNOWN = 0;
- // Persistent system process.
- PERSISTENT = 1;
- // Top activity; actually any visible activity.
- TOP = 2;
- // Important foreground process (ime, wallpaper, etc).
- IMPORTANT_FOREGROUND = 3;
- // Important background process.
- IMPORTANT_BACKGROUND = 4;
- // Performing backup operation.
- BACKUP = 5;
- // Background process running a service.
- SERVICE = 6;
- // Process not running, but would be if there was enough RAM.
- SERVICE_RESTARTING = 7;
- // Process running a receiver.
- RECEIVER = 8;
- // Heavy-weight process (currently not used).
- HEAVY_WEIGHT = 9;
- // Process hosting home/launcher app when not on top.
- HOME = 10;
- // Process hosting the last app the user was in.
- LAST_ACTIVITY = 11;
- // Cached process hosting a previous activity.
- CACHED_ACTIVITY = 12;
- // Cached process hosting a client activity.
- CACHED_ACTIVITY_CLIENT = 13;
- // Cached process that is empty.
- CACHED_EMPTY = 14;
- }
optional ProcessState process_state = 3;
// Millisecond uptime duration spent in this state
@@ -189,74 +147,85 @@ message ProcessStatsProto {
optional ProcessStatsStateProto total_running_state = 6;
}
-// Next Tag: 7
-message ProcessStatsServiceStateProto {
+// Next Tag: 4
+message PackageServiceOperationStatsProto {
option (android.msg_privacy).dest = DEST_AUTOMATIC;
- // Name of service component.
- optional string service_name = 1;
+ // Operate enum: Started, Foreground, Bound, Executing
+ optional ServiceOperationState operation = 1;
+
+ // Number of times the service was in this operation.
+ optional int32 count = 2;
// Information about a state the service can be in.
- message OperationInfo {
+ message StateStats {
option (android.msg_privacy).dest = DEST_AUTOMATIC;
- // Number of times the service was in this operation.
- optional int32 count = 1;
+ // Screen state enum.
+ optional android.service.procstats.ScreenState screen_state = 1;
+ // Memory state enum.
+ optional android.service.procstats.MemoryState memory_state = 2;
- // Time this operation was active in various states. process_state will not be set;
- // includes only uptime, not memory info.
- repeated ProcessStatsStateProto states = 2;
+ // duration in milliseconds.
+ optional int64 duration_ms = 3;
+ // Millisecond elapsed realtime duration spent in this state
+ optional int64 realtime_duration_ms = 4;
}
+ repeated StateStats state_stats = 3;
+}
- // Information about when the service was operating as running (that is how long it was
- // running for any reason, such as the finer-grained started, bound, and executing times
- // also reported in this proto).
- optional OperationInfo running_op = 2;
-
- // Information about when the service was operating as started.
- optional OperationInfo started_op = 3;
-
- // Information about when the service was operating as foreground.
- optional OperationInfo foreground_op = 4;
+// Next Tag: 3
+message PackageServiceStatsProto {
+ option (android.msg_privacy).dest = DEST_AUTOMATIC;
- // Information about when the service was operating as bound.
- optional OperationInfo bound_op = 5;
+ // Name of service component.
+ optional string service_name = 1;
- // Information about when the service was operating as executing.
- optional OperationInfo executing_op = 6;
+ // The operation stats.
+ // The package_name, package_uid, package_version, service_name will not be set to save space.
+ repeated PackageServiceOperationStatsProto operation_stats = 2;
}
// Next Tag: 7
-message ProcessStatsAssociationStateProto {
+message PackageAssociationSourceProcessStatsProto {
option (android.msg_privacy).dest = DEST_AUTOMATIC;
- // Name of the target component.
- optional string component_name = 1;
+ // Uid of the process.
+ optional int32 process_uid = 1;
+ // Process name.
+ optional string process_name = 2;
- // Information on one source in this association.
- message Source {
- option (android.msg_privacy).dest = DEST_AUTOMATIC;
+ // Total count of the times this association appeared.
+ optional int32 total_count = 3;
- // Name of source process.
- optional string process = 1;
+ // Millisecond uptime total duration this association was around.
+ optional int64 total_duration_ms = 4;
- // Uid of the source process.
- optional int32 uid = 2;
+ // Total count of the times this association became actively impacting its target process.
+ optional int32 active_count = 5;
- // Total count of the times this association appeared.
- optional int32 total_count = 3;
+ // Information on one source in this association.
+ message StateStats {
+ option (android.msg_privacy).dest = DEST_AUTOMATIC;
- // Millisecond uptime total duration this association was around.
- optional int64 total_duration_ms = 4;
+ // Process state enum.
+ optional android.service.procstats.ProcessState process_state = 1;
+ // Millisecond uptime duration spent in this state
+ optional int64 duration_ms = 2;
+ // Millisecond elapsed realtime duration spent in this state
+ optional int64 realtime_duration_ms = 3;
+ }
+ repeated StateStats active_state_stats = 6;
+}
- // Total count of the times this association became actively impacting its target process.
- optional int32 active_count = 5;
+// Next Tag: 3
+message PackageAssociationProcessStatsProto {
+ option (android.msg_privacy).dest = DEST_AUTOMATIC;
- // Time association was active in various states. screen_state and memory_state will not
- // be set; includes only uptime, not memory info.
- repeated ProcessStatsStateProto active_states = 6;
- }
- repeated Source sources = 3;
+ // Name of the target component.
+ optional string component_name = 1;
+ // Information on one source in this association.
+ repeated PackageAssociationSourceProcessStatsProto sources = 2;
}
// Next Tag: 7
@@ -276,8 +245,8 @@ message ProcessStatsPackageProto {
repeated ProcessStatsProto process_stats = 4;
// Stats for each of the package's services.
- repeated ProcessStatsServiceStateProto service_stats = 5;
+ repeated PackageServiceStatsProto service_stats = 5;
// Stats for each association with the package.
- repeated ProcessStatsAssociationStateProto association_stats = 6;
+ repeated PackageAssociationProcessStatsProto association_stats = 6;
}
diff --git a/core/proto/android/service/procstats_enum.proto b/core/proto/android/service/procstats_enum.proto
new file mode 100644
index 000000000000..cc3fe5af775b
--- /dev/null
+++ b/core/proto/android/service/procstats_enum.proto
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+syntax = "proto2";
+package android.service.procstats;
+
+option java_multiple_files = true;
+option java_outer_classname = "ProcessStatsEnums";
+
+enum ScreenState {
+ SCREEN_STATE_UNKNOWN = 0;
+ SCREEN_STATE_OFF = 1;
+ SCREEN_STATE_ON = 2;
+}
+
+enum MemoryState {
+ MEMORY_STATE_UNKNOWN = 0;
+ MEMORY_STATE_NORMAL = 1; // normal.
+ MEMORY_STATE_MODERATE = 2; // moderate memory pressure.
+ MEMORY_STATE_LOW = 3; // low memory.
+ MEMORY_STATE_CRITICAL = 4; // critical memory.
+}
+
+// this enum list is from frameworks/base/core/java/com/android/internal/app/procstats/ProcessStats.java
+// and not frameworks/base/core/java/android/app/ActivityManager.java
+enum ProcessState {
+ PROCESS_STATE_UNKNOWN = 0;
+ // Persistent system process.
+ PROCESS_STATE_PERSISTENT = 1;
+ // Top activity; actually any visible activity.
+ PROCESS_STATE_TOP = 2;
+ // Important foreground process (ime, wallpaper, etc).
+ PROCESS_STATE_IMPORTANT_FOREGROUND = 3;
+ // Important background process.
+ PROCESS_STATE_IMPORTANT_BACKGROUND = 4;
+ // Performing backup operation.
+ PROCESS_STATE_BACKUP = 5;
+ // Background process running a service.
+ PROCESS_STATE_SERVICE = 6;
+ // Process not running, but would be if there was enough RAM.
+ PROCESS_STATE_SERVICE_RESTARTING = 7;
+ // Process running a receiver.
+ PROCESS_STATE_RECEIVER = 8;
+ // Heavy-weight process (currently not used).
+ PROCESS_STATE_HEAVY_WEIGHT = 9;
+ // Process hosting home/launcher app when not on top.
+ PROCESS_STATE_HOME = 10;
+ // Process hosting the last app the user was in.
+ PROCESS_STATE_LAST_ACTIVITY = 11;
+ // Cached process hosting a previous activity.
+ PROCESS_STATE_CACHED_ACTIVITY = 12;
+ // Cached process hosting a client activity.
+ PROCESS_STATE_CACHED_ACTIVITY_CLIENT = 13;
+ // Cached process that is empty.
+ PROCESS_STATE_CACHED_EMPTY = 14;
+}
+
+enum ServiceOperationState {
+ SERVICE_OPERATION_STATE_UNKNOWN = 0;
+ SERVICE_OPERATION_STATE_RUNNING = 1;
+ SERVICE_OPERATION_STATE_STARTED = 2;
+ SERVICE_OPERATION_STATE_FOREGROUND = 3;
+ SERVICE_OPERATION_STATE_BOUND = 4;
+ SERVICE_OPERATION_STATE_EXECUTING = 5;
+}
diff --git a/core/res/res/values-af/strings.xml b/core/res/res/values-af/strings.xml
index e136d2e3eb17..c2c9254867c0 100644
--- a/core/res/res/values-af/strings.xml
+++ b/core/res/res/values-af/strings.xml
@@ -514,6 +514,7 @@
<string name="permdesc_imagesWrite" msgid="7073662756617474375">"Laat die program toe om jou fotoversameling te wysig."</string>
<string name="permlab_mediaLocation" msgid="8675148183726247864">"lees liggings in jou mediaversameling"</string>
<string name="permdesc_mediaLocation" msgid="2237023389178865130">"Laat die program toe om liggings in jou mediaversameling te lees."</string>
+ <string name="biometric_error_hw_unavailable" msgid="645781226537551036">"Biometriese hardeware is nie beskikbaar nie"</string>
<string name="fingerprint_acquired_partial" msgid="735082772341716043">"Gedeeltelike vingerafdruk is bespeur. Probeer asseblief weer."</string>
<string name="fingerprint_acquired_insufficient" msgid="4596546021310923214">"Kon nie vingerafdruk verwerk nie. Probeer asseblief weer."</string>
<string name="fingerprint_acquired_imager_dirty" msgid="1087209702421076105">"Vingerafdruksensor is vuil. Maak dit skoon en probeer weer."</string>
@@ -521,7 +522,7 @@
<string name="fingerprint_acquired_too_slow" msgid="59250885689661653">"Vinger is te stadig beweer. Probeer asseblief weer."</string>
<string-array name="fingerprint_acquired_vendor">
</string-array>
- <string name="fingerprint_not_recognized" msgid="2690661881608146617">"Nie herken nie"</string>
+ <string name="biometric_not_recognized" msgid="5770511773560736082">"Nie herken nie"</string>
<string name="fingerprint_authenticated" msgid="5309333983002526448">"Vingerafdruk is gestaaf"</string>
<string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"Vingerafdrukhardeware is nie beskikbaar nie."</string>
<string name="fingerprint_error_no_space" msgid="1055819001126053318">"Vingerafdruk kan nie gestoor word nie. Verwyder asseblief \'n bestaande vingerafdruk."</string>
diff --git a/core/res/res/values-am/strings.xml b/core/res/res/values-am/strings.xml
index 5a7e64399c3e..45f962b890f3 100644
--- a/core/res/res/values-am/strings.xml
+++ b/core/res/res/values-am/strings.xml
@@ -514,6 +514,7 @@
<string name="permdesc_imagesWrite" msgid="7073662756617474375">"መተግበሪያው የፎቶ ስብስብዎን እንዲቀይረው ያስችለዋል።"</string>
<string name="permlab_mediaLocation" msgid="8675148183726247864">"አካባቢዎችን ከሚዲያ ስብስብዎ ማንበብ"</string>
<string name="permdesc_mediaLocation" msgid="2237023389178865130">"መተግበሪያው አካባቢዎችን ከሚዲያ ስብስብዎ እንዲያነብብ ያስችለዋል።"</string>
+ <string name="biometric_error_hw_unavailable" msgid="645781226537551036">"ባዮሜትራዊ ሃርድዌር አይገኝም"</string>
<string name="fingerprint_acquired_partial" msgid="735082772341716043">"ከፊል የጣት አሻራ ተገኝቷል። እባክዎ እንደገና ይሞክሩ።"</string>
<string name="fingerprint_acquired_insufficient" msgid="4596546021310923214">"ጣት አሻራን መስራት አልተቻለም። እባክዎ እንደገና ይሞክሩ።"</string>
<string name="fingerprint_acquired_imager_dirty" msgid="1087209702421076105">"የጣት አሻራ ዳሳሽ ቆሽሿል። እባክዎ ያጽዱት እና እንደገና ይሞክሩ።"</string>
@@ -521,7 +522,7 @@
<string name="fingerprint_acquired_too_slow" msgid="59250885689661653">"ጣት ከልክ በላይ ተንቀራፎ ተንቀሳቅሷል። እባክዎ እንደገና ይሞክሩ።"</string>
<string-array name="fingerprint_acquired_vendor">
</string-array>
- <string name="fingerprint_not_recognized" msgid="2690661881608146617">"አልታወቀም"</string>
+ <string name="biometric_not_recognized" msgid="5770511773560736082">"አልታወቀም"</string>
<string name="fingerprint_authenticated" msgid="5309333983002526448">"የጣት አሻራ ትክክለኛነት ተረጋግጧል"</string>
<string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"የጣት አሻራ ሃርድዌር አይገኝም።"</string>
<string name="fingerprint_error_no_space" msgid="1055819001126053318">"የጣት አሻራ ሊከማች አይችልም። እባክዎ አሁን ያለውን የጣት አሻራ ያስወግዱ።"</string>
diff --git a/core/res/res/values-ar/strings.xml b/core/res/res/values-ar/strings.xml
index d46f758617ca..bbdea6adc2eb 100644
--- a/core/res/res/values-ar/strings.xml
+++ b/core/res/res/values-ar/strings.xml
@@ -526,6 +526,7 @@
<string name="permdesc_imagesWrite" msgid="7073662756617474375">"للسماح للتطبيق بتعديل مجموعة صورك."</string>
<string name="permlab_mediaLocation" msgid="8675148183726247864">"قراءة المواقع من مجموعة الوسائط التابعة لك"</string>
<string name="permdesc_mediaLocation" msgid="2237023389178865130">"للسماح للتطبيق بقراءة المواقع من مجموعة الوسائط التابعة لك."</string>
+ <string name="biometric_error_hw_unavailable" msgid="645781226537551036">"معدّات المقاييس الحيوية غير متاحة."</string>
<string name="fingerprint_acquired_partial" msgid="735082772341716043">"تم اكتشاف بصمة الإصبع بشكل جزئي؛ يرجى إعادة المحاولة."</string>
<string name="fingerprint_acquired_insufficient" msgid="4596546021310923214">"تعذرت معالجة بصمة الإصبع. يُرجى إعادة المحاولة."</string>
<string name="fingerprint_acquired_imager_dirty" msgid="1087209702421076105">"جهاز استشعار بصمات الأصابع متسخ، يرجى تنظيفه وإعادة المحاولة."</string>
@@ -533,7 +534,7 @@
<string name="fingerprint_acquired_too_slow" msgid="59250885689661653">"تم تحريك الإصبع ببطء شديد. يُرجى إعادة المحاولة."</string>
<string-array name="fingerprint_acquired_vendor">
</string-array>
- <string name="fingerprint_not_recognized" msgid="2690661881608146617">"لم يتم التعرف عليها"</string>
+ <string name="biometric_not_recognized" msgid="5770511773560736082">"لم يتم التعرف عليها."</string>
<string name="fingerprint_authenticated" msgid="5309333983002526448">"تم مصادقة بصمة الإصبع"</string>
<string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"جهاز بصمة الإصبع غير متاح."</string>
<string name="fingerprint_error_no_space" msgid="1055819001126053318">"يتعذر تخزين بصمة الإصبع؛ يرجى إزالة إحدى البصمات المخزنة."</string>
diff --git a/core/res/res/values-as/strings.xml b/core/res/res/values-as/strings.xml
index 10b7da4372bd..48d44b0f22bc 100644
--- a/core/res/res/values-as/strings.xml
+++ b/core/res/res/values-as/strings.xml
@@ -514,6 +514,7 @@
<string name="permdesc_imagesWrite" msgid="7073662756617474375">"এপক আপোনাৰ ফট’ সংগ্ৰহ সালসলনি কৰিবলৈ দিয়ে।"</string>
<string name="permlab_mediaLocation" msgid="8675148183726247864">"আপোনাৰ মিডিয়া সংগ্ৰহৰ অৱস্থান পঢ়িবলৈ"</string>
<string name="permdesc_mediaLocation" msgid="2237023389178865130">"এপক আপোনাৰ মিডিয়া সংগ্ৰহৰ অৱস্থান পঢ়িবলৈ দিয়ে।"</string>
+ <string name="biometric_error_hw_unavailable" msgid="645781226537551036">"বায়োমেট্ৰিক হাৰ্ডৱেৰ উপলব্ধ নহয়"</string>
<string name="fingerprint_acquired_partial" msgid="735082772341716043">"ফিংগাৰপ্ৰিণ্ট আংশিকভাৱে চিনাক্ত কৰা হৈছে। অনুগ্ৰহ কৰি আকৌ চেষ্টা কৰক৷"</string>
<string name="fingerprint_acquired_insufficient" msgid="4596546021310923214">"ফিগাৰপ্ৰিণ্টৰ প্ৰক্ৰিয়া সম্পাদন কৰিবপৰা নগ\'ল। অনুগ্ৰহ কৰি আকৌ চেষ্টা কৰক৷"</string>
<string name="fingerprint_acquired_imager_dirty" msgid="1087209702421076105">"ফিংগাৰপ্ৰিণ্ট ছেন্সৰটো লেতেৰা হৈ আছে। অনুগ্ৰহ কৰি পৰিষ্কাৰ কৰি আকৌ চেষ্টা কৰক।"</string>
@@ -521,7 +522,7 @@
<string name="fingerprint_acquired_too_slow" msgid="59250885689661653">"আঙুলিৰ গতি অতি মন্থৰ আছিল। অনুগ্ৰহ কৰি আকৌ চেষ্টা কৰক৷"</string>
<string-array name="fingerprint_acquired_vendor">
</string-array>
- <string name="fingerprint_not_recognized" msgid="2690661881608146617">"চিনাক্ত কৰিবপৰা নগ\'ল"</string>
+ <string name="biometric_not_recognized" msgid="5770511773560736082">"চিনাক্ত কৰিব পৰা নাই"</string>
<string name="fingerprint_authenticated" msgid="5309333983002526448">"ফিংগাৰপ্ৰিণ্টৰ সত্যাপন কৰা হ’ল"</string>
<string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"ফিংগাৰপ্ৰিণ্ট হাৰ্ডৱেৰ নাই।"</string>
<string name="fingerprint_error_no_space" msgid="1055819001126053318">"ফিংগাৰপ্ৰিণ্ট সঞ্চয় কৰিব পৰা নগ\'ল। পূর্বে সঞ্চিত ফিংগাৰপ্ৰিণ্ট এটা আঁতৰাওক।"</string>
diff --git a/core/res/res/values-az/strings.xml b/core/res/res/values-az/strings.xml
index 6464c6126e82..44bcd565051e 100644
--- a/core/res/res/values-az/strings.xml
+++ b/core/res/res/values-az/strings.xml
@@ -514,6 +514,7 @@
<string name="permdesc_imagesWrite" msgid="7073662756617474375">"Tətbiqin foto kolleksiyanıza düzəliş etməsinə icazə verir."</string>
<string name="permlab_mediaLocation" msgid="8675148183726247864">"media kolleksiyanızdan məkanları oxuyun"</string>
<string name="permdesc_mediaLocation" msgid="2237023389178865130">"Tətbiqin media kolleksiyanızdan məkanları oxumasına icazə verin."</string>
+ <string name="biometric_error_hw_unavailable" msgid="645781226537551036">"Biometrik proqram əlçatan deyil"</string>
<string name="fingerprint_acquired_partial" msgid="735082772341716043">"Barmaq qismən müəyyən olundu. Lütfən, yenidən cəhd edin."</string>
<string name="fingerprint_acquired_insufficient" msgid="4596546021310923214">"Barmaq izi tanınmadı. Lütfən, yenidən cəhd edin."</string>
<string name="fingerprint_acquired_imager_dirty" msgid="1087209702421076105">"Barmaq izi sensoru çirklidir. Lütfən, təmizləyin və yenidən cəhd edin."</string>
@@ -521,7 +522,7 @@
<string name="fingerprint_acquired_too_slow" msgid="59250885689661653">"Barmağınızı çox yavaş hərəkət etdirdiniz. Lütfən, yenidən cəhd edin."</string>
<string-array name="fingerprint_acquired_vendor">
</string-array>
- <string name="fingerprint_not_recognized" msgid="2690661881608146617">"Tanınmır"</string>
+ <string name="biometric_not_recognized" msgid="5770511773560736082">"Tanınmır"</string>
<string name="fingerprint_authenticated" msgid="5309333983002526448">"Barmaq izi doğrulandı"</string>
<string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"Barmaq izi üçün avadanlıq yoxdur."</string>
<string name="fingerprint_error_no_space" msgid="1055819001126053318">"Barmaq izi saxlana bilməz. Lütfən, mövcud barmaq izini silin."</string>
diff --git a/core/res/res/values-b+sr+Latn/strings.xml b/core/res/res/values-b+sr+Latn/strings.xml
index 4d31b1b23c85..260f63efb6d9 100644
--- a/core/res/res/values-b+sr+Latn/strings.xml
+++ b/core/res/res/values-b+sr+Latn/strings.xml
@@ -517,6 +517,7 @@
<string name="permdesc_imagesWrite" msgid="7073662756617474375">"Dozvoljava aplikaciji da menja kolekciju slika."</string>
<string name="permlab_mediaLocation" msgid="8675148183726247864">"čitanje lokacija iz medijske kolekcije"</string>
<string name="permdesc_mediaLocation" msgid="2237023389178865130">"Dozvoljava aplikaciji da čita lokacije iz medijske kolekcije."</string>
+ <string name="biometric_error_hw_unavailable" msgid="645781226537551036">"Biometrijski hardver nije dostupan"</string>
<string name="fingerprint_acquired_partial" msgid="735082772341716043">"Otkriven je delimični otisak prsta. Probajte ponovo."</string>
<string name="fingerprint_acquired_insufficient" msgid="4596546021310923214">"Nije uspela obrada otiska prsta. Probajte ponovo."</string>
<string name="fingerprint_acquired_imager_dirty" msgid="1087209702421076105">"Senzor za otiske prstiju je prljav. Očistite ga i pokušajte ponovo."</string>
@@ -524,7 +525,7 @@
<string name="fingerprint_acquired_too_slow" msgid="59250885689661653">"Previše sporo ste pomerili prst. Probajte ponovo."</string>
<string-array name="fingerprint_acquired_vendor">
</string-array>
- <string name="fingerprint_not_recognized" msgid="2690661881608146617">"Nije prepoznat"</string>
+ <string name="biometric_not_recognized" msgid="5770511773560736082">"Nije prepoznato"</string>
<string name="fingerprint_authenticated" msgid="5309333983002526448">"Otisak prsta je potvrđen"</string>
<string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"Hardver za otiske prstiju nije dostupan."</string>
<string name="fingerprint_error_no_space" msgid="1055819001126053318">"Nije moguće sačuvati otisak prsta. Uklonite neki od postojećih otisaka prstiju."</string>
diff --git a/core/res/res/values-be/strings.xml b/core/res/res/values-be/strings.xml
index 77223d7512f1..3d46662c996e 100644
--- a/core/res/res/values-be/strings.xml
+++ b/core/res/res/values-be/strings.xml
@@ -520,6 +520,7 @@
<string name="permdesc_imagesWrite" msgid="7073662756617474375">"Праграма зможа змяняць фотакалекцыю."</string>
<string name="permlab_mediaLocation" msgid="8675148183726247864">"паказваць месцазнаходжанне ў калекцыі мультымедыя"</string>
<string name="permdesc_mediaLocation" msgid="2237023389178865130">"Праграма зможа паказваць месцазнаходжанне ў калекцыі мультымедыя."</string>
+ <string name="biometric_error_hw_unavailable" msgid="645781226537551036">"Біяметрычнае абсталяванне недаступнае"</string>
<string name="fingerprint_acquired_partial" msgid="735082772341716043">"Выяўлена частка адбіткаў пальцаў. Паспрабуйце яшчэ раз."</string>
<string name="fingerprint_acquired_insufficient" msgid="4596546021310923214">"Не атрымалася апрацаваць адбітак пальца. Паспрабуйце яшчэ раз."</string>
<string name="fingerprint_acquired_imager_dirty" msgid="1087209702421076105">"Датчык адбіткаў пальцаў брудны. Ачысціце яго і паспрабуйце яшчэ раз."</string>
@@ -527,7 +528,7 @@
<string name="fingerprint_acquired_too_slow" msgid="59250885689661653">"Палец рухаўся занадта павольна. Паспрабуйце яшчэ раз."</string>
<string-array name="fingerprint_acquired_vendor">
</string-array>
- <string name="fingerprint_not_recognized" msgid="2690661881608146617">"Не распазнаны"</string>
+ <string name="biometric_not_recognized" msgid="5770511773560736082">"Не распазнана"</string>
<string name="fingerprint_authenticated" msgid="5309333983002526448">"Адбітак пальца распазнаны"</string>
<string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"Апаратныя сродкі адбіткаў пальцаў недаступныя."</string>
<string name="fingerprint_error_no_space" msgid="1055819001126053318">"Адбіткі пальцаў нельга захаваць. Выдаліце існы адбітак."</string>
diff --git a/core/res/res/values-bg/strings.xml b/core/res/res/values-bg/strings.xml
index 3fc31f07f534..e9ecba6b272b 100644
--- a/core/res/res/values-bg/strings.xml
+++ b/core/res/res/values-bg/strings.xml
@@ -514,6 +514,7 @@
<string name="permdesc_imagesWrite" msgid="7073662756617474375">"Разрешава на приложението да променя колекцията ви от снимки."</string>
<string name="permlab_mediaLocation" msgid="8675148183726247864">"да чете местоположенията от мултимедийната ви колекция"</string>
<string name="permdesc_mediaLocation" msgid="2237023389178865130">"Разрешава на приложението да чете местоположенията от мултимедийната ви колекция."</string>
+ <string name="biometric_error_hw_unavailable" msgid="645781226537551036">"Биометричният хардуер не е налице"</string>
<string name="fingerprint_acquired_partial" msgid="735082772341716043">"Открит е частичен отпечатък. Моля, опитайте отново."</string>
<string name="fingerprint_acquired_insufficient" msgid="4596546021310923214">"Отпечатъкът не можа да се обработи. Моля, опитайте отново."</string>
<string name="fingerprint_acquired_imager_dirty" msgid="1087209702421076105">"Сензорът за отпечатъци е мръсен. Моля, почистете го и опитайте отново."</string>
@@ -521,7 +522,7 @@
<string name="fingerprint_acquired_too_slow" msgid="59250885689661653">"Преместихте пръста си твърде бавно. Моля, опитайте отново."</string>
<string-array name="fingerprint_acquired_vendor">
</string-array>
- <string name="fingerprint_not_recognized" msgid="2690661881608146617">"Не е разпознато"</string>
+ <string name="biometric_not_recognized" msgid="5770511773560736082">"Не е разпознато"</string>
<string name="fingerprint_authenticated" msgid="5309333983002526448">"Отпечатъкът е удостоверен"</string>
<string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"Хардуерът за отпечатъци не е налице."</string>
<string name="fingerprint_error_no_space" msgid="1055819001126053318">"Отпечатъкът не може да бъде съхранен. Моля, премахнете съществуващ."</string>
diff --git a/core/res/res/values-bn/strings.xml b/core/res/res/values-bn/strings.xml
index e7990ca52991..4ece21bea213 100644
--- a/core/res/res/values-bn/strings.xml
+++ b/core/res/res/values-bn/strings.xml
@@ -514,6 +514,7 @@
<string name="permdesc_imagesWrite" msgid="7073662756617474375">"অ্যাপকে আপনার ফটো সংগ্রহ পরিবর্তন করার অনুমতি দিন।"</string>
<string name="permlab_mediaLocation" msgid="8675148183726247864">"ডিয়া সংগ্রহ থেকে লোকেশন দেখতে দিন"</string>
<string name="permdesc_mediaLocation" msgid="2237023389178865130">"আপনার মিডিয়া সংগ্রহ থেকে লোকেশন দেখতে অ্যাপকে অনুমতি দিন।"</string>
+ <string name="biometric_error_hw_unavailable" msgid="645781226537551036">"বায়োমেট্রিক হার্ডওয়্যার পাওয়া যাবে না"</string>
<string name="fingerprint_acquired_partial" msgid="735082772341716043">"আঙ্গুলের ছাপ আংশিক শনাক্ত করা হয়েছে৷ অনুগ্রহ করে আবার চেষ্টা করুন৷"</string>
<string name="fingerprint_acquired_insufficient" msgid="4596546021310923214">"আঙ্গুলের ছাপ প্রক্রিয়া করা যায়নি৷ অনুগ্রহ করে আবার চেষ্টা করুন৷"</string>
<string name="fingerprint_acquired_imager_dirty" msgid="1087209702421076105">"আঙ্গুলের ছাপ নেওয়ার সেন্সরটি অপরিস্কার৷ অনুগ্রহ করে পরিষ্কার করে আবার চেষ্টা করুন৷"</string>
@@ -521,7 +522,7 @@
<string name="fingerprint_acquired_too_slow" msgid="59250885689661653">"আঙ্গুল খুব ধীরে সরানো হয়েছে৷ অনুগ্রহ করে আবার চেষ্টা করুন৷"</string>
<string-array name="fingerprint_acquired_vendor">
</string-array>
- <string name="fingerprint_not_recognized" msgid="2690661881608146617">"স্বীকৃত নয়"</string>
+ <string name="biometric_not_recognized" msgid="5770511773560736082">"স্বীকৃত নয়"</string>
<string name="fingerprint_authenticated" msgid="5309333983002526448">"আঙ্গুলের ছাপ যাচাই করা হয়েছে"</string>
<string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"আঙ্গুলের ছাপ নেওয়ার হার্ডওয়্যার অনুপলব্ধ৷"</string>
<string name="fingerprint_error_no_space" msgid="1055819001126053318">"আঙ্গুলের ছাপ সংরক্ষণ করা যাবে না৷ অনুগ্রহ করে একটি বিদ্যমান আঙ্গুলের ছাপ সরান৷"</string>
diff --git a/core/res/res/values-bs/strings.xml b/core/res/res/values-bs/strings.xml
index 244af735a431..918ecf98be5c 100644
--- a/core/res/res/values-bs/strings.xml
+++ b/core/res/res/values-bs/strings.xml
@@ -517,6 +517,7 @@
<string name="permdesc_imagesWrite" msgid="7073662756617474375">"Omogućava aplikaciji da mijenja vašu kolekciju fotografija."</string>
<string name="permlab_mediaLocation" msgid="8675148183726247864">"čitanje lokacija iz kolekcije medija"</string>
<string name="permdesc_mediaLocation" msgid="2237023389178865130">"Omogućava aplikaciji da čita lokacije iz vaše kolekcije medija."</string>
+ <string name="biometric_error_hw_unavailable" msgid="645781226537551036">"Biometrijski hardver nije dostupan"</string>
<string name="fingerprint_acquired_partial" msgid="735082772341716043">"Otkriven je djelomičan otisak prsta. Pokušajte ponovo."</string>
<string name="fingerprint_acquired_insufficient" msgid="4596546021310923214">"Nije uspjela obrada otiska prsta. Pokušajte ponovo."</string>
<string name="fingerprint_acquired_imager_dirty" msgid="1087209702421076105">"Senzor za otisak prsta je prljav. Očistite ga i pokušajte ponovo."</string>
@@ -524,7 +525,7 @@
<string name="fingerprint_acquired_too_slow" msgid="59250885689661653">"Prst je uklonjen presporo. Pokušajte ponovo."</string>
<string-array name="fingerprint_acquired_vendor">
</string-array>
- <string name="fingerprint_not_recognized" msgid="2690661881608146617">"Nije prepoznato"</string>
+ <string name="biometric_not_recognized" msgid="5770511773560736082">"Nije prepoznato"</string>
<string name="fingerprint_authenticated" msgid="5309333983002526448">"Otisak prsta je potvrđen"</string>
<string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"Hardver za otisak prsta nije dostupan."</string>
<string name="fingerprint_error_no_space" msgid="1055819001126053318">"Otisak prsta se ne može pohraniti. Uklonite postojeći otisak prsta."</string>
diff --git a/core/res/res/values-ca/strings.xml b/core/res/res/values-ca/strings.xml
index 2c74e8247852..f6c46ba09a98 100644
--- a/core/res/res/values-ca/strings.xml
+++ b/core/res/res/values-ca/strings.xml
@@ -216,7 +216,7 @@
<string name="global_actions" product="default" msgid="2406416831541615258">"Opcions del telèfon"</string>
<string name="global_action_lock" msgid="2844945191792119712">"Bloqueig de pantalla"</string>
<string name="global_action_power_off" msgid="4471879440839879722">"Apaga"</string>
- <string name="global_action_emergency" msgid="7112311161137421166">"Emergències"</string>
+ <string name="global_action_emergency" msgid="7112311161137421166">"Emergència"</string>
<string name="global_action_bug_report" msgid="7934010578922304799">"Informe d\'error"</string>
<string name="global_action_logout" msgid="935179188218826050">"Finalitza la sessió"</string>
<string name="global_action_screenshot" msgid="8329831278085426283">"Captura de pantalla"</string>
@@ -514,6 +514,7 @@
<string name="permdesc_imagesWrite" msgid="7073662756617474375">"Permet que l\'aplicació modifiqui la teva col·lecció de fotos."</string>
<string name="permlab_mediaLocation" msgid="8675148183726247864">"llegir les ubicacions de les teves col·leccions multimèdia"</string>
<string name="permdesc_mediaLocation" msgid="2237023389178865130">"Permet que l\'aplicació llegeixi les ubicacions de les teves col·leccions multimèdia."</string>
+ <string name="biometric_error_hw_unavailable" msgid="645781226537551036">"Maquinari biomètric no disponible"</string>
<string name="fingerprint_acquired_partial" msgid="735082772341716043">"S\'ha detectat una empremta digital parcial. Torna-ho a provar."</string>
<string name="fingerprint_acquired_insufficient" msgid="4596546021310923214">"No s\'ha pogut processar l\'empremta digital. Torna-ho a provar."</string>
<string name="fingerprint_acquired_imager_dirty" msgid="1087209702421076105">"El sensor d\'empremtes digitals està brut. Neteja\'l i torna-ho a provar."</string>
@@ -521,7 +522,7 @@
<string name="fingerprint_acquired_too_slow" msgid="59250885689661653">"El dit s\'ha mogut massa lentament. Torna-ho a provar."</string>
<string-array name="fingerprint_acquired_vendor">
</string-array>
- <string name="fingerprint_not_recognized" msgid="2690661881608146617">"No s\'ha reconegut"</string>
+ <string name="biometric_not_recognized" msgid="5770511773560736082">"No s\'ha reconegut"</string>
<string name="fingerprint_authenticated" msgid="5309333983002526448">"L\'empremta digital s\'ha autenticat"</string>
<string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"El maquinari per a empremtes digitals no està disponible."</string>
<string name="fingerprint_error_no_space" msgid="1055819001126053318">"L\'empremta digital no es pot desar. Suprimeix-ne una."</string>
diff --git a/core/res/res/values-cs/strings.xml b/core/res/res/values-cs/strings.xml
index 278ab95706c4..e882f427b577 100644
--- a/core/res/res/values-cs/strings.xml
+++ b/core/res/res/values-cs/strings.xml
@@ -520,6 +520,7 @@
<string name="permdesc_imagesWrite" msgid="7073662756617474375">"Umožňuje aplikaci upravit vaši sbírku fotek."</string>
<string name="permlab_mediaLocation" msgid="8675148183726247864">"čtení míst ze sbírky médií"</string>
<string name="permdesc_mediaLocation" msgid="2237023389178865130">"Umožňuje aplikaci číst místa z vaší sbírky médií."</string>
+ <string name="biometric_error_hw_unavailable" msgid="645781226537551036">"Biometrický hardware není k dispozici"</string>
<string name="fingerprint_acquired_partial" msgid="735082772341716043">"Byla zjištěna jen část otisku prstu. Zkuste to znovu."</string>
<string name="fingerprint_acquired_insufficient" msgid="4596546021310923214">"Zpracování otisku prstu se nezdařilo. Zkuste to znovu."</string>
<string name="fingerprint_acquired_imager_dirty" msgid="1087209702421076105">"Senzor otisků prstů je znečištěn. Vyčistěte jej a zkuste to znovu."</string>
@@ -527,7 +528,7 @@
<string name="fingerprint_acquired_too_slow" msgid="59250885689661653">"Pohyb prstem byl příliš pomalý. Zkuste to znovu."</string>
<string-array name="fingerprint_acquired_vendor">
</string-array>
- <string name="fingerprint_not_recognized" msgid="2690661881608146617">"Nerozpoznáno"</string>
+ <string name="biometric_not_recognized" msgid="5770511773560736082">"Nerozpoznáno"</string>
<string name="fingerprint_authenticated" msgid="5309333983002526448">"Otisk byl ověřen"</string>
<string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"Není k dispozici hardware ke snímání otisků prstů."</string>
<string name="fingerprint_error_no_space" msgid="1055819001126053318">"Otisk prstu nelze uložit. Odstraňte existující otisk prstu."</string>
diff --git a/core/res/res/values-da/strings.xml b/core/res/res/values-da/strings.xml
index 32be0d34f57d..9a793a879da9 100644
--- a/core/res/res/values-da/strings.xml
+++ b/core/res/res/values-da/strings.xml
@@ -383,13 +383,13 @@
<string name="permdesc_broadcastSticky" product="tv" msgid="6839285697565389467">"Giver appen lov til at sende klæbende udsendelser, som ikke forsvinder, når udsendelsen er slut. Overdreven brug kan gøre fjernsynet langsomt eller ustabilt ved at få det til at bruge for meget hukommelse."</string>
<string name="permdesc_broadcastSticky" product="default" msgid="2825803764232445091">"Tillader, at appen kan sende klæbende udsendelser, der forbliver tilbage, når udsendelsen er slut. Overdreven brug kan gøre din telefon langsom eller ustabil ved at tvinge den til at bruge for meget hukommelse."</string>
<string name="permlab_readContacts" msgid="8348481131899886131">"læse dine kontaktpersoner"</string>
- <string name="permdesc_readContacts" product="tablet" msgid="5294866856941149639">"Tillader, at appen kan læse data om de kontaktpersoner, der er gemt på din tablet, f.eks. hvor ofte du har ringet til, sendt mail til eller på anden måde kommunikeret med bestemte personer. Med denne tilladelse kan apps gemme dine kontaktdata, og skadelige apps kan dele kontaktdata uden din viden."</string>
- <string name="permdesc_readContacts" product="tv" msgid="1839238344654834087">"Giver appen lov til at læse data om dine kontaktpersoner, der er gemt på dit tv, herunder hvor ofte du har ringet, mailet eller på andre måder kommunikeret med bestemte personer. Denne tilladelse gør det muligt for apps at gemme dine kontaktoplysninger, og ondsindede apps kan dele kontaktoplysninger uden din viden."</string>
- <string name="permdesc_readContacts" product="default" msgid="8440654152457300662">"Tillader, at appen kan læse data om de kontaktpersoner, der er gemt på din telefon, f.eks. hvor ofte du har ringet til, sendt mail til eller på anden måde kommunikeret med bestemte personer. Med denne tilladelse kan apps gemme dine kontaktdata, og skadelige apps kan dele kontaktdata uden din viden."</string>
+ <string name="permdesc_readContacts" product="tablet" msgid="5294866856941149639">"Tillader, at appen kan læse data om de kontakter, der er gemt på din tablet, f.eks. hvor ofte du har ringet til, sendt mail til eller på anden måde kommunikeret med bestemte personer. Med denne tilladelse kan apps gemme dine kontaktdata, og skadelige apps kan dele kontaktdata uden din viden."</string>
+ <string name="permdesc_readContacts" product="tv" msgid="1839238344654834087">"Giver appen lov til at læse data om dine kontakter, der er gemt på dit tv, herunder hvor ofte du har ringet, mailet eller på andre måder kommunikeret med bestemte personer. Denne tilladelse gør det muligt for apps at gemme dine kontaktoplysninger, og ondsindede apps kan dele kontaktoplysninger uden din viden."</string>
+ <string name="permdesc_readContacts" product="default" msgid="8440654152457300662">"Tillader, at appen kan læse data om de kontakter, der er gemt på din telefon, f.eks. hvor ofte du har ringet til, sendt mail til eller på anden måde kommunikeret med bestemte personer. Med denne tilladelse kan apps gemme dine kontaktdata, og skadelige apps kan dele kontaktdata uden din viden."</string>
<string name="permlab_writeContacts" msgid="5107492086416793544">"ændre dine kontaktpersoner"</string>
- <string name="permdesc_writeContacts" product="tablet" msgid="897243932521953602">"Tillader, at appen kan ændre data om de kontaktpersoner, der er gemt på din tablet, f.eks. hvor ofte du har ringet til dem, sendt dem en mail eller på anden måde kommunikeret med bestemte kontaktpersoner. Med denne tilladelse kan apps slette kontaktoplysninger."</string>
- <string name="permdesc_writeContacts" product="tv" msgid="5438230957000018959">"Giver appen lov til at ændre data om dine kontaktpersoner, der er gemt på dit tv, herunder hvor ofte du har ringet, mailet eller på anden måde kommunikeret med bestemte kontaktpersoner. Denne tilladelse gør det muligt for apps at slette kontaktoplysninger."</string>
- <string name="permdesc_writeContacts" product="default" msgid="589869224625163558">"Tillader, at appen kan ændre data om de kontaktpersoner, der er gemt på din telefon, f.eks. hvor ofte du har ringet til dem, sendt en mail til dem eller på anden måde kommunikeret med bestemte kontaktpersoner. Med denne tilladelse kan apps slette kontaktoplysninger."</string>
+ <string name="permdesc_writeContacts" product="tablet" msgid="897243932521953602">"Tillader, at appen kan ændre data om de kontakter, der er gemt på din tablet, f.eks. hvor ofte du har ringet til dem, sendt dem en mail eller på anden måde kommunikeret med bestemte kontakter. Med denne tilladelse kan apps slette kontaktoplysninger."</string>
+ <string name="permdesc_writeContacts" product="tv" msgid="5438230957000018959">"Giver appen lov til at ændre data om dine kontakter, der er gemt på dit tv, herunder hvor ofte du har ringet, mailet eller på anden måde kommunikeret med bestemte kontakter. Denne tilladelse gør det muligt for apps at slette kontaktoplysninger."</string>
+ <string name="permdesc_writeContacts" product="default" msgid="589869224625163558">"Tillader, at appen kan ændre data om de kontakter, der er gemt på din telefon, f.eks. hvor ofte du har ringet til dem, sendt en mail til dem eller på anden måde kommunikeret med bestemte kontakter. Med denne tilladelse kan apps slette kontaktoplysninger."</string>
<string name="permlab_readCallLog" msgid="3478133184624102739">"læse opkaldsliste"</string>
<string name="permdesc_readCallLog" msgid="3204122446463552146">"Denne app kan læse din opkaldshistorik."</string>
<string name="permlab_writeCallLog" msgid="8552045664743499354">"skriv opkaldsliste"</string>
@@ -514,6 +514,7 @@
<string name="permdesc_imagesWrite" msgid="7073662756617474375">"Tillader, at appen kan ændre din billedsamling."</string>
<string name="permlab_mediaLocation" msgid="8675148183726247864">"læse placeringer fra din mediesamling"</string>
<string name="permdesc_mediaLocation" msgid="2237023389178865130">"Tillader, at appen kan læse placeringer fra din mediesamling."</string>
+ <string name="biometric_error_hw_unavailable" msgid="645781226537551036">"Biometrisk hardware er ikke tilgængelig"</string>
<string name="fingerprint_acquired_partial" msgid="735082772341716043">"Der blev registreret et delvist fingeraftryk. Prøv igen."</string>
<string name="fingerprint_acquired_insufficient" msgid="4596546021310923214">"Fingeraftrykket kunne ikke behandles. Prøv igen."</string>
<string name="fingerprint_acquired_imager_dirty" msgid="1087209702421076105">"Sensoren til registrering af fingeraftryk er beskidt. Tør den af, og prøv igen."</string>
@@ -521,7 +522,7 @@
<string name="fingerprint_acquired_too_slow" msgid="59250885689661653">"Du bevægede fingeren for langsomt. Prøv igen."</string>
<string-array name="fingerprint_acquired_vendor">
</string-array>
- <string name="fingerprint_not_recognized" msgid="2690661881608146617">"Ikke genkendt"</string>
+ <string name="biometric_not_recognized" msgid="5770511773560736082">"Ikke genkendt"</string>
<string name="fingerprint_authenticated" msgid="5309333983002526448">"Fingeraftrykket blev godkendt"</string>
<string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"Hardwaren til fingeraftryk er ikke tilgængelig."</string>
<string name="fingerprint_error_no_space" msgid="1055819001126053318">"Fingeraftrykket kan ikke gemmes. Fjern et eksisterende fingeraftryk."</string>
diff --git a/core/res/res/values-de/strings.xml b/core/res/res/values-de/strings.xml
index e5b9372d25cf..8eb0eb89825d 100644
--- a/core/res/res/values-de/strings.xml
+++ b/core/res/res/values-de/strings.xml
@@ -514,6 +514,7 @@
<string name="permdesc_imagesWrite" msgid="7073662756617474375">"Ermöglicht der App, deine Fotosammlung zu ändern."</string>
<string name="permlab_mediaLocation" msgid="8675148183726247864">"Standorte aus meiner Mediensammlung abrufen"</string>
<string name="permdesc_mediaLocation" msgid="2237023389178865130">"Ermöglicht der App, Standorte aus deiner Mediensammlung abzurufen."</string>
+ <string name="biometric_error_hw_unavailable" msgid="645781226537551036">"Biometrische Hardware nicht verfügbar"</string>
<string name="fingerprint_acquired_partial" msgid="735082772341716043">"Fingerabdruck teilweise erkannt. Versuche es erneut."</string>
<string name="fingerprint_acquired_insufficient" msgid="4596546021310923214">"Fingerabdruck konnte nicht verarbeitet werden. Versuche es erneut."</string>
<string name="fingerprint_acquired_imager_dirty" msgid="1087209702421076105">"Fingerabdrucksensor ist verschmutzt. Reinige ihn und versuche es erneut."</string>
@@ -521,7 +522,7 @@
<string name="fingerprint_acquired_too_slow" msgid="59250885689661653">"Finger zu langsam bewegt. Versuche es erneut."</string>
<string-array name="fingerprint_acquired_vendor">
</string-array>
- <string name="fingerprint_not_recognized" msgid="2690661881608146617">"Nicht erkannt"</string>
+ <string name="biometric_not_recognized" msgid="5770511773560736082">"Nicht erkannt"</string>
<string name="fingerprint_authenticated" msgid="5309333983002526448">"Fingerabdruck wurde authentifiziert"</string>
<string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"Fingerabdruckhardware nicht verfügbar"</string>
<string name="fingerprint_error_no_space" msgid="1055819001126053318">"Fingerabdruck kann nicht gespeichert werden. Entferne einen vorhandenen Fingerabdruck."</string>
diff --git a/core/res/res/values-el/strings.xml b/core/res/res/values-el/strings.xml
index 482e29f39715..3a50f9e7d0f8 100644
--- a/core/res/res/values-el/strings.xml
+++ b/core/res/res/values-el/strings.xml
@@ -514,6 +514,7 @@
<string name="permdesc_imagesWrite" msgid="7073662756617474375">"Επιτρέπει στην εφαρμογή να τροποποιήσει τη συλλογή φωτογραφιών σας."</string>
<string name="permlab_mediaLocation" msgid="8675148183726247864">"ανάγνωση τοποθεσιών από τη συλλογή πολυμέσων σας"</string>
<string name="permdesc_mediaLocation" msgid="2237023389178865130">"Επιτρέπει στην εφαρμογή να διαβάσει τοποθεσίες από τη συλλογή πολυμέσων σας."</string>
+ <string name="biometric_error_hw_unavailable" msgid="645781226537551036">"Δεν υπάρχει διαθέσιμος βιομετρικός εξοπλισμός"</string>
<string name="fingerprint_acquired_partial" msgid="735082772341716043">"Εντοπίστηκε μερικό μοναδικό χαρακτηριστικό. Δοκιμάστε ξανά."</string>
<string name="fingerprint_acquired_insufficient" msgid="4596546021310923214">"Δεν ήταν δυνατή η επεξεργασία του μοναδικού χαρακτηριστικού. Δοκιμάστε ξανά."</string>
<string name="fingerprint_acquired_imager_dirty" msgid="1087209702421076105">"Ο αισθητήρας μοναδικού χαρακτηριστικού δεν είναι καθαρός. Καθαρίστε τον και δοκιμάστε ξανά."</string>
@@ -521,7 +522,7 @@
<string name="fingerprint_acquired_too_slow" msgid="59250885689661653">"Πολύ αργή κίνηση δαχτύλου. Δοκιμάστε ξανά."</string>
<string-array name="fingerprint_acquired_vendor">
</string-array>
- <string name="fingerprint_not_recognized" msgid="2690661881608146617">"Δεν αναγνωρίστηκε"</string>
+ <string name="biometric_not_recognized" msgid="5770511773560736082">"Δεν αναγνωρίστηκε"</string>
<string name="fingerprint_authenticated" msgid="5309333983002526448">"Η ταυτότητα του δακτυλικού αποτυπώματος ελέγχθηκε"</string>
<string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"Ο εξοπλισμός μοναδικού χαρακτηριστικού δεν είναι διαθέσιμος."</string>
<string name="fingerprint_error_no_space" msgid="1055819001126053318">"Δεν είναι δυνατή η αποθήκευση μοναδικού χαρακτηριστικού. Καταργήστε το υπάρχον μοναδικό χαρακτηριστικό."</string>
diff --git a/core/res/res/values-en-rAU/strings.xml b/core/res/res/values-en-rAU/strings.xml
index 19d0916de752..04b20ba076d5 100644
--- a/core/res/res/values-en-rAU/strings.xml
+++ b/core/res/res/values-en-rAU/strings.xml
@@ -514,6 +514,7 @@
<string name="permdesc_imagesWrite" msgid="7073662756617474375">"Allows the app to modify your photo collection."</string>
<string name="permlab_mediaLocation" msgid="8675148183726247864">"read locations from your media collection"</string>
<string name="permdesc_mediaLocation" msgid="2237023389178865130">"Allows the app to read locations from your media collection."</string>
+ <string name="biometric_error_hw_unavailable" msgid="645781226537551036">"Biometric hardware unavailable"</string>
<string name="fingerprint_acquired_partial" msgid="735082772341716043">"Partial fingerprint detected. Please try again."</string>
<string name="fingerprint_acquired_insufficient" msgid="4596546021310923214">"Couldn\'t process fingerprint. Please try again."</string>
<string name="fingerprint_acquired_imager_dirty" msgid="1087209702421076105">"Fingerprint sensor is dirty. Please clean and try again."</string>
@@ -521,7 +522,7 @@
<string name="fingerprint_acquired_too_slow" msgid="59250885689661653">"Finger moved too slow. Please try again."</string>
<string-array name="fingerprint_acquired_vendor">
</string-array>
- <string name="fingerprint_not_recognized" msgid="2690661881608146617">"Not recognised"</string>
+ <string name="biometric_not_recognized" msgid="5770511773560736082">"Not recognised"</string>
<string name="fingerprint_authenticated" msgid="5309333983002526448">"Fingerprint authenticated"</string>
<string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"Fingerprint hardware not available."</string>
<string name="fingerprint_error_no_space" msgid="1055819001126053318">"Fingerprint can\'t be stored. Please remove an existing fingerprint."</string>
diff --git a/core/res/res/values-en-rCA/strings.xml b/core/res/res/values-en-rCA/strings.xml
index 1e2e0816df86..c1ca0c4a279a 100644
--- a/core/res/res/values-en-rCA/strings.xml
+++ b/core/res/res/values-en-rCA/strings.xml
@@ -514,6 +514,7 @@
<string name="permdesc_imagesWrite" msgid="7073662756617474375">"Allows the app to modify your photo collection."</string>
<string name="permlab_mediaLocation" msgid="8675148183726247864">"read locations from your media collection"</string>
<string name="permdesc_mediaLocation" msgid="2237023389178865130">"Allows the app to read locations from your media collection."</string>
+ <string name="biometric_error_hw_unavailable" msgid="645781226537551036">"Biometric hardware unavailable"</string>
<string name="fingerprint_acquired_partial" msgid="735082772341716043">"Partial fingerprint detected. Please try again."</string>
<string name="fingerprint_acquired_insufficient" msgid="4596546021310923214">"Couldn\'t process fingerprint. Please try again."</string>
<string name="fingerprint_acquired_imager_dirty" msgid="1087209702421076105">"Fingerprint sensor is dirty. Please clean and try again."</string>
@@ -521,7 +522,7 @@
<string name="fingerprint_acquired_too_slow" msgid="59250885689661653">"Finger moved too slow. Please try again."</string>
<string-array name="fingerprint_acquired_vendor">
</string-array>
- <string name="fingerprint_not_recognized" msgid="2690661881608146617">"Not recognised"</string>
+ <string name="biometric_not_recognized" msgid="5770511773560736082">"Not recognised"</string>
<string name="fingerprint_authenticated" msgid="5309333983002526448">"Fingerprint authenticated"</string>
<string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"Fingerprint hardware not available."</string>
<string name="fingerprint_error_no_space" msgid="1055819001126053318">"Fingerprint can\'t be stored. Please remove an existing fingerprint."</string>
diff --git a/core/res/res/values-en-rGB/strings.xml b/core/res/res/values-en-rGB/strings.xml
index 19d0916de752..04b20ba076d5 100644
--- a/core/res/res/values-en-rGB/strings.xml
+++ b/core/res/res/values-en-rGB/strings.xml
@@ -514,6 +514,7 @@
<string name="permdesc_imagesWrite" msgid="7073662756617474375">"Allows the app to modify your photo collection."</string>
<string name="permlab_mediaLocation" msgid="8675148183726247864">"read locations from your media collection"</string>
<string name="permdesc_mediaLocation" msgid="2237023389178865130">"Allows the app to read locations from your media collection."</string>
+ <string name="biometric_error_hw_unavailable" msgid="645781226537551036">"Biometric hardware unavailable"</string>
<string name="fingerprint_acquired_partial" msgid="735082772341716043">"Partial fingerprint detected. Please try again."</string>
<string name="fingerprint_acquired_insufficient" msgid="4596546021310923214">"Couldn\'t process fingerprint. Please try again."</string>
<string name="fingerprint_acquired_imager_dirty" msgid="1087209702421076105">"Fingerprint sensor is dirty. Please clean and try again."</string>
@@ -521,7 +522,7 @@
<string name="fingerprint_acquired_too_slow" msgid="59250885689661653">"Finger moved too slow. Please try again."</string>
<string-array name="fingerprint_acquired_vendor">
</string-array>
- <string name="fingerprint_not_recognized" msgid="2690661881608146617">"Not recognised"</string>
+ <string name="biometric_not_recognized" msgid="5770511773560736082">"Not recognised"</string>
<string name="fingerprint_authenticated" msgid="5309333983002526448">"Fingerprint authenticated"</string>
<string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"Fingerprint hardware not available."</string>
<string name="fingerprint_error_no_space" msgid="1055819001126053318">"Fingerprint can\'t be stored. Please remove an existing fingerprint."</string>
diff --git a/core/res/res/values-en-rIN/strings.xml b/core/res/res/values-en-rIN/strings.xml
index 19d0916de752..04b20ba076d5 100644
--- a/core/res/res/values-en-rIN/strings.xml
+++ b/core/res/res/values-en-rIN/strings.xml
@@ -514,6 +514,7 @@
<string name="permdesc_imagesWrite" msgid="7073662756617474375">"Allows the app to modify your photo collection."</string>
<string name="permlab_mediaLocation" msgid="8675148183726247864">"read locations from your media collection"</string>
<string name="permdesc_mediaLocation" msgid="2237023389178865130">"Allows the app to read locations from your media collection."</string>
+ <string name="biometric_error_hw_unavailable" msgid="645781226537551036">"Biometric hardware unavailable"</string>
<string name="fingerprint_acquired_partial" msgid="735082772341716043">"Partial fingerprint detected. Please try again."</string>
<string name="fingerprint_acquired_insufficient" msgid="4596546021310923214">"Couldn\'t process fingerprint. Please try again."</string>
<string name="fingerprint_acquired_imager_dirty" msgid="1087209702421076105">"Fingerprint sensor is dirty. Please clean and try again."</string>
@@ -521,7 +522,7 @@
<string name="fingerprint_acquired_too_slow" msgid="59250885689661653">"Finger moved too slow. Please try again."</string>
<string-array name="fingerprint_acquired_vendor">
</string-array>
- <string name="fingerprint_not_recognized" msgid="2690661881608146617">"Not recognised"</string>
+ <string name="biometric_not_recognized" msgid="5770511773560736082">"Not recognised"</string>
<string name="fingerprint_authenticated" msgid="5309333983002526448">"Fingerprint authenticated"</string>
<string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"Fingerprint hardware not available."</string>
<string name="fingerprint_error_no_space" msgid="1055819001126053318">"Fingerprint can\'t be stored. Please remove an existing fingerprint."</string>
diff --git a/core/res/res/values-en-rXC/strings.xml b/core/res/res/values-en-rXC/strings.xml
index 68bc26163337..4add7752b58a 100644
--- a/core/res/res/values-en-rXC/strings.xml
+++ b/core/res/res/values-en-rXC/strings.xml
@@ -514,6 +514,7 @@
<string name="permdesc_imagesWrite" msgid="7073662756617474375">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‎‎‏‎‎‎‏‎‏‎‏‎‏‎‏‏‎‎‏‎‏‏‎‎‏‏‎‎‏‎‎‏‏‏‎‏‎‎‎‏‏‎‎‎‎‏‎‏‎‎‎‏‎‏‎‎‎‏‏‏‎Allows the app to modify your photo collection.‎‏‎‎‏‎"</string>
<string name="permlab_mediaLocation" msgid="8675148183726247864">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‎‎‎‎‏‏‎‎‏‎‎‎‏‎‏‎‎‎‏‎‏‎‎‏‏‏‏‎‏‏‎‏‎‎‎‏‏‏‎‎‎‎‎‏‏‎‎‏‏‏‏‏‎‏‏‏‎‎‎‎read locations from your media collection‎‏‎‎‏‎"</string>
<string name="permdesc_mediaLocation" msgid="2237023389178865130">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‏‏‏‏‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‎‏‏‏‎‏‎‏‏‏‎‎‏‎‎‏‎‎‎‏‏‏‏‏‏‎‎‏‎‎‏‎‏‏‏‏‎‏‎‏‎‎Allows the app to read locations from your media collection.‎‏‎‎‏‎"</string>
+ <string name="biometric_error_hw_unavailable" msgid="645781226537551036">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‎‏‎‎‎‏‏‏‏‎‏‏‎‎‏‎‎‎‏‏‎‏‎‎‏‏‎‏‎‏‎‏‎‎‎‏‎‎‏‏‎‎‎‏‏‎‎‎‎‎‏‎‎‏‎‏‏‏‏‎‎‎Biometric hardware unavailable‎‏‎‎‏‎"</string>
<string name="fingerprint_acquired_partial" msgid="735082772341716043">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‎‏‎‏‎‎‎‏‏‎‎‏‏‏‎‎‎‏‎‎‏‏‏‏‎‎‎‏‏‎‎‎‎‎‏‎‏‏‏‏‎‏‏‏‏‏‏‏‏‎‏‎‎‎‏‎‎‏‎‏‏‎Partial fingerprint detected. Please try again.‎‏‎‎‏‎"</string>
<string name="fingerprint_acquired_insufficient" msgid="4596546021310923214">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‏‏‏‏‏‏‎‎‏‎‏‎‎‎‏‏‎‏‏‎‎‏‎‎‎‎‎‎‏‎‏‏‏‎‎‏‏‏‏‏‏‎‎‏‎‎‎‎‎‎‎‏‏‏‎‎‏‏‏‎‎Couldn\'t process fingerprint. Please try again.‎‏‎‎‏‎"</string>
<string name="fingerprint_acquired_imager_dirty" msgid="1087209702421076105">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‎‏‏‏‏‎‎‎‏‎‏‏‎‏‎‎‎‏‎‏‏‎‏‏‏‎‏‏‎‏‏‎‎‏‏‎‏‎‎‏‎‏‎‏‎‏‎‎‏‏‎‎‎‏‎‎‎‏‎‎‏‎Fingerprint sensor is dirty. Please clean and try again.‎‏‎‎‏‎"</string>
@@ -521,7 +522,7 @@
<string name="fingerprint_acquired_too_slow" msgid="59250885689661653">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‎‎‎‏‏‎‏‎‎‏‎‏‎‎‎‎‎‎‎‎‏‎‏‏‏‎‏‏‏‎‏‏‎‏‎‎‎‏‎‏‎‎‎‏‏‎‏‏‎‎‎‏‏‎‏‎‏‎‏‎Finger moved too slow. Please try again.‎‏‎‎‏‎"</string>
<string-array name="fingerprint_acquired_vendor">
</string-array>
- <string name="fingerprint_not_recognized" msgid="2690661881608146617">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‎‏‎‏‎‏‎‏‎‏‏‏‎‎‏‎‎‏‏‎‏‎‏‏‏‎‎‏‏‎‏‏‏‏‏‏‏‏‏‏‎‎‎‎‎‎‎‎‏‏‏‎‏‎‏‏‏‎‎‏‎Not recognized‎‏‎‎‏‎"</string>
+ <string name="biometric_not_recognized" msgid="5770511773560736082">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‎‎‎‎‎‎‎‏‎‏‎‎‏‏‏‏‏‎‎‏‏‏‏‎‎‎‏‎‎‏‏‏‎‎‏‏‎‏‎‎‏‏‎‎‎‎‎‎‏‎‎‏‎‏‎‏‎‎‏‎‎Not recognized‎‏‎‎‏‎"</string>
<string name="fingerprint_authenticated" msgid="5309333983002526448">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‏‎‎‏‏‎‏‎‏‏‏‎‏‎‎‎‏‎‏‏‎‎‏‎‎‎‎‎‏‎‏‎‎‎‏‎‏‏‎‎‎‏‏‎‏‎‎‎‎‎‏‎‏‏‏‏‎‎‎‎‎Fingerprint authenticated‎‏‎‎‏‎"</string>
<string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‏‏‏‎‎‏‏‎‏‎‎‏‎‎‎‏‏‏‎‎‏‎‎‏‏‎‎‎‏‎‏‏‎‏‎‏‏‏‏‏‎‎‏‏‏‎‎‎‏‏‏‏‎‏‎‏‎‏‎‎‎Fingerprint hardware not available.‎‏‎‎‏‎"</string>
<string name="fingerprint_error_no_space" msgid="1055819001126053318">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‎‏‏‏‎‏‎‏‎‎‏‏‏‎‎‎‎‎‏‎‏‏‏‎‎‏‎‎‏‏‎‎‏‏‏‎‏‎‎‏‏‏‎‎‏‏‏‏‎‎‏‎‏‏‏‎‎‎‏‏‎‎Fingerprint can\'t be stored. Please remove an existing fingerprint.‎‏‎‎‏‎"</string>
diff --git a/core/res/res/values-es-rUS/strings.xml b/core/res/res/values-es-rUS/strings.xml
index 9969af373632..f317a4ecc2ea 100644
--- a/core/res/res/values-es-rUS/strings.xml
+++ b/core/res/res/values-es-rUS/strings.xml
@@ -514,6 +514,7 @@
<string name="permdesc_imagesWrite" msgid="7073662756617474375">"Permite que la app modifique tu colección de fotos."</string>
<string name="permlab_mediaLocation" msgid="8675148183726247864">"leer ubicaciones de tu colección de contenido multimedia"</string>
<string name="permdesc_mediaLocation" msgid="2237023389178865130">"Permite que la app lea las ubicaciones de tu colección de contenido multimedia."</string>
+ <string name="biometric_error_hw_unavailable" msgid="645781226537551036">"No hay hardware biométrico disponible"</string>
<string name="fingerprint_acquired_partial" msgid="735082772341716043">"La huella digital se detectó parcialmente. Vuelve a intentarlo."</string>
<string name="fingerprint_acquired_insufficient" msgid="4596546021310923214">"No se pudo procesar la huella digital. Vuelve a intentarlo."</string>
<string name="fingerprint_acquired_imager_dirty" msgid="1087209702421076105">"El sensor de huellas digitales está sucio. Limpia el sensor y vuelve a intentarlo."</string>
@@ -521,7 +522,7 @@
<string name="fingerprint_acquired_too_slow" msgid="59250885689661653">"Moviste el dedo muy lento. Vuelve a intentarlo."</string>
<string-array name="fingerprint_acquired_vendor">
</string-array>
- <string name="fingerprint_not_recognized" msgid="2690661881608146617">"No reconocido"</string>
+ <string name="biometric_not_recognized" msgid="5770511773560736082">"No se reconoció"</string>
<string name="fingerprint_authenticated" msgid="5309333983002526448">"Se autenticó la huella digital"</string>
<string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"El hardware para detectar huellas digitales no está disponible."</string>
<string name="fingerprint_error_no_space" msgid="1055819001126053318">"No se puede almacenar la huella digital. Elimina una de las existentes."</string>
diff --git a/core/res/res/values-es/strings.xml b/core/res/res/values-es/strings.xml
index e40a5462b40d..c42f53c8b21a 100644
--- a/core/res/res/values-es/strings.xml
+++ b/core/res/res/values-es/strings.xml
@@ -514,6 +514,7 @@
<string name="permdesc_imagesWrite" msgid="7073662756617474375">"Permite que la aplicación modifique tu colección de fotos."</string>
<string name="permlab_mediaLocation" msgid="8675148183726247864">"leer las ubicaciones de tu colección de contenido multimedia"</string>
<string name="permdesc_mediaLocation" msgid="2237023389178865130">"Permite que la aplicación lea las ubicaciones de tu colección de contenido multimedia."</string>
+ <string name="biometric_error_hw_unavailable" msgid="645781226537551036">"Hardware biométrico no disponible"</string>
<string name="fingerprint_acquired_partial" msgid="735082772341716043">"Se ha detectado una huella digital parcial. Vuelve a intentarlo."</string>
<string name="fingerprint_acquired_insufficient" msgid="4596546021310923214">"No se ha podido procesar la huella digital. Vuelve a intentarlo."</string>
<string name="fingerprint_acquired_imager_dirty" msgid="1087209702421076105">"El sensor de huellas digitales está sucio. Límpialo y vuelve a intentarlo."</string>
@@ -521,7 +522,7 @@
<string name="fingerprint_acquired_too_slow" msgid="59250885689661653">"Has movido el dedo demasiado despacio. Vuelve a intentarlo."</string>
<string-array name="fingerprint_acquired_vendor">
</string-array>
- <string name="fingerprint_not_recognized" msgid="2690661881608146617">"No reconocido"</string>
+ <string name="biometric_not_recognized" msgid="5770511773560736082">"No se reconoce"</string>
<string name="fingerprint_authenticated" msgid="5309333983002526448">"Se ha autenticado la huella digital"</string>
<string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"El hardware de huella digital no está disponible."</string>
<string name="fingerprint_error_no_space" msgid="1055819001126053318">"No se puede almacenar la huella digital. Elimina una ya creada."</string>
diff --git a/core/res/res/values-et/strings.xml b/core/res/res/values-et/strings.xml
index 56181c864e08..cc052c47289d 100644
--- a/core/res/res/values-et/strings.xml
+++ b/core/res/res/values-et/strings.xml
@@ -514,6 +514,7 @@
<string name="permdesc_imagesWrite" msgid="7073662756617474375">"Võimaldab rakendusel muuta teie fotokogu."</string>
<string name="permlab_mediaLocation" msgid="8675148183726247864">"Lugeda teie meediakogus olevaid asukohti"</string>
<string name="permdesc_mediaLocation" msgid="2237023389178865130">"Võimaldab rakendusel lugeda teie meediakogus olevaid asukohti."</string>
+ <string name="biometric_error_hw_unavailable" msgid="645781226537551036">"Biomeetriline riistvara ei ole saadaval"</string>
<string name="fingerprint_acquired_partial" msgid="735082772341716043">"Tuvastati osaline sõrmejälg. Proovige uuesti."</string>
<string name="fingerprint_acquired_insufficient" msgid="4596546021310923214">"Sõrmejälge ei õnnestunud töödelda. Proovige uuesti."</string>
<string name="fingerprint_acquired_imager_dirty" msgid="1087209702421076105">"Sõrmejäljeandur on must. Puhastage see ja proovige uuesti."</string>
@@ -521,7 +522,7 @@
<string name="fingerprint_acquired_too_slow" msgid="59250885689661653">"Sõrm liikus liiga aeglaselt. Proovige uuesti."</string>
<string-array name="fingerprint_acquired_vendor">
</string-array>
- <string name="fingerprint_not_recognized" msgid="2690661881608146617">"Ei tuvastatud"</string>
+ <string name="biometric_not_recognized" msgid="5770511773560736082">"Ei tuvastatud"</string>
<string name="fingerprint_authenticated" msgid="5309333983002526448">"Sõrmejälg autenditi"</string>
<string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"Sõrmejälje riistvara pole saadaval."</string>
<string name="fingerprint_error_no_space" msgid="1055819001126053318">"Sõrmejälge ei saa salvestada. Eemaldage olemasolev sõrmejälg."</string>
diff --git a/core/res/res/values-eu/strings.xml b/core/res/res/values-eu/strings.xml
index 5ec56376c0c8..275e17150be5 100644
--- a/core/res/res/values-eu/strings.xml
+++ b/core/res/res/values-eu/strings.xml
@@ -514,6 +514,7 @@
<string name="permdesc_imagesWrite" msgid="7073662756617474375">"Argazki-bilduma aldatzea baimentzen die aplikazioei."</string>
<string name="permlab_mediaLocation" msgid="8675148183726247864">"multimedia-edukien bildumako kokapena irakurri"</string>
<string name="permdesc_mediaLocation" msgid="2237023389178865130">"Multimedia-edukien bildumako kokapena irakurtzea baimentzen die aplikazioei."</string>
+ <string name="biometric_error_hw_unavailable" msgid="645781226537551036">"Hardware biometrikoa ez dago erabilgarri"</string>
<string name="fingerprint_acquired_partial" msgid="735082772341716043">"Hatz-marka digitala ez da osorik hauteman. Saiatu berriro."</string>
<string name="fingerprint_acquired_insufficient" msgid="4596546021310923214">"Ezin izan da prozesatu hatz-marka. Saiatu berriro."</string>
<string name="fingerprint_acquired_imager_dirty" msgid="1087209702421076105">"Hatz-marka digitalen sentsorea zikina dago. Garbi ezazu, eta saiatu berriro."</string>
@@ -521,7 +522,7 @@
<string name="fingerprint_acquired_too_slow" msgid="59250885689661653">"Mantsoegi mugitu duzu hatza. Saiatu berriro."</string>
<string-array name="fingerprint_acquired_vendor">
</string-array>
- <string name="fingerprint_not_recognized" msgid="2690661881608146617">"Ez da ezagutzen"</string>
+ <string name="biometric_not_recognized" msgid="5770511773560736082">"Ez da ezagutu"</string>
<string name="fingerprint_authenticated" msgid="5309333983002526448">"Autentifikatu da hatz-marka"</string>
<string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"Hatz-markaren hardwarea ez dago erabilgarri."</string>
<string name="fingerprint_error_no_space" msgid="1055819001126053318">"Ezin da gorde hatz-marka digitala. Kendu lehendik gordeta duzunetako bat."</string>
diff --git a/core/res/res/values-fa/strings.xml b/core/res/res/values-fa/strings.xml
index b64937c694aa..5055e8ba5c30 100644
--- a/core/res/res/values-fa/strings.xml
+++ b/core/res/res/values-fa/strings.xml
@@ -514,6 +514,7 @@
<string name="permdesc_imagesWrite" msgid="7073662756617474375">"به برنامه اجازه می‌دهد مجموعه عکستان را تغییر دهد."</string>
<string name="permlab_mediaLocation" msgid="8675148183726247864">"خواندن مکان‌ها از مجموعه رسانه شما"</string>
<string name="permdesc_mediaLocation" msgid="2237023389178865130">"به برنامه اجازه می‌دهد مکان‌ها را از مجموعه رسانه‌تان بخواند."</string>
+ <string name="biometric_error_hw_unavailable" msgid="645781226537551036">"سخت‌افزار زیست‌سنجی دردسترس نیست"</string>
<string name="fingerprint_acquired_partial" msgid="735082772341716043">"بخشی از اثر انگشت شناسایی شد. لطفاً دوباره امتحان کنید."</string>
<string name="fingerprint_acquired_insufficient" msgid="4596546021310923214">"اثرانگشت پردازش نشد. لطفاً دوباره امتحان کنید."</string>
<string name="fingerprint_acquired_imager_dirty" msgid="1087209702421076105">"حسگر اثر انگشت کثیف است. لطفاً آن را تمیز کنید و دوباره امتحان نمایید."</string>
@@ -521,7 +522,7 @@
<string name="fingerprint_acquired_too_slow" msgid="59250885689661653">"حرکت انگشت خیلی آهسته بود. لطفاً دوباره امتحان کنید."</string>
<string-array name="fingerprint_acquired_vendor">
</string-array>
- <string name="fingerprint_not_recognized" msgid="2690661881608146617">"شناخته نشد"</string>
+ <string name="biometric_not_recognized" msgid="5770511773560736082">"شناسایی نشد"</string>
<string name="fingerprint_authenticated" msgid="5309333983002526448">"اثر انگشت احراز هویت شد"</string>
<string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"سخت‌افزار اثرانگشت در دسترس نیست."</string>
<string name="fingerprint_error_no_space" msgid="1055819001126053318">"ذخیره اثر انگشت ممکن نیست. لطفاً یک اثر انگشت موجود را حذف کنید."</string>
diff --git a/core/res/res/values-fi/strings.xml b/core/res/res/values-fi/strings.xml
index e13a01fdcce7..d54cb72cfc91 100644
--- a/core/res/res/values-fi/strings.xml
+++ b/core/res/res/values-fi/strings.xml
@@ -514,6 +514,7 @@
<string name="permdesc_imagesWrite" msgid="7073662756617474375">"Antaa sovelluksen muokata kuvakokoelmaasi."</string>
<string name="permlab_mediaLocation" msgid="8675148183726247864">"lukea mediakokoelmasi sijainteja"</string>
<string name="permdesc_mediaLocation" msgid="2237023389178865130">"Antaa sovelluksen lukea mediakokoelmasi sijainteja."</string>
+ <string name="biometric_error_hw_unavailable" msgid="645781226537551036">"Biometrinen laitteisto ei käytettävissä"</string>
<string name="fingerprint_acquired_partial" msgid="735082772341716043">"Sormenjälki havaittiin vain osittain. Yritä uudelleen."</string>
<string name="fingerprint_acquired_insufficient" msgid="4596546021310923214">"Sormenjäljen käsittely epäonnistui. Yritä uudelleen."</string>
<string name="fingerprint_acquired_imager_dirty" msgid="1087209702421076105">"Sormenjälkitunnistin on likainen. Puhdista tunnistin ja yritä uudelleen."</string>
@@ -521,7 +522,7 @@
<string name="fingerprint_acquired_too_slow" msgid="59250885689661653">"Liikutit sormea liian hitaasti. Yritä uudelleen."</string>
<string-array name="fingerprint_acquired_vendor">
</string-array>
- <string name="fingerprint_not_recognized" msgid="2690661881608146617">"Ei tunnistettu"</string>
+ <string name="biometric_not_recognized" msgid="5770511773560736082">"Ei tunnistettu"</string>
<string name="fingerprint_authenticated" msgid="5309333983002526448">"Sormenjälki tunnistettu"</string>
<string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"Sormenjälkilaitteisto ei ole käytettävissä."</string>
<string name="fingerprint_error_no_space" msgid="1055819001126053318">"Sormenjälkeä ei voida tallentaa. Poista aiemmin lisätty sormenjälki."</string>
diff --git a/core/res/res/values-fr-rCA/strings.xml b/core/res/res/values-fr-rCA/strings.xml
index 240920295501..0c0cdea4f571 100644
--- a/core/res/res/values-fr-rCA/strings.xml
+++ b/core/res/res/values-fr-rCA/strings.xml
@@ -253,7 +253,7 @@
<string name="notification_channel_network_alerts" msgid="2895141221414156525">"Alertes réseau"</string>
<string name="notification_channel_network_available" msgid="4531717914138179517">"Réseau accessible"</string>
<string name="notification_channel_vpn" msgid="8330103431055860618">"État du RPV"</string>
- <string name="notification_channel_device_admin" msgid="1568154104368069249">"Administration d\'appareils"</string>
+ <string name="notification_channel_device_admin" msgid="1568154104368069249">"Gestion de l\'appareil"</string>
<string name="notification_channel_alerts" msgid="4496839309318519037">"Alertes"</string>
<string name="notification_channel_retail_mode" msgid="6088920674914038779">"Démo en magasin"</string>
<string name="notification_channel_usb" msgid="9006850475328924681">"Connexion USB"</string>
@@ -514,6 +514,7 @@
<string name="permdesc_imagesWrite" msgid="7073662756617474375">"Autorise l\'application à modifier votre collection de photos."</string>
<string name="permlab_mediaLocation" msgid="8675148183726247864">"lire les positions issues de votre collection multimédia"</string>
<string name="permdesc_mediaLocation" msgid="2237023389178865130">"Autorise l\'application à lire les positions indiquées dans votre collection multimédia."</string>
+ <string name="biometric_error_hw_unavailable" msgid="645781226537551036">"Matériel biométrique indisponible"</string>
<string name="fingerprint_acquired_partial" msgid="735082772341716043">"Empreinte digitale partielle détectée. Veuillez essayer de nouveau."</string>
<string name="fingerprint_acquired_insufficient" msgid="4596546021310923214">"Impossible de traiter les empreintes digitales. Veuillez essayer de nouveau."</string>
<string name="fingerprint_acquired_imager_dirty" msgid="1087209702421076105">"Le capteur d\'empreintes digitales est sale. Veuillez le nettoyer et essayer de nouveau."</string>
@@ -521,7 +522,7 @@
<string name="fingerprint_acquired_too_slow" msgid="59250885689661653">"Vous avez déplacé votre doigt trop lentement. Veuillez réessayer."</string>
<string-array name="fingerprint_acquired_vendor">
</string-array>
- <string name="fingerprint_not_recognized" msgid="2690661881608146617">"Doigt non reconnu"</string>
+ <string name="biometric_not_recognized" msgid="5770511773560736082">"Données biométriques non reconnues"</string>
<string name="fingerprint_authenticated" msgid="5309333983002526448">"Empreinte digitale authentifiée"</string>
<string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"Matériel d\'empreinte numérique indisponible."</string>
<string name="fingerprint_error_no_space" msgid="1055819001126053318">"L\'empreinte digitale ne peut pas être enregistrée. Veuillez supprimer une empreinte existante."</string>
diff --git a/core/res/res/values-fr/strings.xml b/core/res/res/values-fr/strings.xml
index 9c8a7e78bca0..6932be373c0b 100644
--- a/core/res/res/values-fr/strings.xml
+++ b/core/res/res/values-fr/strings.xml
@@ -514,6 +514,7 @@
<string name="permdesc_imagesWrite" msgid="7073662756617474375">"Autorise l\'application à modifier votre bibliothèque photo."</string>
<string name="permlab_mediaLocation" msgid="8675148183726247864">"consulter des positions issues de votre bibliothèque multimédia"</string>
<string name="permdesc_mediaLocation" msgid="2237023389178865130">"Autorise l\'application à consulter des positions issues de votre bibliothèque multimédia."</string>
+ <string name="biometric_error_hw_unavailable" msgid="645781226537551036">"Matériel biométrique indisponible"</string>
<string name="fingerprint_acquired_partial" msgid="735082772341716043">"Empreinte numérique partiellement détectée. Veuillez réessayer."</string>
<string name="fingerprint_acquired_insufficient" msgid="4596546021310923214">"Impossible de reconnaître l\'empreinte numérique. Veuillez réessayer."</string>
<string name="fingerprint_acquired_imager_dirty" msgid="1087209702421076105">"Le lecteur d\'empreintes numériques est sale. Veuillez le nettoyer, puis réessayer."</string>
@@ -521,7 +522,7 @@
<string name="fingerprint_acquired_too_slow" msgid="59250885689661653">"Vous avez déplacé votre doigt trop lentement. Veuillez réessayer."</string>
<string-array name="fingerprint_acquired_vendor">
</string-array>
- <string name="fingerprint_not_recognized" msgid="2690661881608146617">"Non reconnu"</string>
+ <string name="biometric_not_recognized" msgid="5770511773560736082">"Non reconnu"</string>
<string name="fingerprint_authenticated" msgid="5309333983002526448">"Empreinte digitale authentifiée"</string>
<string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"Matériel d\'empreinte numérique indisponible."</string>
<string name="fingerprint_error_no_space" msgid="1055819001126053318">"Impossible d\'enregistrer l\'empreinte numérique. Veuillez supprimer une empreinte."</string>
diff --git a/core/res/res/values-gl/strings.xml b/core/res/res/values-gl/strings.xml
index 27efff880db5..ba66adfe31ca 100644
--- a/core/res/res/values-gl/strings.xml
+++ b/core/res/res/values-gl/strings.xml
@@ -514,6 +514,7 @@
<string name="permdesc_imagesWrite" msgid="7073662756617474375">"Permite que a aplicación modifique a túa colección de fotos."</string>
<string name="permlab_mediaLocation" msgid="8675148183726247864">"ler localizacións da túa colección multimedia"</string>
<string name="permdesc_mediaLocation" msgid="2237023389178865130">"Permite que a aplicación lea as localizacións da túa colección multimedia."</string>
+ <string name="biometric_error_hw_unavailable" msgid="645781226537551036">"O hardware biométrico non está dispoñible"</string>
<string name="fingerprint_acquired_partial" msgid="735082772341716043">"Detectouse unha impresión dixital parcial. Téntao de novo."</string>
<string name="fingerprint_acquired_insufficient" msgid="4596546021310923214">"Non se puido procesar a impresión dixital. Téntao de novo."</string>
<string name="fingerprint_acquired_imager_dirty" msgid="1087209702421076105">"O sensor de impresión dixital está sucio. Límpao e téntao de novo."</string>
@@ -521,7 +522,7 @@
<string name="fingerprint_acquired_too_slow" msgid="59250885689661653">"O dedo moveuse demasiado lento. Téntao de novo."</string>
<string-array name="fingerprint_acquired_vendor">
</string-array>
- <string name="fingerprint_not_recognized" msgid="2690661881608146617">"Non se recoñece"</string>
+ <string name="biometric_not_recognized" msgid="5770511773560736082">"Non se recoñeceu"</string>
<string name="fingerprint_authenticated" msgid="5309333983002526448">"Autenticouse a impresión dixital"</string>
<string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"Hardware de impresión dixital non dispoñible."</string>
<string name="fingerprint_error_no_space" msgid="1055819001126053318">"Non se pode almacenar a impresión dixital. Elimina unha impresión dixital existente."</string>
@@ -1891,8 +1892,8 @@
</plurals>
<string name="autofill_save_title" msgid="3345527308992082601">"Queres gardar o contido en: &lt;b&gt;<xliff:g id="LABEL">%1$s</xliff:g>&lt;/b&gt;?"</string>
<string name="autofill_save_title_with_type" msgid="8637809388029313305">"Queres gardar <xliff:g id="TYPE">%1$s</xliff:g> en: &lt;b&gt;<xliff:g id="LABEL">%2$s</xliff:g>&lt;/b&gt;?"</string>
- <string name="autofill_save_title_with_2types" msgid="5214035651838265325">"Queres gardar <xliff:g id="TYPE_0">%1$s</xliff:g> e <xliff:g id="TYPE_1">%2$s</xliff:g> en: &lt;b&gt;<xliff:g id="LABEL">%3$s</xliff:g>&lt;/b&gt;?"</string>
- <string name="autofill_save_title_with_3types" msgid="6943161834231458441">"Queres gardar <xliff:g id="TYPE_0">%1$s</xliff:g>, <xliff:g id="TYPE_1">%2$s</xliff:g> e <xliff:g id="TYPE_2">%3$s</xliff:g> en: &lt;b&gt;<xliff:g id="LABEL">%4$s</xliff:g>&lt;/b&gt;?"</string>
+ <string name="autofill_save_title_with_2types" msgid="5214035651838265325">"Queres gardar estes datos (<xliff:g id="TYPE_0">%1$s</xliff:g> e <xliff:g id="TYPE_1">%2$s</xliff:g>) en &lt;b&gt;<xliff:g id="LABEL">%3$s</xliff:g>&lt;/b&gt;?"</string>
+ <string name="autofill_save_title_with_3types" msgid="6943161834231458441">"Queres gardar estes datos (<xliff:g id="TYPE_0">%1$s</xliff:g>, <xliff:g id="TYPE_1">%2$s</xliff:g> e <xliff:g id="TYPE_2">%3$s</xliff:g>) en &lt;b&gt;<xliff:g id="LABEL">%4$s</xliff:g>&lt;/b&gt;?"</string>
<string name="autofill_update_title" msgid="4879673117448810818">"Queres actualizar &lt;b&gt;<xliff:g id="LABEL">%1$s</xliff:g>&lt;/b&gt; con estes datos?"</string>
<string name="autofill_update_title_with_type" msgid="339733442087186755">"Queres actualizar &lt;b&gt;<xliff:g id="LABEL">%2$s</xliff:g>&lt;/b&gt; con estes datos (<xliff:g id="TYPE">%1$s</xliff:g>)?"</string>
<string name="autofill_update_title_with_2types" msgid="6321714204167424745">"Queres actualizar &lt;b&gt;<xliff:g id="LABEL">%3$s</xliff:g>&lt;/b&gt; con estes datos (<xliff:g id="TYPE_0">%1$s</xliff:g> e <xliff:g id="TYPE_1">%2$s</xliff:g>)?"</string>
diff --git a/core/res/res/values-gu/strings.xml b/core/res/res/values-gu/strings.xml
index 5e6c34d0f43a..2b96f3fe6c11 100644
--- a/core/res/res/values-gu/strings.xml
+++ b/core/res/res/values-gu/strings.xml
@@ -514,6 +514,7 @@
<string name="permdesc_imagesWrite" msgid="7073662756617474375">"એપને તમારો ફોટો સંગ્રહ સંશોધિત કરવાની મંજૂરી આપે છે."</string>
<string name="permlab_mediaLocation" msgid="8675148183726247864">"આપના મીડિયા સંગ્રહમાંથી સ્થાનો વાંચવા"</string>
<string name="permdesc_mediaLocation" msgid="2237023389178865130">"એપને તમારા મીડિયા સંગ્રહમાંથી સ્થાનો વાંચવાની મંજૂરી આપે છે."</string>
+ <string name="biometric_error_hw_unavailable" msgid="645781226537551036">"બાયોમેટ્રિક હાર્ડવેર ઉપલબ્ધ નથી"</string>
<string name="fingerprint_acquired_partial" msgid="735082772341716043">"આંશિક ફિંગરપ્રિન્ટ મળી. કૃપા કરીને ફરી પ્રયાસ કરો."</string>
<string name="fingerprint_acquired_insufficient" msgid="4596546021310923214">"ફિંગરપ્રિન્ટ પ્રક્રિયા કરી શકાઈ નથી. કૃપા કરીને ફરી પ્રયાસ કરો."</string>
<string name="fingerprint_acquired_imager_dirty" msgid="1087209702421076105">"ફિંગરપ્રિન્ટ સેન્સર ગંદું છે. કૃપા કરીને સાફ કરો અને ફરી પ્રયાસ કરો."</string>
@@ -521,7 +522,7 @@
<string name="fingerprint_acquired_too_slow" msgid="59250885689661653">"આંગળી બહુ જ ધીમેથી ખસેડી. કૃપા કરીને ફરી પ્રયાસ કરો."</string>
<string-array name="fingerprint_acquired_vendor">
</string-array>
- <string name="fingerprint_not_recognized" msgid="2690661881608146617">"ઓળખાયેલ નથી"</string>
+ <string name="biometric_not_recognized" msgid="5770511773560736082">"ઓળખાયેલ નથી"</string>
<string name="fingerprint_authenticated" msgid="5309333983002526448">"ફિંગરપ્રિન્ટ પ્રમાણિત કરી"</string>
<string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"ફિંગરપ્રિન્ટ હાર્ડવેર ઉપલબ્ધ નથી."</string>
<string name="fingerprint_error_no_space" msgid="1055819001126053318">"ફિંગરપ્રિન્ટ સંગ્રહિત કરી શકાતી નથી. કૃપા કરીને અસ્તિત્વમાંની ફિંગરપ્રિન્ટ દૂર કરો."</string>
diff --git a/core/res/res/values-hi/strings.xml b/core/res/res/values-hi/strings.xml
index a85d6fa11106..d4b800ad2e04 100644
--- a/core/res/res/values-hi/strings.xml
+++ b/core/res/res/values-hi/strings.xml
@@ -300,18 +300,12 @@
<string name="permgrouplab_sensors" msgid="416037179223226722">"शरीर संवेदक"</string>
<string name="permgroupdesc_sensors" msgid="7147968539346634043">"अपने महत्वपूर्ण संकेतों के बारे में सेंसर डेटा को ऐक्सेस करें"</string>
<string name="permgrouprequest_sensors" msgid="6349806962814556786">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; को अपने स्वास्थ्य से जुड़ी ज़रूरी जानकारी इस्तेमाल करने की अनुमति देना चाहते हैं?"</string>
- <!-- no translation found for permgrouplab_aural (965607064083134896) -->
- <skip />
- <!-- no translation found for permgroupdesc_aural (4870189506255958055) -->
- <skip />
- <!-- no translation found for permgrouprequest_aural (6787926123071735620) -->
- <skip />
- <!-- no translation found for permgrouplab_visual (8030190588123857921) -->
- <skip />
- <!-- no translation found for permgroupdesc_visual (3415827902566663546) -->
- <skip />
- <!-- no translation found for permgrouprequest_visual (6907523945030290376) -->
- <skip />
+ <string name="permgrouplab_aural" msgid="965607064083134896">"संगीत"</string>
+ <string name="permgroupdesc_aural" msgid="4870189506255958055">"अपना संगीत संग्रह एक्सेस करने दें"</string>
+ <string name="permgrouprequest_aural" msgid="6787926123071735620">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; को अपना संगीत एक्सेस करने दें?"</string>
+ <string name="permgrouplab_visual" msgid="8030190588123857921">"फ़ोटो और वीडियो"</string>
+ <string name="permgroupdesc_visual" msgid="3415827902566663546">"अपने फ़ोटो और वीडियो एक्सेस करने दें"</string>
+ <string name="permgrouprequest_visual" msgid="6907523945030290376">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; को अपने फ़ोटो और वीडियो एक्सेस करने दें?"</string>
<string name="capability_title_canRetrieveWindowContent" msgid="3901717936930170320">"विंडो की सामग्री वापस पाएं"</string>
<string name="capability_desc_canRetrieveWindowContent" msgid="3772225008605310672">"उस विंडो की सामग्री की जाँच करें, जिसका आप इस्तेमाल कर रहे हैं."</string>
<string name="capability_title_canRequestTouchExploration" msgid="3108723364676667320">"छूकर, किसी चीज़ से जुड़ी जानकारी सुनने की सुविधा चालू करें"</string>
@@ -506,33 +500,21 @@
<string name="permdesc_manageFingerprint" msgid="178208705828055464">"उंगली की छाप वाले टेम्पलेट का उपयोग करने के लिए जोड़ने और हटाने हेतु ऐप को विधियां प्रारंभ करने देती है."</string>
<string name="permlab_useFingerprint" msgid="3150478619915124905">"उंगली की छाप के लिए हार्डवेयर का उपयोग करें"</string>
<string name="permdesc_useFingerprint" msgid="9165097460730684114">"ऐप के प्रमाणीकरण के लिए उंगली की छाप हार्डवेयर का उपयोग करने देती है"</string>
- <!-- no translation found for permlab_audioRead (6617225220728465565) -->
- <skip />
- <!-- no translation found for permdesc_audioRead (5034032570243484805) -->
- <skip />
- <!-- no translation found for permlab_audioWrite (2661772059799779292) -->
- <skip />
- <!-- no translation found for permdesc_audioWrite (8888544708166230494) -->
- <skip />
- <!-- no translation found for permlab_videoRead (9182618678674737229) -->
- <skip />
- <!-- no translation found for permdesc_videoRead (7045676429859396194) -->
- <skip />
- <!-- no translation found for permlab_videoWrite (128769316366746446) -->
- <skip />
- <!-- no translation found for permdesc_videoWrite (5448565757490640841) -->
- <skip />
- <!-- no translation found for permlab_imagesRead (3015078545742665304) -->
- <skip />
- <!-- no translation found for permdesc_imagesRead (3144263806038695580) -->
- <skip />
- <!-- no translation found for permlab_imagesWrite (3391306186247235510) -->
- <skip />
- <!-- no translation found for permdesc_imagesWrite (7073662756617474375) -->
- <skip />
- <!-- no translation found for permlab_mediaLocation (8675148183726247864) -->
- <skip />
- <!-- no translation found for permdesc_mediaLocation (2237023389178865130) -->
+ <string name="permlab_audioRead" msgid="6617225220728465565">"अपना संगीत संग्रह एक्सेस करने की अनुमति दें"</string>
+ <string name="permdesc_audioRead" msgid="5034032570243484805">"इससे ऐप्लिकेशन को आपके संगीत संग्रह को एक्सेस करने की मंज़ूरी दी जाती है."</string>
+ <string name="permlab_audioWrite" msgid="2661772059799779292">"अपने संगीत संग्रह में बदलाव करने की अनुमति दें"</string>
+ <string name="permdesc_audioWrite" msgid="8888544708166230494">"इससे ऐप्लिकेशन को आपके संगीत संग्रह में बदलाव करने की मंज़ूरी दी जाती है"</string>
+ <string name="permlab_videoRead" msgid="9182618678674737229">"अपना वीडियो संग्रह एक्सेस करने की अनुमति दें"</string>
+ <string name="permdesc_videoRead" msgid="7045676429859396194">"इससे ऐप्लिकेशन को आपके वीडियो संग्रह को एक्सेस करने की मंज़ूरी दी जाती है."</string>
+ <string name="permlab_videoWrite" msgid="128769316366746446">"अपने वीडियो संग्रह में बदलाव करने की अनुमति दें"</string>
+ <string name="permdesc_videoWrite" msgid="5448565757490640841">"इससे ऐप्लिकेशन को आपके वीडियो संग्रह में बदलाव करने की मंज़ूरी दी जाती है."</string>
+ <string name="permlab_imagesRead" msgid="3015078545742665304">"अपना फ़ोटो संग्रह एक्सेस करने की अनुमति दें"</string>
+ <string name="permdesc_imagesRead" msgid="3144263806038695580">"इससे ऐप्लिकेशन को आपके फ़ोटो संग्रह को एक्सेस करने की मंज़ूरी दी जाती है."</string>
+ <string name="permlab_imagesWrite" msgid="3391306186247235510">"अपने फ़ोटो संग्रह में बदलाव करने की अनुमति दें"</string>
+ <string name="permdesc_imagesWrite" msgid="7073662756617474375">"इससे ऐप्लिकेशन को आपके फ़ोटो संग्रह में बदलाव करने की मंज़ूरी दी जाती है."</string>
+ <string name="permlab_mediaLocation" msgid="8675148183726247864">"अपने मीडिया संग्रह से जगह की जानकारी एक्सेस करने की अनुमति दें"</string>
+ <string name="permdesc_mediaLocation" msgid="2237023389178865130">"इससे ऐप्लिकेशन को आपके मीडिया संग्रह से जगह की जानकारी एक्सेस करने की अनुमति दी जाती है."</string>
+ <!-- no translation found for biometric_error_hw_unavailable (645781226537551036) -->
<skip />
<string name="fingerprint_acquired_partial" msgid="735082772341716043">"आंशिक फ़िंगरप्रिंट की पहचान की गई. कृपया पुनः प्रयास करें."</string>
<string name="fingerprint_acquired_insufficient" msgid="4596546021310923214">"फ़िंगरप्रिंट संसाधित नहीं हो सका. कृपया पुन: प्रयास करें."</string>
@@ -541,7 +523,8 @@
<string name="fingerprint_acquired_too_slow" msgid="59250885689661653">"उंगली बहुत धीरे चलाई गई. कृपया फिर से कोशिश करें."</string>
<string-array name="fingerprint_acquired_vendor">
</string-array>
- <string name="fingerprint_not_recognized" msgid="2690661881608146617">"पहचाना नहीं गया"</string>
+ <!-- no translation found for biometric_not_recognized (5770511773560736082) -->
+ <skip />
<string name="fingerprint_authenticated" msgid="5309333983002526448">"फ़िंगरप्रिंट की पुष्टि हो गई"</string>
<string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"फ़िंगरप्रिंट हार्डवेयर उपलब्ध नहीं है."</string>
<string name="fingerprint_error_no_space" msgid="1055819001126053318">"फ़िंगरप्रिंट को संग्रहित नहीं किया जा सका. कृपया कोई मौजूदा फ़िंगरप्रिंट निकालें."</string>
@@ -1912,18 +1895,13 @@
<string name="autofill_save_title_with_type" msgid="8637809388029313305">"<xliff:g id="TYPE">%1$s</xliff:g> को &lt;b&gt;<xliff:g id="LABEL">%2$s</xliff:g>&lt;/b&gt; में सेव करें?"</string>
<string name="autofill_save_title_with_2types" msgid="5214035651838265325">"<xliff:g id="TYPE_0">%1$s</xliff:g> और <xliff:g id="TYPE_1">%2$s</xliff:g> को &lt;b&gt;<xliff:g id="LABEL">%3$s</xliff:g>&lt;/b&gt; में सेव करें?"</string>
<string name="autofill_save_title_with_3types" msgid="6943161834231458441">"<xliff:g id="TYPE_0">%1$s</xliff:g>, <xliff:g id="TYPE_1">%2$s</xliff:g> और <xliff:g id="TYPE_2">%3$s</xliff:g> को &lt;b&gt;<xliff:g id="LABEL">%4$s</xliff:g>&lt;/b&gt; में सेव करें?"</string>
- <!-- no translation found for autofill_update_title (4879673117448810818) -->
- <skip />
- <!-- no translation found for autofill_update_title_with_type (339733442087186755) -->
- <skip />
- <!-- no translation found for autofill_update_title_with_2types (6321714204167424745) -->
- <skip />
- <!-- no translation found for autofill_update_title_with_3types (5866735124066629287) -->
- <skip />
+ <string name="autofill_update_title" msgid="4879673117448810818">"&lt;b&gt;<xliff:g id="LABEL">%1$s</xliff:g>&lt;/b&gt;? में अपडेट करें?"</string>
+ <string name="autofill_update_title_with_type" msgid="339733442087186755">"<xliff:g id="TYPE">%1$s</xliff:g> को to &lt;b&gt;<xliff:g id="LABEL">%2$s</xliff:g>&lt;/b&gt; में अपडेट करें?"</string>
+ <string name="autofill_update_title_with_2types" msgid="6321714204167424745">"<xliff:g id="TYPE_0">%1$s</xliff:g> और <xliff:g id="TYPE_1">%2$s</xliff:g> को &lt;b&gt;<xliff:g id="LABEL">%3$s</xliff:g>&lt;/b&gt; में अपडेट करें?"</string>
+ <string name="autofill_update_title_with_3types" msgid="5866735124066629287">"<xliff:g id="TYPE_0">%1$s</xliff:g>, <xliff:g id="TYPE_1">%2$s</xliff:g> और <xliff:g id="TYPE_2">%3$s</xliff:g> को &lt;b&gt;<xliff:g id="LABEL">%4$s</xliff:g>&lt;/b&gt; में अपडेट करें."</string>
<string name="autofill_save_yes" msgid="6398026094049005921">"सेव करें"</string>
<string name="autofill_save_no" msgid="2625132258725581787">"नहीं, धन्यवाद"</string>
- <!-- no translation found for autofill_update_yes (310358413273276958) -->
- <skip />
+ <string name="autofill_update_yes" msgid="310358413273276958">"अपडेट करें"</string>
<string name="autofill_save_type_password" msgid="5288448918465971568">"पासवर्ड"</string>
<string name="autofill_save_type_address" msgid="4936707762193009542">"पता"</string>
<string name="autofill_save_type_credit_card" msgid="7127694776265563071">"क्रेडिट कार्ड"</string>
diff --git a/core/res/res/values-hr/strings.xml b/core/res/res/values-hr/strings.xml
index f24a3c422ad4..e7b6b5fc6ac8 100644
--- a/core/res/res/values-hr/strings.xml
+++ b/core/res/res/values-hr/strings.xml
@@ -517,6 +517,7 @@
<string name="permdesc_imagesWrite" msgid="7073662756617474375">"Omogućuje aplikaciji izmjenu vaše zbirke fotografija."</string>
<string name="permlab_mediaLocation" msgid="8675148183726247864">"čitanje lokacija iz vaše medijske zbirke"</string>
<string name="permdesc_mediaLocation" msgid="2237023389178865130">"Omogućuje aplikaciji čitanje lokacija iz vaše medijske zbirke."</string>
+ <string name="biometric_error_hw_unavailable" msgid="645781226537551036">"Biometrijski hardver nije dostupan"</string>
<string name="fingerprint_acquired_partial" msgid="735082772341716043">"Otkriven je djelomični otisak prsta. Pokušajte ponovo."</string>
<string name="fingerprint_acquired_insufficient" msgid="4596546021310923214">"Obrada otiska prsta nije uspjela. Pokušajte ponovo."</string>
<string name="fingerprint_acquired_imager_dirty" msgid="1087209702421076105">"Senzor otiska prsta nije čist. Očistite ga i pokušajte ponovo."</string>
@@ -524,7 +525,7 @@
<string name="fingerprint_acquired_too_slow" msgid="59250885689661653">"Presporo pomicanje prsta. Pokušajte ponovo."</string>
<string-array name="fingerprint_acquired_vendor">
</string-array>
- <string name="fingerprint_not_recognized" msgid="2690661881608146617">"Nije prepoznat"</string>
+ <string name="biometric_not_recognized" msgid="5770511773560736082">"Nije prepoznato"</string>
<string name="fingerprint_authenticated" msgid="5309333983002526448">"Autentificirano otiskom prsta"</string>
<string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"Hardver za otisak prsta nije dostupan."</string>
<string name="fingerprint_error_no_space" msgid="1055819001126053318">"Otisak prsta nije pohranjen. Uklonite postojeći otisak prsta."</string>
diff --git a/core/res/res/values-hu/strings.xml b/core/res/res/values-hu/strings.xml
index e7c1bf2c2aa0..3d9a35bbb6c3 100644
--- a/core/res/res/values-hu/strings.xml
+++ b/core/res/res/values-hu/strings.xml
@@ -514,6 +514,7 @@
<string name="permdesc_imagesWrite" msgid="7073662756617474375">"Engedélyezi az alkalmazásnak a fényképgyűjtemény módosítását."</string>
<string name="permlab_mediaLocation" msgid="8675148183726247864">"helyek olvasása a médiagyűjteményből"</string>
<string name="permdesc_mediaLocation" msgid="2237023389178865130">"Engedélyezi az alkalmazásnak a helyek médiagyűjteményből való olvasását."</string>
+ <string name="biometric_error_hw_unavailable" msgid="645781226537551036">"Biometrikus hardver nem áll rendelkezésre"</string>
<string name="fingerprint_acquired_partial" msgid="735082772341716043">"A rendszer az ujjlenyomatnak csak egy részletét érzékelte. Próbálkozzon újra."</string>
<string name="fingerprint_acquired_insufficient" msgid="4596546021310923214">"Nem sikerült feldolgozni az ujjlenyomatot. Próbálkozzon újra."</string>
<string name="fingerprint_acquired_imager_dirty" msgid="1087209702421076105">"Az ujjlenyomat-olvasó koszos. Tisztítsa meg, majd próbálkozzon újra."</string>
@@ -521,7 +522,7 @@
<string name="fingerprint_acquired_too_slow" msgid="59250885689661653">"Túl lassan húzta az ujját. Próbálkozzon újra."</string>
<string-array name="fingerprint_acquired_vendor">
</string-array>
- <string name="fingerprint_not_recognized" msgid="2690661881608146617">"Nem sikerült felismerni"</string>
+ <string name="biometric_not_recognized" msgid="5770511773560736082">"Nem ismerhető fel"</string>
<string name="fingerprint_authenticated" msgid="5309333983002526448">"Ujjlenyomat hitelesítve"</string>
<string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"Az ujjlenyomathoz szükséges hardver nem érhető el."</string>
<string name="fingerprint_error_no_space" msgid="1055819001126053318">"Az ujjlenyomat nem tárolható. Távolítson el egy meglévő ujjlenyomatot."</string>
diff --git a/core/res/res/values-hy/strings.xml b/core/res/res/values-hy/strings.xml
index a46d5e6f3252..8b3f287d08aa 100644
--- a/core/res/res/values-hy/strings.xml
+++ b/core/res/res/values-hy/strings.xml
@@ -514,6 +514,7 @@
<string name="permdesc_imagesWrite" msgid="7073662756617474375">"Թույլ է տալիս հավելվածին փոփոխել ձեր լուսանկարների հավաքածուն:"</string>
<string name="permlab_mediaLocation" msgid="8675148183726247864">"ճանաչել տեղադրության մասին տվյալները մեդիա բովանդակության հավաքածուից"</string>
<string name="permdesc_mediaLocation" msgid="2237023389178865130">"Թույլ է տալիս հավելվածին ճանաչել տեղադրության մասին տվյալները ձեր մեդիա բովանդակության հավաքածուից:"</string>
+ <string name="biometric_error_hw_unavailable" msgid="645781226537551036">"Կենսաչափական սարք չի գտնվել"</string>
<string name="fingerprint_acquired_partial" msgid="735082772341716043">"Մատնահետքը հայտնաբերվել է մասամբ: Փորձեք նորից:"</string>
<string name="fingerprint_acquired_insufficient" msgid="4596546021310923214">"Չհաջողվեց մշակել մատնահետքը: Նորից փորձեք:"</string>
<string name="fingerprint_acquired_imager_dirty" msgid="1087209702421076105">"Մատնահետքերի սենսորն աղտոտված է: Մաքրեք այն և փորձեք նորից:"</string>
@@ -521,7 +522,7 @@
<string name="fingerprint_acquired_too_slow" msgid="59250885689661653">"Շատ դանդաղ անցկացրեցիք մատը: Փորձեք նորից:"</string>
<string-array name="fingerprint_acquired_vendor">
</string-array>
- <string name="fingerprint_not_recognized" msgid="2690661881608146617">"Չճանաչվեց"</string>
+ <string name="biometric_not_recognized" msgid="5770511773560736082">"Չհաջողվեց ճանաչել"</string>
<string name="fingerprint_authenticated" msgid="5309333983002526448">"Մատնահետքը նույնականացվեց"</string>
<string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"Մատնահետքի սարքն անհասանելի է:"</string>
<string name="fingerprint_error_no_space" msgid="1055819001126053318">"Հնարավոր չէ պահել մատնահետքը: Հեռացրեք առկա մատնահետքը:"</string>
diff --git a/core/res/res/values-in/strings.xml b/core/res/res/values-in/strings.xml
index ed5444d9ed3e..6d1da48b1264 100644
--- a/core/res/res/values-in/strings.xml
+++ b/core/res/res/values-in/strings.xml
@@ -514,6 +514,7 @@
<string name="permdesc_imagesWrite" msgid="7073662756617474375">"Mengizinkan aplikasi untuk memodifikasi koleksi foto Anda."</string>
<string name="permlab_mediaLocation" msgid="8675148183726247864">"membaca lokasi dari koleksi media Anda"</string>
<string name="permdesc_mediaLocation" msgid="2237023389178865130">"Mengizinkan aplikasi untuk membaca lokasi dari koleksi media Anda."</string>
+ <string name="biometric_error_hw_unavailable" msgid="645781226537551036">"Hardware biometrik tidak tersedia"</string>
<string name="fingerprint_acquired_partial" msgid="735082772341716043">"Sebagian sidik jari terdeteksi. Coba lagi."</string>
<string name="fingerprint_acquired_insufficient" msgid="4596546021310923214">"Tidak dapat memproses sidik jari. Coba lagi."</string>
<string name="fingerprint_acquired_imager_dirty" msgid="1087209702421076105">"Sensor sidik jari kotor. Bersihkan dan coba lagi."</string>
@@ -521,7 +522,7 @@
<string name="fingerprint_acquired_too_slow" msgid="59250885689661653">"Jari digerakkan terlalu lambat. Coba lagi."</string>
<string-array name="fingerprint_acquired_vendor">
</string-array>
- <string name="fingerprint_not_recognized" msgid="2690661881608146617">"Tidak dikenali"</string>
+ <string name="biometric_not_recognized" msgid="5770511773560736082">"Tidak dikenali"</string>
<string name="fingerprint_authenticated" msgid="5309333983002526448">"Sidik jari diautentikasi"</string>
<string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"Hardware sidik jari tidak tersedia."</string>
<string name="fingerprint_error_no_space" msgid="1055819001126053318">"Sidik jari tidak dapat disimpan. Hapus sidik jari yang ada."</string>
diff --git a/core/res/res/values-is/strings.xml b/core/res/res/values-is/strings.xml
index 330b0106d3e1..4d7996fb1fb4 100644
--- a/core/res/res/values-is/strings.xml
+++ b/core/res/res/values-is/strings.xml
@@ -514,6 +514,7 @@
<string name="permdesc_imagesWrite" msgid="7073662756617474375">"Leyfir forritinu að breyta myndasafninu þínu."</string>
<string name="permlab_mediaLocation" msgid="8675148183726247864">"lesa staðsetningar úr efnissafninu þínu"</string>
<string name="permdesc_mediaLocation" msgid="2237023389178865130">"Leyfir forritinu að lesa staðsetningar úr efnissafninu þínu."</string>
+ <string name="biometric_error_hw_unavailable" msgid="645781226537551036">"Lífkennavélbúnaður ekki tiltækur"</string>
<string name="fingerprint_acquired_partial" msgid="735082772341716043">"Hluti fingrafars greindist. Reyndu aftur."</string>
<string name="fingerprint_acquired_insufficient" msgid="4596546021310923214">"Ekki var hægt að vinna úr fingrafarinu. Reyndu aftur."</string>
<string name="fingerprint_acquired_imager_dirty" msgid="1087209702421076105">"Fingrafaraskynjarinn er óhreinn. Hreinsaðu hann og reyndu aftur."</string>
@@ -521,7 +522,7 @@
<string name="fingerprint_acquired_too_slow" msgid="59250885689661653">"Fingurinn hreyfðist of hægt. Reyndu aftur."</string>
<string-array name="fingerprint_acquired_vendor">
</string-array>
- <string name="fingerprint_not_recognized" msgid="2690661881608146617">"Þekktist ekki"</string>
+ <string name="biometric_not_recognized" msgid="5770511773560736082">"Þekktist ekki"</string>
<string name="fingerprint_authenticated" msgid="5309333983002526448">"Fingrafar staðfest"</string>
<string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"Fingrafarsvélbúnaður ekki til staðar."</string>
<string name="fingerprint_error_no_space" msgid="1055819001126053318">"Ekki er hægt að vista fingrafarið. Fjarlægðu eitthvert af fingraförunum sem fyrir eru."</string>
diff --git a/core/res/res/values-it/strings.xml b/core/res/res/values-it/strings.xml
index a7c1ae29f7e8..44818a3bc10e 100644
--- a/core/res/res/values-it/strings.xml
+++ b/core/res/res/values-it/strings.xml
@@ -514,6 +514,7 @@
<string name="permdesc_imagesWrite" msgid="7073662756617474375">"Consente all\'app di modificare la tua raccolta di foto."</string>
<string name="permlab_mediaLocation" msgid="8675148183726247864">"Lettura delle posizioni dalla tua raccolta multimediale"</string>
<string name="permdesc_mediaLocation" msgid="2237023389178865130">"Consente all\'app di leggere le posizioni dalla tua raccolta multimediale."</string>
+ <string name="biometric_error_hw_unavailable" msgid="645781226537551036">"Hardware biometrico non disponibile"</string>
<string name="fingerprint_acquired_partial" msgid="735082772341716043">"Rilevata impronta digitale parziale. Riprova."</string>
<string name="fingerprint_acquired_insufficient" msgid="4596546021310923214">"Impossibile elaborare l\'impronta digitale. Riprova."</string>
<string name="fingerprint_acquired_imager_dirty" msgid="1087209702421076105">"Il sensore di impronte digitali è sporco. Puliscilo e riprova."</string>
@@ -521,7 +522,7 @@
<string name="fingerprint_acquired_too_slow" msgid="59250885689661653">"Movimento del dito troppo lento. Riprova."</string>
<string-array name="fingerprint_acquired_vendor">
</string-array>
- <string name="fingerprint_not_recognized" msgid="2690661881608146617">"Non riconosciuto"</string>
+ <string name="biometric_not_recognized" msgid="5770511773560736082">"Non riconosciuto"</string>
<string name="fingerprint_authenticated" msgid="5309333983002526448">"Impronta digitale autenticata"</string>
<string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"Hardware per l\'impronta digitale non disponibile."</string>
<string name="fingerprint_error_no_space" msgid="1055819001126053318">"Impossibile memorizzare l\'impronta digitale. Rimuovi un\'impronta esistente."</string>
@@ -832,7 +833,7 @@
<string name="lockscreen_forgot_pattern_button_text" msgid="2626999449610695930">"Hai dimenticato la sequenza?"</string>
<string name="lockscreen_glogin_forgot_pattern" msgid="2588521501166032747">"Sblocco account"</string>
<string name="lockscreen_glogin_too_many_attempts" msgid="2751368605287288808">"Troppi tentativi di inserimento della sequenza"</string>
- <string name="lockscreen_glogin_instructions" msgid="3931816256100707784">"Per sbloccare, accedi tramite il tuo account Google."</string>
+ <string name="lockscreen_glogin_instructions" msgid="3931816256100707784">"Per sbloccare, accedi tramite il tuo Account Google."</string>
<string name="lockscreen_glogin_username_hint" msgid="8846881424106484447">"Nome utente (email)"</string>
<string name="lockscreen_glogin_password_hint" msgid="5958028383954738528">"Password"</string>
<string name="lockscreen_glogin_submit_button" msgid="7130893694795786300">"Accedi"</string>
@@ -1585,7 +1586,7 @@
<string name="kg_invalid_puk" msgid="3638289409676051243">"Inserisci di nuovo il codice PUK corretto. Ripetuti tentativi comportano la disattivazione definitiva della scheda SIM."</string>
<string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"I codici PIN non corrispondono"</string>
<string name="kg_login_too_many_attempts" msgid="6486842094005698475">"Troppi tentativi di inserimento della sequenza"</string>
- <string name="kg_login_instructions" msgid="1100551261265506448">"Per sbloccare, accedi con il tuo account Google."</string>
+ <string name="kg_login_instructions" msgid="1100551261265506448">"Per sbloccare, accedi con il tuo Account Google."</string>
<string name="kg_login_username_hint" msgid="5718534272070920364">"Nome utente (email)"</string>
<string name="kg_login_password_hint" msgid="9057289103827298549">"Password"</string>
<string name="kg_login_submit_button" msgid="5355904582674054702">"Accedi"</string>
diff --git a/core/res/res/values-iw/strings.xml b/core/res/res/values-iw/strings.xml
index 9a3fe87bebbd..fd5c2a11051d 100644
--- a/core/res/res/values-iw/strings.xml
+++ b/core/res/res/values-iw/strings.xml
@@ -520,6 +520,7 @@
<string name="permdesc_imagesWrite" msgid="7073662756617474375">"מאפשרת לאפליקציה לשנות את אוסף התמונות שלך."</string>
<string name="permlab_mediaLocation" msgid="8675148183726247864">"לקרוא מיקומים מאוסף המדיה שלך"</string>
<string name="permdesc_mediaLocation" msgid="2237023389178865130">"מאפשרת לאפליקציה לקרוא מיקומים מאוסף המדיה שלך."</string>
+ <string name="biometric_error_hw_unavailable" msgid="645781226537551036">"חומרה ביומטרית לא זמינה"</string>
<string name="fingerprint_acquired_partial" msgid="735082772341716043">"זוהתה טביעת אצבע חלקית. נסה שוב."</string>
<string name="fingerprint_acquired_insufficient" msgid="4596546021310923214">"לא ניתן היה לעבד את טביעת האצבע. נסה שוב."</string>
<string name="fingerprint_acquired_imager_dirty" msgid="1087209702421076105">"החיישן של טביעות האצבעות מלוכלך. נקה אותו ונסה שוב."</string>
@@ -527,7 +528,7 @@
<string name="fingerprint_acquired_too_slow" msgid="59250885689661653">"הזזת את האצבע לאט מדי. נסה שוב."</string>
<string-array name="fingerprint_acquired_vendor">
</string-array>
- <string name="fingerprint_not_recognized" msgid="2690661881608146617">"לא זוהתה"</string>
+ <string name="biometric_not_recognized" msgid="5770511773560736082">"לא זוהתה"</string>
<string name="fingerprint_authenticated" msgid="5309333983002526448">"טביעת האצבע אומתה"</string>
<string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"החומרה בשביל טביעת אצבע אינה זמינה."</string>
<string name="fingerprint_error_no_space" msgid="1055819001126053318">"לא ניתן לאחסן טביעת אצבע. הסר טביעת אצבע קיימת."</string>
diff --git a/core/res/res/values-ja/strings.xml b/core/res/res/values-ja/strings.xml
index ec2ada4d3642..4cada6068fe7 100644
--- a/core/res/res/values-ja/strings.xml
+++ b/core/res/res/values-ja/strings.xml
@@ -514,6 +514,7 @@
<string name="permdesc_imagesWrite" msgid="7073662756617474375">"写真コレクションの変更をアプリに許可します。"</string>
<string name="permlab_mediaLocation" msgid="8675148183726247864">"メディア コレクションの位置情報の読み取り"</string>
<string name="permdesc_mediaLocation" msgid="2237023389178865130">"メディア コレクションの位置情報の読み取りをアプリに許可します。"</string>
+ <string name="biometric_error_hw_unavailable" msgid="645781226537551036">"生体認証ハードウェアが利用できません"</string>
<string name="fingerprint_acquired_partial" msgid="735082772341716043">"指紋を一部しか検出できませんでした。もう一度お試しください。"</string>
<string name="fingerprint_acquired_insufficient" msgid="4596546021310923214">"指紋を処理できませんでした。もう一度お試しください。"</string>
<string name="fingerprint_acquired_imager_dirty" msgid="1087209702421076105">"指紋認証センサーに汚れがあります。汚れを落としてもう一度お試しください。"</string>
@@ -521,7 +522,7 @@
<string name="fingerprint_acquired_too_slow" msgid="59250885689661653">"指の動きが遅すぎました。もう一度お試しください。"</string>
<string-array name="fingerprint_acquired_vendor">
</string-array>
- <string name="fingerprint_not_recognized" msgid="2690661881608146617">"認識されませんでした"</string>
+ <string name="biometric_not_recognized" msgid="5770511773560736082">"認識されませんでした"</string>
<string name="fingerprint_authenticated" msgid="5309333983002526448">"指紋認証を完了しました"</string>
<string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"指紋ハードウェアは使用できません。"</string>
<string name="fingerprint_error_no_space" msgid="1055819001126053318">"指紋を保存できません。既存の指紋を削除してください。"</string>
diff --git a/core/res/res/values-ka/strings.xml b/core/res/res/values-ka/strings.xml
index 0a383dff04f8..51a4c28f4d9e 100644
--- a/core/res/res/values-ka/strings.xml
+++ b/core/res/res/values-ka/strings.xml
@@ -514,6 +514,7 @@
<string name="permdesc_imagesWrite" msgid="7073662756617474375">"აპი შეძლებს თქვენი ფოტოკოლექციის შეცვლას."</string>
<string name="permlab_mediaLocation" msgid="8675148183726247864">"მდებარეობების გაცნობა თქვენი მედიაკოლექციიდან"</string>
<string name="permdesc_mediaLocation" msgid="2237023389178865130">"აპი შეძლებს მდებარეობების გაცნობას თქვენი მედიაკოლექციიდან."</string>
+ <string name="biometric_error_hw_unavailable" msgid="645781226537551036">"ბიომეტრიული აპარატურა მიუწვდომელია"</string>
<string name="fingerprint_acquired_partial" msgid="735082772341716043">"აღმოჩენილია თითის ნაწილობრივი ანაბეჭდი. გთხოვთ, სცადოთ ხელახლა."</string>
<string name="fingerprint_acquired_insufficient" msgid="4596546021310923214">"თითის ანაბეჭდი ვერ მუშავდება. გთხოვთ, სცადოთ ხელახლა."</string>
<string name="fingerprint_acquired_imager_dirty" msgid="1087209702421076105">"თითის ანაბეჭდის სენსორი დაბინძურებულია. გთხოვთ, გაასუფთაოთ და სცადოთ ხელახლა."</string>
@@ -521,7 +522,7 @@
<string name="fingerprint_acquired_too_slow" msgid="59250885689661653">"თითის აღება მეტისმეტად ნელა მოხდა. გთხოვთ, სცადოთ ხელახლა."</string>
<string-array name="fingerprint_acquired_vendor">
</string-array>
- <string name="fingerprint_not_recognized" msgid="2690661881608146617">"არ არის ამოცნობილი"</string>
+ <string name="biometric_not_recognized" msgid="5770511773560736082">"არ არის ამოცნობილი"</string>
<string name="fingerprint_authenticated" msgid="5309333983002526448">"თითის ანაბეჭდი ავტორიზებულია"</string>
<string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"თითის ანაბეჭდის აპარატურა არ არის ხელმისაწვდომი."</string>
<string name="fingerprint_error_no_space" msgid="1055819001126053318">"თითის ანაბეჭდის შენახვა ვერ ხერხდება. გთხოვთ, ამოშალოთ არსებული თითის ანაბეჭდი."</string>
diff --git a/core/res/res/values-kk/strings.xml b/core/res/res/values-kk/strings.xml
index 25099585fb9d..18be1e6d285f 100644
--- a/core/res/res/values-kk/strings.xml
+++ b/core/res/res/values-kk/strings.xml
@@ -514,6 +514,7 @@
<string name="permdesc_imagesWrite" msgid="7073662756617474375">"Қолданбаға суреттер жинағын өзгертуге мүмкіндік береді."</string>
<string name="permlab_mediaLocation" msgid="8675148183726247864">"медиамазмұн жинағынан геодеректерді оқу"</string>
<string name="permdesc_mediaLocation" msgid="2237023389178865130">"Қолданбаға медиамазмұн жинағынан геодеректерді оқуға мүмкіндік береді."</string>
+ <string name="biometric_error_hw_unavailable" msgid="645781226537551036">"Биометрикалық жабдық жоқ"</string>
<string name="fingerprint_acquired_partial" msgid="735082772341716043">"Саусақ ізі ішінара анықталды. Әрекетті қайталаңыз."</string>
<string name="fingerprint_acquired_insufficient" msgid="4596546021310923214">"Саусақ ізін өңдеу мүмкін емес. Әрекетті қайталаңыз."</string>
<string name="fingerprint_acquired_imager_dirty" msgid="1087209702421076105">"Саусақ ізі сенсоры лас. Тазалап, әрекетті қайталаңыз."</string>
@@ -521,7 +522,7 @@
<string name="fingerprint_acquired_too_slow" msgid="59250885689661653">"Саусағыңызды тым баяу қозғалттыңыз. Әрекетті қайталап көріңіз."</string>
<string-array name="fingerprint_acquired_vendor">
</string-array>
- <string name="fingerprint_not_recognized" msgid="2690661881608146617">"Анықталмаған"</string>
+ <string name="biometric_not_recognized" msgid="5770511773560736082">"Танылмады"</string>
<string name="fingerprint_authenticated" msgid="5309333983002526448">"Саусақ ізі аутентификацияланды"</string>
<string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"Саусақ ізі жабдығы қолжетімді емес."</string>
<string name="fingerprint_error_no_space" msgid="1055819001126053318">"Саусақ ізін сақтау мүмкін емес. Бар саусақ ізін жойыңыз."</string>
diff --git a/core/res/res/values-km/strings.xml b/core/res/res/values-km/strings.xml
index e24c9a09d918..091fa713db5f 100644
--- a/core/res/res/values-km/strings.xml
+++ b/core/res/res/values-km/strings.xml
@@ -514,6 +514,7 @@
<string name="permdesc_imagesWrite" msgid="7073662756617474375">"អនុញ្ញាតឱ្យ​កម្មវិធី​កែប្រែ​បណ្ដុំ​រូបថត​របស់​អ្នក។"</string>
<string name="permlab_mediaLocation" msgid="8675148183726247864">"អាន​ទីតាំង​ពី​បណ្ដុំ​មេឌៀ​របស់​អ្នក"</string>
<string name="permdesc_mediaLocation" msgid="2237023389178865130">"អនុញ្ញាតឱ្យ​កម្មវិធី​អាន​ទីតាំង​ពីបណ្ដុំ​មេឌៀ​របស់​អ្នក។"</string>
+ <string name="biometric_error_hw_unavailable" msgid="645781226537551036">"មិនអាច​ប្រើឧបករណ៍​ស្កេន​ស្នាមម្រាមដៃ​បានទេ"</string>
<string name="fingerprint_acquired_partial" msgid="735082772341716043">"បានផ្តិតយកស្នាមម្រាមដៃមិនពេញលក្ខណៈ។ សូមព្យាយាមម្តងទៀត។"</string>
<string name="fingerprint_acquired_insufficient" msgid="4596546021310923214">"មិនអាចដំណើរការស្នាមម្រាមដៃបានទេ។ សូមព្យាយាមម្តងទៀត។"</string>
<string name="fingerprint_acquired_imager_dirty" msgid="1087209702421076105">"ឧបករណ៍ផ្តិតម្រាមដៃប្រលាក់ហើយ។ សូមសម្អាត ហើយព្យាយាមម្តងទៀត។"</string>
@@ -521,7 +522,7 @@
<string name="fingerprint_acquired_too_slow" msgid="59250885689661653">"ចលនាម្រាមដៃយឺតពេកហើយ។ សូមព្យាយាមម្តងទៀត។"</string>
<string-array name="fingerprint_acquired_vendor">
</string-array>
- <string name="fingerprint_not_recognized" msgid="2690661881608146617">"មិនអាចសម្គាល់បានទេ"</string>
+ <string name="biometric_not_recognized" msgid="5770511773560736082">"មិនអាចសម្គាល់បានទេ"</string>
<string name="fingerprint_authenticated" msgid="5309333983002526448">"បាន​ផ្ទៀង​ផ្ទាត់​ស្នាម​ម្រាមដៃ"</string>
<string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"ផ្នែករឹងស្នាមម្រាមដៃមិនមានទេ។"</string>
<string name="fingerprint_error_no_space" msgid="1055819001126053318">"មិនអាចផ្ទុកស្នាមម្រាមដៃទេ។ សូមយកស្នាមម្រាមដៃដែលមានស្រាប់ចេញ។"</string>
diff --git a/core/res/res/values-kn/strings.xml b/core/res/res/values-kn/strings.xml
index 158a316d7798..dca94ff526e1 100644
--- a/core/res/res/values-kn/strings.xml
+++ b/core/res/res/values-kn/strings.xml
@@ -514,6 +514,7 @@
<string name="permdesc_imagesWrite" msgid="7073662756617474375">"ನಿಮ್ಮ ಫೋಟೋ ಸಂಗ್ರಹಣೆಯನ್ನು ಮಾರ್ಪಡಿಸಲು ಆ್ಯಪ್‌ಗೆ ಅನುಮತಿಸುತ್ತದೆ."</string>
<string name="permlab_mediaLocation" msgid="8675148183726247864">"ನಿಮ್ಮ ಮೀಡಿಯಾ ಸಂಗ್ರಹಣೆಯಿಂದ ಸ್ಥಳಗಳನ್ನು ಓದಿ"</string>
<string name="permdesc_mediaLocation" msgid="2237023389178865130">"ನಿಮ್ಮ ಮೀಡಿಯಾ ಸಂಗ್ರಹಣೆಯಿಂದ ಸ್ಥಳಗಳನ್ನು ಓದಲು ಆ್ಯಪ್‌ಗೆ ಅನುಮತಿಸುತ್ತದೆ."</string>
+ <string name="biometric_error_hw_unavailable" msgid="645781226537551036">"ಬಯೋಮೆಟ್ರಿಕ್ ಹಾರ್ಡ್‌ವೇರ್‌ ಲಭ್ಯವಿಲ್ಲ"</string>
<string name="fingerprint_acquired_partial" msgid="735082772341716043">"ಭಾಗಶಃ ಬೆರಳಚ್ಚು ಪತ್ತೆಯಾಗಿದೆ. ದಯವಿಟ್ಟು ಮತ್ತೆ ಪ್ರಯತ್ನಿಸಿ."</string>
<string name="fingerprint_acquired_insufficient" msgid="4596546021310923214">"ಬೆರಳಚ್ಚು ಪ್ರಕ್ರಿಯೆಗೊಳಿಸಲು ಸಾಧ್ಯವಿಲ್ಲ. ದಯವಿಟ್ಟು ಮತ್ತೆ ಪ್ರಯತ್ನಿಸಿ."</string>
<string name="fingerprint_acquired_imager_dirty" msgid="1087209702421076105">"ಬೆರಳಚ್ಚು ಸೆನ್ಸಾರ್ ಕೊಳೆಯಾಗಿದೆ. ದಯವಿಟ್ಟು ಅದನ್ನು ಸ್ವಚ್ಛಗೊಳಿಸಿ ಹಾಗೂ ಮತ್ತೆ ಪ್ರಯತ್ನಿಸಿ."</string>
@@ -521,7 +522,7 @@
<string name="fingerprint_acquired_too_slow" msgid="59250885689661653">"ಬೆರಳನ್ನು ತುಂಬಾ ನಿಧಾನವಾಗಿ ಸರಿಸಲಾಗಿದೆ. ಮತ್ತೆ ಪ್ರಯತ್ನಿಸಿ."</string>
<string-array name="fingerprint_acquired_vendor">
</string-array>
- <string name="fingerprint_not_recognized" msgid="2690661881608146617">"ಗುರುತಿಸಲಾಗಿಲ್ಲ"</string>
+ <string name="biometric_not_recognized" msgid="5770511773560736082">"ಗುರುತಿಸಲಾಗಿಲ್ಲ"</string>
<string name="fingerprint_authenticated" msgid="5309333983002526448">"ಫಿಂಗರ್‌ಪ್ರಿಂಟ್ ಅನ್ನು ಪ್ರಮಾಣೀಕರಣ ಮಾಡಲಾಗಿದೆ"</string>
<string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"ಬೆರಳಚ್ಚು ಹಾರ್ಡ್‌ವೇರ್‌ ಲಭ್ಯವಿಲ್ಲ."</string>
<string name="fingerprint_error_no_space" msgid="1055819001126053318">"ಬೆರಳಚ್ಚು ಸಂಗ್ರಹಿಸಲು ಸಾಧ್ಯವಿಲ್ಲ. ಅಸ್ತಿತ್ವದಲ್ಲಿರುವ ಬೆರಳಚ್ಚು ತೆಗೆದುಹಾಕಿ."</string>
diff --git a/core/res/res/values-ko/strings.xml b/core/res/res/values-ko/strings.xml
index 776f773480d4..d37a4750e205 100644
--- a/core/res/res/values-ko/strings.xml
+++ b/core/res/res/values-ko/strings.xml
@@ -284,7 +284,7 @@
<string name="permgrouprequest_sms" msgid="7168124215838204719">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;에서 SMS 메시지를 전송하고 보도록 허용하시겠습니까?"</string>
<string name="permgrouplab_storage" msgid="1971118770546336966">"저장용량"</string>
<string name="permgroupdesc_storage" msgid="637758554581589203">"기기 사진, 미디어, 파일 액세스"</string>
- <string name="permgrouprequest_storage" msgid="7885942926944299560">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;에서 기기의 사진, 미디어, 파일에 액세스하도록 허용하시겠습니까.?"</string>
+ <string name="permgrouprequest_storage" msgid="7885942926944299560">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;에서 기기의 사진, 미디어, 파일에 액세스하도록 허용하시겠습니까?"</string>
<string name="permgrouplab_microphone" msgid="171539900250043464">"마이크"</string>
<string name="permgroupdesc_microphone" msgid="4988812113943554584">"오디오 녹음"</string>
<string name="permgrouprequest_microphone" msgid="9167492350681916038">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;에서 오디오를 녹음하도록 허용하시겠습니까?"</string>
@@ -514,6 +514,7 @@
<string name="permdesc_imagesWrite" msgid="7073662756617474375">"앱에서 사진 컬렉션을 수정하도록 허용합니다."</string>
<string name="permlab_mediaLocation" msgid="8675148183726247864">"미디어 컬렉션에서 위치 읽기"</string>
<string name="permdesc_mediaLocation" msgid="2237023389178865130">"앱에서 미디어 컬렉션의 위치를 읽도록 허용합니다."</string>
+ <string name="biometric_error_hw_unavailable" msgid="645781226537551036">"생체 인식 하드웨어를 사용할 수 없음"</string>
<string name="fingerprint_acquired_partial" msgid="735082772341716043">"지문이 일부만 인식되었습니다. 다시 시도해 주세요."</string>
<string name="fingerprint_acquired_insufficient" msgid="4596546021310923214">"지문을 인식할 수 없습니다. 다시 시도해 주세요."</string>
<string name="fingerprint_acquired_imager_dirty" msgid="1087209702421076105">"지문 센서를 깨끗이 닦고 다시 시도하세요."</string>
@@ -521,7 +522,7 @@
<string name="fingerprint_acquired_too_slow" msgid="59250885689661653">"손가락을 너무 느리게 움직였습니다. 다시 시도해 주세요."</string>
<string-array name="fingerprint_acquired_vendor">
</string-array>
- <string name="fingerprint_not_recognized" msgid="2690661881608146617">"인식할 수 없습니다."</string>
+ <string name="biometric_not_recognized" msgid="5770511773560736082">"인식할 수 없음"</string>
<string name="fingerprint_authenticated" msgid="5309333983002526448">"지문이 인증됨"</string>
<string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"지문 인식 하드웨어를 사용할 수 없습니다."</string>
<string name="fingerprint_error_no_space" msgid="1055819001126053318">"지문을 저장할 수 없습니다. 기존 지문을 삭제하세요."</string>
diff --git a/core/res/res/values-ky/strings.xml b/core/res/res/values-ky/strings.xml
index 1c1e9a940a30..cf5f53165285 100644
--- a/core/res/res/values-ky/strings.xml
+++ b/core/res/res/values-ky/strings.xml
@@ -514,6 +514,7 @@
<string name="permdesc_imagesWrite" msgid="7073662756617474375">"Колдонмого сүрөт жыйнагыңызды өзгөртүүгө мүмкүнчүлүк берет."</string>
<string name="permlab_mediaLocation" msgid="8675148183726247864">"медиа жыйнагыңыз сакталган жерлерди окуу"</string>
<string name="permdesc_mediaLocation" msgid="2237023389178865130">"Колдонмого медиа жыйнагыңыз сакталган жерлерди окууга мүмкүнчүлүк берет."</string>
+ <string name="biometric_error_hw_unavailable" msgid="645781226537551036">"Биометрикалык аппарат жеткиликсиз"</string>
<string name="fingerprint_acquired_partial" msgid="735082772341716043">"Манжа изи жарым-жартылай аныкталды. Кайра аракет кылыңыз."</string>
<string name="fingerprint_acquired_insufficient" msgid="4596546021310923214">"Манжа изи иштелбей койду. Кайра аракет кылыңыз."</string>
<string name="fingerprint_acquired_imager_dirty" msgid="1087209702421076105">"Манжа изинин сенсору кирдеп калган. Тазалап, кайра аракет кылыңыз."</string>
@@ -521,7 +522,7 @@
<string name="fingerprint_acquired_too_slow" msgid="59250885689661653">"Манжа өтө жай жылды. Кайра аракет кылыңыз."</string>
<string-array name="fingerprint_acquired_vendor">
</string-array>
- <string name="fingerprint_not_recognized" msgid="2690661881608146617">"Таанылган жок"</string>
+ <string name="biometric_not_recognized" msgid="5770511773560736082">"Таанылган жок"</string>
<string name="fingerprint_authenticated" msgid="5309333983002526448">"Манжа изинин аныктыгы текшерилди"</string>
<string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"Манжа изинин аппараттык камсыздоосу жеткиликтүү эмес."</string>
<string name="fingerprint_error_no_space" msgid="1055819001126053318">"Манжа изин сактоо мүмкүн эмес. Учурдагы манжа изин алып салыңыз."</string>
diff --git a/core/res/res/values-lo/strings.xml b/core/res/res/values-lo/strings.xml
index b17b5ab76958..7d8a4e2f97f9 100644
--- a/core/res/res/values-lo/strings.xml
+++ b/core/res/res/values-lo/strings.xml
@@ -514,6 +514,7 @@
<string name="permdesc_imagesWrite" msgid="7073662756617474375">"ອະນຸຍາດໃຫ້ແອັບແກ້ໄຂຄໍເລັກຊັນຮູບຂອງທ່ານ."</string>
<string name="permlab_mediaLocation" msgid="8675148183726247864">"ອ່ານສະຖານທີ່ຈາກຄໍເລັກຊັນມີເດຍຂອງທ່ານ"</string>
<string name="permdesc_mediaLocation" msgid="2237023389178865130">"ອະນຸຍາດໃຫ້ແອັບອ່ານສະຖານທີ່ຈາກຄໍເລັກຊັນມີເດຍຂອງທ່ານ."</string>
+ <string name="biometric_error_hw_unavailable" msgid="645781226537551036">"ຮາດແວຊີວະມິຕິບໍ່ສາມາດໃຊ້ໄດ້"</string>
<string name="fingerprint_acquired_partial" msgid="735082772341716043">"ກວດ​ພົບ​ລາຍ​ນີ້ວ​ມື​ບາງ​ສ່ວນ​ແລ້ວ. ກະ​ລຸ​ນາ​ລອງ​ໃໝ່​ອີກ."</string>
<string name="fingerprint_acquired_insufficient" msgid="4596546021310923214">"ບໍ່​ສາ​ມາດ​ດຳ​ເນີນ​ການ​ລາຍ​ນີ້ວ​ມື​ໄດ້. ກະ​ລຸ​ນາ​ລອງ​ໃໝ່​ອີກ."</string>
<string name="fingerprint_acquired_imager_dirty" msgid="1087209702421076105">"ເຊັນ​ເຊີ​ລາຍ​ນີ້ວ​ມື​ເປື້ອນ. ກະ​ລຸ​ນາ​ທຳ​ຄວາມ​ສະ​ອາດ ແລະ​ລອງ​ໃໝ່​ອີກ."</string>
@@ -521,7 +522,7 @@
<string name="fingerprint_acquired_too_slow" msgid="59250885689661653">"ຍ້າຍ​ນີ້ວ​ມື​ໄປຊ້າ​ເກີນ​ໄປ. ກະ​ລຸ​ນາ​ລອງ​ໃໝ່​ອີກ."</string>
<string-array name="fingerprint_acquired_vendor">
</string-array>
- <string name="fingerprint_not_recognized" msgid="2690661881608146617">"ບໍ່​ຈົດ​ຈຳ​ໄດ້"</string>
+ <string name="biometric_not_recognized" msgid="5770511773560736082">"ບໍ່ຮັບຮູ້"</string>
<string name="fingerprint_authenticated" msgid="5309333983002526448">"ພິສູດຢືນຢັນລາຍນິ້ວມືແລ້ວ"</string>
<string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"ບໍ່​ມີ​ຮາດ​ແວລາຍ​ນີ້ວ​ມື​ໃຫ້​ຢູ່."</string>
<string name="fingerprint_error_no_space" msgid="1055819001126053318">"ບໍ່​ສາ​ມາດ​ເກັບ​ຮັກ​ສາ​ລາຍ​ນີ້ວ​ມື​ໄວ້​ໄດ້. ກະ​ລຸ​ນາ​ເອົາ​ລາຍ​ນີ້ວ​ມື​ທີ່​ມີ​ຢູ່​ອອກ​ໄປ."</string>
diff --git a/core/res/res/values-lt/strings.xml b/core/res/res/values-lt/strings.xml
index 9409c7deafb6..a0015c35d099 100644
--- a/core/res/res/values-lt/strings.xml
+++ b/core/res/res/values-lt/strings.xml
@@ -520,6 +520,7 @@
<string name="permdesc_imagesWrite" msgid="7073662756617474375">"Programai leidžiama keisti nuotraukų kolekciją."</string>
<string name="permlab_mediaLocation" msgid="8675148183726247864">"skaityti vietoves iš medijos kolekcijos"</string>
<string name="permdesc_mediaLocation" msgid="2237023389178865130">"Programai leidžiama skaityti vietoves iš medijos kolekcijos."</string>
+ <string name="biometric_error_hw_unavailable" msgid="645781226537551036">"Biometrinė aparatinė įranga nepasiekiama"</string>
<string name="fingerprint_acquired_partial" msgid="735082772341716043">"Aptiktas dalinis kontrolinis kodas. Bandykite dar kartą."</string>
<string name="fingerprint_acquired_insufficient" msgid="4596546021310923214">"Nepavyko apdoroti kontrolinio kodo. Bandykite dar kartą."</string>
<string name="fingerprint_acquired_imager_dirty" msgid="1087209702421076105">"Kontrolinio kodo jutiklis purvinas. Nuvalykite ir bandykite dar kartą."</string>
@@ -527,7 +528,7 @@
<string name="fingerprint_acquired_too_slow" msgid="59250885689661653">"Per lėtai judinate pirštą. Bandykite dar kartą."</string>
<string-array name="fingerprint_acquired_vendor">
</string-array>
- <string name="fingerprint_not_recognized" msgid="2690661881608146617">"Neatpažintas"</string>
+ <string name="biometric_not_recognized" msgid="5770511773560736082">"Neatpažinta"</string>
<string name="fingerprint_authenticated" msgid="5309333983002526448">"Kontrolinis kodas autentifikuotas"</string>
<string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"Kontrolinio kodo aparatinė įranga nepasiekiama."</string>
<string name="fingerprint_error_no_space" msgid="1055819001126053318">"Negalima išsaugoti kontrolinio kodo. Pašalinkite esamą kontrolinį kodą."</string>
diff --git a/core/res/res/values-lv/strings.xml b/core/res/res/values-lv/strings.xml
index 272deb36949b..a1aebe1184ad 100644
--- a/core/res/res/values-lv/strings.xml
+++ b/core/res/res/values-lv/strings.xml
@@ -517,6 +517,7 @@
<string name="permdesc_imagesWrite" msgid="7073662756617474375">"Ļauj lietotnei pārveidot jūsu fotoattēlu kolekciju."</string>
<string name="permlab_mediaLocation" msgid="8675148183726247864">"Lasīt atrašanās vietas no jūsu multivides kolekcijas"</string>
<string name="permdesc_mediaLocation" msgid="2237023389178865130">"Ļauj lietotnei lasīt atrašanās vietas no jūsu multivides kolekcijas."</string>
+ <string name="biometric_error_hw_unavailable" msgid="645781226537551036">"Biometrisko datu aparatūra nav pieejama"</string>
<string name="fingerprint_acquired_partial" msgid="735082772341716043">"Noteikts daļējs pirksta nospiedums. Lūdzu, mēģiniet vēlreiz."</string>
<string name="fingerprint_acquired_insufficient" msgid="4596546021310923214">"Nevarēja apstrādāt pirksta nospiedumu. Lūdzu, mēģiniet vēlreiz."</string>
<string name="fingerprint_acquired_imager_dirty" msgid="1087209702421076105">"Pirkstu nospiedumu sensors ir netīrs. Lūdzu, notīriet to un mēģiniet vēlreiz."</string>
@@ -524,7 +525,7 @@
<string name="fingerprint_acquired_too_slow" msgid="59250885689661653">"Pārāk lēna pirksta kustība. Lūdzu, mēģiniet vēlreiz."</string>
<string-array name="fingerprint_acquired_vendor">
</string-array>
- <string name="fingerprint_not_recognized" msgid="2690661881608146617">"Nav atpazīts"</string>
+ <string name="biometric_not_recognized" msgid="5770511773560736082">"Dati nav atpazīti"</string>
<string name="fingerprint_authenticated" msgid="5309333983002526448">"Pirksta nospiedums tika autentificēts."</string>
<string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"Nospieduma aparatūra nav pieejama."</string>
<string name="fingerprint_error_no_space" msgid="1055819001126053318">"Pirkstu nospiedumu nevar saglabāt. Lūdzu, noņemiet esošu pirksta nospiedumu."</string>
diff --git a/core/res/res/values-mcc310-mnc030-pt-rBR/strings.xml b/core/res/res/values-mcc310-mnc030-pt-rBR/strings.xml
index 663261c4cf56..60a143f8eb51 100644
--- a/core/res/res/values-mcc310-mnc030-pt-rBR/strings.xml
+++ b/core/res/res/values-mcc310-mnc030-pt-rBR/strings.xml
@@ -20,7 +20,7 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="mmcc_imsi_unknown_in_hlr" msgid="6575159319460304530">"SIM não aprovisionado MM#2"</string>
- <string name="mmcc_illegal_ms" msgid="1930079814544869756">"SIM não permitido MM#3"</string>
+ <string name="mmcc_imsi_unknown_in_hlr" msgid="6575159319460304530">"Chip não aprovisionado MM#2"</string>
+ <string name="mmcc_illegal_ms" msgid="1930079814544869756">"Chip não permitido MM#3"</string>
<string name="mmcc_illegal_me" msgid="2995576894416087107">"Smartphone não permitido MM#6"</string>
</resources>
diff --git a/core/res/res/values-mcc310-mnc030-pt/strings.xml b/core/res/res/values-mcc310-mnc030-pt/strings.xml
index 663261c4cf56..60a143f8eb51 100644
--- a/core/res/res/values-mcc310-mnc030-pt/strings.xml
+++ b/core/res/res/values-mcc310-mnc030-pt/strings.xml
@@ -20,7 +20,7 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="mmcc_imsi_unknown_in_hlr" msgid="6575159319460304530">"SIM não aprovisionado MM#2"</string>
- <string name="mmcc_illegal_ms" msgid="1930079814544869756">"SIM não permitido MM#3"</string>
+ <string name="mmcc_imsi_unknown_in_hlr" msgid="6575159319460304530">"Chip não aprovisionado MM#2"</string>
+ <string name="mmcc_illegal_ms" msgid="1930079814544869756">"Chip não permitido MM#3"</string>
<string name="mmcc_illegal_me" msgid="2995576894416087107">"Smartphone não permitido MM#6"</string>
</resources>
diff --git a/core/res/res/values-mcc310-mnc170-pt-rBR/strings.xml b/core/res/res/values-mcc310-mnc170-pt-rBR/strings.xml
index fcffa1650969..c774e95d6f26 100644
--- a/core/res/res/values-mcc310-mnc170-pt-rBR/strings.xml
+++ b/core/res/res/values-mcc310-mnc170-pt-rBR/strings.xml
@@ -20,7 +20,7 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="mmcc_imsi_unknown_in_hlr" msgid="210168420192421012">"SIM não aprovisionado MM#2"</string>
- <string name="mmcc_illegal_ms" msgid="1130721094178658338">"SIM não permitido MM#3"</string>
+ <string name="mmcc_imsi_unknown_in_hlr" msgid="210168420192421012">"Chip não aprovisionado MM#2"</string>
+ <string name="mmcc_illegal_ms" msgid="1130721094178658338">"Chip não permitido MM#3"</string>
<string name="mmcc_illegal_me" msgid="3173546391131606065">"Smartphone não permitido MM#6"</string>
</resources>
diff --git a/core/res/res/values-mcc310-mnc170-pt/strings.xml b/core/res/res/values-mcc310-mnc170-pt/strings.xml
index fcffa1650969..c774e95d6f26 100644
--- a/core/res/res/values-mcc310-mnc170-pt/strings.xml
+++ b/core/res/res/values-mcc310-mnc170-pt/strings.xml
@@ -20,7 +20,7 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="mmcc_imsi_unknown_in_hlr" msgid="210168420192421012">"SIM não aprovisionado MM#2"</string>
- <string name="mmcc_illegal_ms" msgid="1130721094178658338">"SIM não permitido MM#3"</string>
+ <string name="mmcc_imsi_unknown_in_hlr" msgid="210168420192421012">"Chip não aprovisionado MM#2"</string>
+ <string name="mmcc_illegal_ms" msgid="1130721094178658338">"Chip não permitido MM#3"</string>
<string name="mmcc_illegal_me" msgid="3173546391131606065">"Smartphone não permitido MM#6"</string>
</resources>
diff --git a/core/res/res/values-mcc310-mnc280-pt-rBR/strings.xml b/core/res/res/values-mcc310-mnc280-pt-rBR/strings.xml
index f7fb684fe622..3a269b672b73 100644
--- a/core/res/res/values-mcc310-mnc280-pt-rBR/strings.xml
+++ b/core/res/res/values-mcc310-mnc280-pt-rBR/strings.xml
@@ -20,7 +20,7 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="mmcc_imsi_unknown_in_hlr" msgid="6638755728961013003">"SIM não aprovisionado MM#2"</string>
- <string name="mmcc_illegal_ms" msgid="5562215652599183258">"SIM não permitido MM#3"</string>
+ <string name="mmcc_imsi_unknown_in_hlr" msgid="6638755728961013003">"Chip não aprovisionado MM#2"</string>
+ <string name="mmcc_illegal_ms" msgid="5562215652599183258">"Chip não permitido MM#3"</string>
<string name="mmcc_illegal_me" msgid="822496463303720579">"Smartphone não permitido MM#6"</string>
</resources>
diff --git a/core/res/res/values-mcc310-mnc280-pt/strings.xml b/core/res/res/values-mcc310-mnc280-pt/strings.xml
index f7fb684fe622..3a269b672b73 100644
--- a/core/res/res/values-mcc310-mnc280-pt/strings.xml
+++ b/core/res/res/values-mcc310-mnc280-pt/strings.xml
@@ -20,7 +20,7 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="mmcc_imsi_unknown_in_hlr" msgid="6638755728961013003">"SIM não aprovisionado MM#2"</string>
- <string name="mmcc_illegal_ms" msgid="5562215652599183258">"SIM não permitido MM#3"</string>
+ <string name="mmcc_imsi_unknown_in_hlr" msgid="6638755728961013003">"Chip não aprovisionado MM#2"</string>
+ <string name="mmcc_illegal_ms" msgid="5562215652599183258">"Chip não permitido MM#3"</string>
<string name="mmcc_illegal_me" msgid="822496463303720579">"Smartphone não permitido MM#6"</string>
</resources>
diff --git a/core/res/res/values-mcc310-mnc380-pt-rBR/strings.xml b/core/res/res/values-mcc310-mnc380-pt-rBR/strings.xml
index 06bc55abdb31..6f8fb21882ea 100644
--- a/core/res/res/values-mcc310-mnc380-pt-rBR/strings.xml
+++ b/core/res/res/values-mcc310-mnc380-pt-rBR/strings.xml
@@ -20,6 +20,6 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="mmcc_imsi_unknown_in_hlr" msgid="6933439408719203102">"SIM não aprovisionado MM#2"</string>
- <string name="mmcc_illegal_ms" msgid="6367773216941648568">"SIM não permitido MM#3"</string>
+ <string name="mmcc_imsi_unknown_in_hlr" msgid="6933439408719203102">"Chip não aprovisionado MM#2"</string>
+ <string name="mmcc_illegal_ms" msgid="6367773216941648568">"Chip não permitido MM#3"</string>
</resources>
diff --git a/core/res/res/values-mcc310-mnc380-pt/strings.xml b/core/res/res/values-mcc310-mnc380-pt/strings.xml
index 06bc55abdb31..6f8fb21882ea 100644
--- a/core/res/res/values-mcc310-mnc380-pt/strings.xml
+++ b/core/res/res/values-mcc310-mnc380-pt/strings.xml
@@ -20,6 +20,6 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="mmcc_imsi_unknown_in_hlr" msgid="6933439408719203102">"SIM não aprovisionado MM#2"</string>
- <string name="mmcc_illegal_ms" msgid="6367773216941648568">"SIM não permitido MM#3"</string>
+ <string name="mmcc_imsi_unknown_in_hlr" msgid="6933439408719203102">"Chip não aprovisionado MM#2"</string>
+ <string name="mmcc_illegal_ms" msgid="6367773216941648568">"Chip não permitido MM#3"</string>
</resources>
diff --git a/core/res/res/values-mcc310-mnc410-pt-rBR/strings.xml b/core/res/res/values-mcc310-mnc410-pt-rBR/strings.xml
index f6bfc67e750a..f80ff85f5c22 100644
--- a/core/res/res/values-mcc310-mnc410-pt-rBR/strings.xml
+++ b/core/res/res/values-mcc310-mnc410-pt-rBR/strings.xml
@@ -20,7 +20,7 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="mmcc_imsi_unknown_in_hlr" msgid="376893116792604964">"SIM não aprovisionado MM#2"</string>
- <string name="mmcc_illegal_ms" msgid="1593063035884873292">"SIM não permitido MM#3"</string>
+ <string name="mmcc_imsi_unknown_in_hlr" msgid="376893116792604964">"Chip não aprovisionado MM#2"</string>
+ <string name="mmcc_illegal_ms" msgid="1593063035884873292">"Chip não permitido MM#3"</string>
<string name="mmcc_illegal_me" msgid="4477688981805467729">"Smartphone não permitido MM#6"</string>
</resources>
diff --git a/core/res/res/values-mcc310-mnc410-pt/strings.xml b/core/res/res/values-mcc310-mnc410-pt/strings.xml
index f6bfc67e750a..f80ff85f5c22 100644
--- a/core/res/res/values-mcc310-mnc410-pt/strings.xml
+++ b/core/res/res/values-mcc310-mnc410-pt/strings.xml
@@ -20,7 +20,7 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="mmcc_imsi_unknown_in_hlr" msgid="376893116792604964">"SIM não aprovisionado MM#2"</string>
- <string name="mmcc_illegal_ms" msgid="1593063035884873292">"SIM não permitido MM#3"</string>
+ <string name="mmcc_imsi_unknown_in_hlr" msgid="376893116792604964">"Chip não aprovisionado MM#2"</string>
+ <string name="mmcc_illegal_ms" msgid="1593063035884873292">"Chip não permitido MM#3"</string>
<string name="mmcc_illegal_me" msgid="4477688981805467729">"Smartphone não permitido MM#6"</string>
</resources>
diff --git a/core/res/res/values-mcc310-mnc560-pt-rBR/strings.xml b/core/res/res/values-mcc310-mnc560-pt-rBR/strings.xml
index fba400c1ab74..1d16be798085 100644
--- a/core/res/res/values-mcc310-mnc560-pt-rBR/strings.xml
+++ b/core/res/res/values-mcc310-mnc560-pt-rBR/strings.xml
@@ -20,7 +20,7 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="mmcc_imsi_unknown_in_hlr" msgid="2976453378311251765">"SIM não aprovisionado MM#2"</string>
- <string name="mmcc_illegal_ms" msgid="2519618694918727742">"SIM não permitido MM#3"</string>
+ <string name="mmcc_imsi_unknown_in_hlr" msgid="2976453378311251765">"Chip não aprovisionado MM#2"</string>
+ <string name="mmcc_illegal_ms" msgid="2519618694918727742">"Chip não permitido MM#3"</string>
<string name="mmcc_illegal_me" msgid="7030488670186895244">"Smartphone não permitido MM#6"</string>
</resources>
diff --git a/core/res/res/values-mcc310-mnc560-pt/strings.xml b/core/res/res/values-mcc310-mnc560-pt/strings.xml
index fba400c1ab74..1d16be798085 100644
--- a/core/res/res/values-mcc310-mnc560-pt/strings.xml
+++ b/core/res/res/values-mcc310-mnc560-pt/strings.xml
@@ -20,7 +20,7 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="mmcc_imsi_unknown_in_hlr" msgid="2976453378311251765">"SIM não aprovisionado MM#2"</string>
- <string name="mmcc_illegal_ms" msgid="2519618694918727742">"SIM não permitido MM#3"</string>
+ <string name="mmcc_imsi_unknown_in_hlr" msgid="2976453378311251765">"Chip não aprovisionado MM#2"</string>
+ <string name="mmcc_illegal_ms" msgid="2519618694918727742">"Chip não permitido MM#3"</string>
<string name="mmcc_illegal_me" msgid="7030488670186895244">"Smartphone não permitido MM#6"</string>
</resources>
diff --git a/core/res/res/values-mcc310-mnc950-pt-rBR/strings.xml b/core/res/res/values-mcc310-mnc950-pt-rBR/strings.xml
index 83c84ce5056b..e74582c310dc 100644
--- a/core/res/res/values-mcc310-mnc950-pt-rBR/strings.xml
+++ b/core/res/res/values-mcc310-mnc950-pt-rBR/strings.xml
@@ -20,7 +20,7 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="mmcc_imsi_unknown_in_hlr" msgid="94675382531896663">"SIM não aprovisionado MM#2"</string>
- <string name="mmcc_illegal_ms" msgid="2418195136279399212">"SIM não permitido MM#3"</string>
+ <string name="mmcc_imsi_unknown_in_hlr" msgid="94675382531896663">"Chip não aprovisionado MM#2"</string>
+ <string name="mmcc_illegal_ms" msgid="2418195136279399212">"Chip não permitido MM#3"</string>
<string name="mmcc_illegal_me" msgid="8920048244573695129">"Smartphone não permitido MM#6"</string>
</resources>
diff --git a/core/res/res/values-mcc310-mnc950-pt/strings.xml b/core/res/res/values-mcc310-mnc950-pt/strings.xml
index 83c84ce5056b..e74582c310dc 100644
--- a/core/res/res/values-mcc310-mnc950-pt/strings.xml
+++ b/core/res/res/values-mcc310-mnc950-pt/strings.xml
@@ -20,7 +20,7 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="mmcc_imsi_unknown_in_hlr" msgid="94675382531896663">"SIM não aprovisionado MM#2"</string>
- <string name="mmcc_illegal_ms" msgid="2418195136279399212">"SIM não permitido MM#3"</string>
+ <string name="mmcc_imsi_unknown_in_hlr" msgid="94675382531896663">"Chip não aprovisionado MM#2"</string>
+ <string name="mmcc_illegal_ms" msgid="2418195136279399212">"Chip não permitido MM#3"</string>
<string name="mmcc_illegal_me" msgid="8920048244573695129">"Smartphone não permitido MM#6"</string>
</resources>
diff --git a/core/res/res/values-mcc311-mnc180-pt-rBR/strings.xml b/core/res/res/values-mcc311-mnc180-pt-rBR/strings.xml
index 637a91c31878..beb1715bbde5 100644
--- a/core/res/res/values-mcc311-mnc180-pt-rBR/strings.xml
+++ b/core/res/res/values-mcc311-mnc180-pt-rBR/strings.xml
@@ -20,7 +20,7 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="mmcc_imsi_unknown_in_hlr" msgid="531930017979728896">"SIM não aprovisionado MM#2"</string>
- <string name="mmcc_illegal_ms" msgid="97745044956236881">"SIM não permitido MM#3"</string>
+ <string name="mmcc_imsi_unknown_in_hlr" msgid="531930017979728896">"Chip não aprovisionado MM#2"</string>
+ <string name="mmcc_illegal_ms" msgid="97745044956236881">"Chip não permitido MM#3"</string>
<string name="mmcc_illegal_me" msgid="5766888847785331904">"Smartphone não permitido MM#6"</string>
</resources>
diff --git a/core/res/res/values-mcc311-mnc180-pt/strings.xml b/core/res/res/values-mcc311-mnc180-pt/strings.xml
index 637a91c31878..beb1715bbde5 100644
--- a/core/res/res/values-mcc311-mnc180-pt/strings.xml
+++ b/core/res/res/values-mcc311-mnc180-pt/strings.xml
@@ -20,7 +20,7 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="mmcc_imsi_unknown_in_hlr" msgid="531930017979728896">"SIM não aprovisionado MM#2"</string>
- <string name="mmcc_illegal_ms" msgid="97745044956236881">"SIM não permitido MM#3"</string>
+ <string name="mmcc_imsi_unknown_in_hlr" msgid="531930017979728896">"Chip não aprovisionado MM#2"</string>
+ <string name="mmcc_illegal_ms" msgid="97745044956236881">"Chip não permitido MM#3"</string>
<string name="mmcc_illegal_me" msgid="5766888847785331904">"Smartphone não permitido MM#6"</string>
</resources>
diff --git a/core/res/res/values-mk/strings.xml b/core/res/res/values-mk/strings.xml
index b2beb3aad01a..0ab31b3229a0 100644
--- a/core/res/res/values-mk/strings.xml
+++ b/core/res/res/values-mk/strings.xml
@@ -514,6 +514,7 @@
<string name="permdesc_imagesWrite" msgid="7073662756617474375">"Дозволува апликацијата да ја менува вашата збирка на фотографии."</string>
<string name="permlab_mediaLocation" msgid="8675148183726247864">"да чита локации од вашата збирка на аудиовизуелни содржини"</string>
<string name="permdesc_mediaLocation" msgid="2237023389178865130">"Дозволува апликацијата да чита локации од вашата збирка на аудиовизуелни содржини."</string>
+ <string name="biometric_error_hw_unavailable" msgid="645781226537551036">"Биометрискиот хардвер е недостапен"</string>
<string name="fingerprint_acquired_partial" msgid="735082772341716043">"Откриен е делумен отпечаток. Обидете се повторно."</string>
<string name="fingerprint_acquired_insufficient" msgid="4596546021310923214">"Отпечатокот не можеше да се обработи. Обидете се повторно."</string>
<string name="fingerprint_acquired_imager_dirty" msgid="1087209702421076105">"Сензорот за отпечатоци е валкан. Исчистете го и обидете се повторно."</string>
@@ -521,7 +522,7 @@
<string name="fingerprint_acquired_too_slow" msgid="59250885689661653">"Прстот се движеше премногу бавно. Обидете се повторно."</string>
<string-array name="fingerprint_acquired_vendor">
</string-array>
- <string name="fingerprint_not_recognized" msgid="2690661881608146617">"Не е препознаено"</string>
+ <string name="biometric_not_recognized" msgid="5770511773560736082">"Непознат"</string>
<string name="fingerprint_authenticated" msgid="5309333983002526448">"Отпечатокот е проверен"</string>
<string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"Хардвер за отпечаток од прст не е достапен."</string>
<string name="fingerprint_error_no_space" msgid="1055819001126053318">"Отпечатокот не може да се складира. Отстранете го постоечкиот отпечаток."</string>
diff --git a/core/res/res/values-ml/strings.xml b/core/res/res/values-ml/strings.xml
index 81421bb8318f..eafd6a4c148f 100644
--- a/core/res/res/values-ml/strings.xml
+++ b/core/res/res/values-ml/strings.xml
@@ -514,6 +514,7 @@
<string name="permdesc_imagesWrite" msgid="7073662756617474375">"നിങ്ങളുടെ ഫോട്ടോ ശേഖരം പരിഷ്‌ക്കരിക്കുന്നതിന് ആപ്പിനെ അനുവദിക്കുന്നു."</string>
<string name="permlab_mediaLocation" msgid="8675148183726247864">"നിങ്ങളുടെ മീഡിയ ശേഖരത്തിൽ നിന്നും ലൊക്കേഷനുകൾ റീഡ് ചെയ്യുക"</string>
<string name="permdesc_mediaLocation" msgid="2237023389178865130">"നിങ്ങളുടെ മീഡിയ ശേഖരത്തിൽ നിന്നും ലൊക്കേഷനുകൾ റീഡ് ചെയ്യുന്നതിന് ആപ്പിനെ അനുവദിക്കുന്നു."</string>
+ <string name="biometric_error_hw_unavailable" msgid="645781226537551036">"ബയോമെട്രിക് ഹാർ‌ഡ്‌വെയർ ലഭ്യമല്ല"</string>
<string name="fingerprint_acquired_partial" msgid="735082772341716043">"വിരലടയാളം ഭാഗികമായി തിരിച്ചറിഞ്ഞു. വീണ്ടും ശ്രമിക്കുക."</string>
<string name="fingerprint_acquired_insufficient" msgid="4596546021310923214">"വിരലടയാളം പ്രോസസ്സ് ചെയ്യാനായില്ല. വീണ്ടും ശ്രമിക്കുക."</string>
<string name="fingerprint_acquired_imager_dirty" msgid="1087209702421076105">"വിരലടയാള സെൻസറിന് വൃത്തിയില്ല. അത് ശുചിയാക്കി വീണ്ടും ശ്രമിക്കുക."</string>
@@ -521,7 +522,7 @@
<string name="fingerprint_acquired_too_slow" msgid="59250885689661653">"വിരൽ വളരെ പതുക്കെ നീക്കി. വീണ്ടും ശ്രമിക്കുക."</string>
<string-array name="fingerprint_acquired_vendor">
</string-array>
- <string name="fingerprint_not_recognized" msgid="2690661881608146617">"തിരിച്ചറിഞ്ഞില്ല"</string>
+ <string name="biometric_not_recognized" msgid="5770511773560736082">"തിരിച്ചറിഞ്ഞില്ല"</string>
<string name="fingerprint_authenticated" msgid="5309333983002526448">"ഫിംഗർപ്രിന്റ് പരിശോധിച്ചുറപ്പിച്ചു"</string>
<string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"ഫിംഗർപ്രിന്റ് ഹാർഡ്‌വെയർ ലഭ്യമല്ല."</string>
<string name="fingerprint_error_no_space" msgid="1055819001126053318">"വിരലടയാളം സംഭരിക്കാനാവില്ല. നിലവിലുള്ള വിരലടയാളം നീക്കംചെയ്യുക."</string>
diff --git a/core/res/res/values-mn/strings.xml b/core/res/res/values-mn/strings.xml
index ddf1bc68da0b..12e318631dd6 100644
--- a/core/res/res/values-mn/strings.xml
+++ b/core/res/res/values-mn/strings.xml
@@ -514,6 +514,7 @@
<string name="permdesc_imagesWrite" msgid="7073662756617474375">"Таны зургийн цуглуулгыг тохируулах зөвшөөрлийг аппад олгодог."</string>
<string name="permlab_mediaLocation" msgid="8675148183726247864">"медиа цуглуулгаасаа байршлыг унших"</string>
<string name="permdesc_mediaLocation" msgid="2237023389178865130">"Таны медиа цуглуулгаас байршлыг унших зөвшөөрлийг аппад олгодог."</string>
+ <string name="biometric_error_hw_unavailable" msgid="645781226537551036">"Биометрийн техник хангамж боломжгүй байна"</string>
<string name="fingerprint_acquired_partial" msgid="735082772341716043">"Хурууны хээг дутуу уншуулсан байна. Дахин оролдоно уу."</string>
<string name="fingerprint_acquired_insufficient" msgid="4596546021310923214">"Хурууны хээ боловсруулж чадахгүй байна. Дахин оролдоно уу."</string>
<string name="fingerprint_acquired_imager_dirty" msgid="1087209702421076105">"Хурууны хээ мэдрэгч бохирдсон байна. Та цэвэрлэсний дараагаар дахин оролдоно уу."</string>
@@ -521,7 +522,7 @@
<string name="fingerprint_acquired_too_slow" msgid="59250885689661653">"Хуруу хэт удаан хөдөлгөсөн байна. Дахин оролдоно уу."</string>
<string-array name="fingerprint_acquired_vendor">
</string-array>
- <string name="fingerprint_not_recognized" msgid="2690661881608146617">"Танигдахгүй байна"</string>
+ <string name="biometric_not_recognized" msgid="5770511773560736082">"Таниагүй"</string>
<string name="fingerprint_authenticated" msgid="5309333983002526448">"Хурууны хээг нотолсон"</string>
<string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"Хурууны хээний тоног төхөөрөмж бэлэн бус байна."</string>
<string name="fingerprint_error_no_space" msgid="1055819001126053318">"Хурууны хээг хадгалах боломжгүй байна. Одоо байгаа хурууны хээг арилгана уу."</string>
diff --git a/core/res/res/values-mr/strings.xml b/core/res/res/values-mr/strings.xml
index c25700846219..fe248c11370f 100644
--- a/core/res/res/values-mr/strings.xml
+++ b/core/res/res/values-mr/strings.xml
@@ -514,6 +514,7 @@
<string name="permdesc_imagesWrite" msgid="7073662756617474375">"अॅपला तुमच्या फोटो संग्रहामध्ये सुधारणा करण्याची अनुमती देते."</string>
<string name="permlab_mediaLocation" msgid="8675148183726247864">"तुमच्या मीडिया संग्रहातून स्थाने वाचा"</string>
<string name="permdesc_mediaLocation" msgid="2237023389178865130">"अॅपला तुमच्या मीडिया संग्रहामध्येील स्थाने वाचण्यासाठी अनुमती देते."</string>
+ <string name="biometric_error_hw_unavailable" msgid="645781226537551036">"बायोमेट्रिक हार्डवेअर उपलब्ध नाही"</string>
<string name="fingerprint_acquired_partial" msgid="735082772341716043">"आंशिक फिंगरप्रिंट आढळली. कृपया पुन्हा प्रयत्न करा."</string>
<string name="fingerprint_acquired_insufficient" msgid="4596546021310923214">"फिंगरप्रिंटवर प्रक्रिया करणे शक्य झाले नाही. कृपया पुन्हा प्रयत्न करा."</string>
<string name="fingerprint_acquired_imager_dirty" msgid="1087209702421076105">"फिंगरप्रिंट सेन्सर खराब आहे. कृपया साफ करा आणि पुन्हा प्रयत्न करा."</string>
@@ -521,7 +522,7 @@
<string name="fingerprint_acquired_too_slow" msgid="59250885689661653">"बोट खूप सावकाश हलविले. कृपया पुन्हा प्रयत्न करा."</string>
<string-array name="fingerprint_acquired_vendor">
</string-array>
- <string name="fingerprint_not_recognized" msgid="2690661881608146617">"ओळखले नाही"</string>
+ <string name="biometric_not_recognized" msgid="5770511773560736082">"ओळखले नाही"</string>
<string name="fingerprint_authenticated" msgid="5309333983002526448">"फिंगरप्रिंट ऑथेंटिकेट केली आहे"</string>
<string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"फिंगरप्रिंट हार्डवेअर उपलब्‍ध नाही."</string>
<string name="fingerprint_error_no_space" msgid="1055819001126053318">"फिंगरप्रिंट स्टोअर केले जाऊ शकत नाही. कृपया विद्यमान फिंगरप्रिंट काढा."</string>
diff --git a/core/res/res/values-ms/strings.xml b/core/res/res/values-ms/strings.xml
index 939b9a490d7a..a813a7bdeff1 100644
--- a/core/res/res/values-ms/strings.xml
+++ b/core/res/res/values-ms/strings.xml
@@ -514,6 +514,7 @@
<string name="permdesc_imagesWrite" msgid="7073662756617474375">"Membenarkan apl mengubah suai koleksi foto anda."</string>
<string name="permlab_mediaLocation" msgid="8675148183726247864">"baca lokasi daripada koleksi media anda"</string>
<string name="permdesc_mediaLocation" msgid="2237023389178865130">"Membenarkan apl membaca lokasi daripada koleksi media anda."</string>
+ <string name="biometric_error_hw_unavailable" msgid="645781226537551036">"Perkakasan biometrik tidak tersedia"</string>
<string name="fingerprint_acquired_partial" msgid="735082772341716043">"Cap jari separa dikesan. Sila cuba lagi."</string>
<string name="fingerprint_acquired_insufficient" msgid="4596546021310923214">"Tidak dapat memproses cap jari. Sila cuba lagi."</string>
<string name="fingerprint_acquired_imager_dirty" msgid="1087209702421076105">"Penderia cap jari kotor. Sila bersihkan dan cuba lagi."</string>
@@ -521,7 +522,7 @@
<string name="fingerprint_acquired_too_slow" msgid="59250885689661653">"Jari digerakkan terlalu perlahan. Sila cuba lagi."</string>
<string-array name="fingerprint_acquired_vendor">
</string-array>
- <string name="fingerprint_not_recognized" msgid="2690661881608146617">"Tidak dicam"</string>
+ <string name="biometric_not_recognized" msgid="5770511773560736082">"Tidak dikenali"</string>
<string name="fingerprint_authenticated" msgid="5309333983002526448">"Cap jari disahkan"</string>
<string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"Perkakasan cap jari tidak tersedia."</string>
<string name="fingerprint_error_no_space" msgid="1055819001126053318">"Cap jari tidak dapat disimpan. Sila alih keluar cap jari sedia ada."</string>
diff --git a/core/res/res/values-my/strings.xml b/core/res/res/values-my/strings.xml
index 23a73ff031f4..812ff751d962 100644
--- a/core/res/res/values-my/strings.xml
+++ b/core/res/res/values-my/strings.xml
@@ -514,6 +514,7 @@
<string name="permdesc_imagesWrite" msgid="7073662756617474375">"အက်ပ်အား သင့်ဓာတ်ပုံစုစည်းမှုကို ပြုပြင်ခွင့်ပေးသည်။"</string>
<string name="permlab_mediaLocation" msgid="8675148183726247864">"သင့်မီဒီယာစုစည်းမှုမှ တည်နေရာများကို ဖတ်ခြင်း"</string>
<string name="permdesc_mediaLocation" msgid="2237023389178865130">"အက်ပ်အား သင့်မီဒီယာစုစည်းမှုမှ တည်နေရာများကို ဖတ်ခွင့်ပေးသည်။"</string>
+ <string name="biometric_error_hw_unavailable" msgid="645781226537551036">"ဇီဝအချက်အလက်သုံး ကွန်ပျူတာစက်ပစ္စည်း မရရှိနိုင်ပါ"</string>
<string name="fingerprint_acquired_partial" msgid="735082772341716043">"လက်ဗွေရဦ တစ်ပိုင်းတစ်စ တွေ့ရှိသည်။ ကျေးဇူးပြု၍ ထပ်မံကြိုးစားပါ။"</string>
<string name="fingerprint_acquired_insufficient" msgid="4596546021310923214">"လက်ဗွေရာယူခြင်း မဆောင်ရွက်နိုင်ပါ။ ထပ်မံကြိုးစားပါ။"</string>
<string name="fingerprint_acquired_imager_dirty" msgid="1087209702421076105">"လက်ဗွေရာဖတ်ကိရိယာ ညစ်ပေနေသည်။ ကျေးဇူးပြု၍ ရှင်းလင်းကာ ထပ်မံကြိုးစားပါ။"</string>
@@ -521,7 +522,7 @@
<string name="fingerprint_acquired_too_slow" msgid="59250885689661653">"လက်ညှိုးအလွန်နှေးကွေးစွာ ရွေ့ခဲ့သည်။ ကျေးဇူးပြု၍ ထပ်မံကြိုးစားပါ။"</string>
<string-array name="fingerprint_acquired_vendor">
</string-array>
- <string name="fingerprint_not_recognized" msgid="2690661881608146617">"အသိအမှတ်မပြုပါ"</string>
+ <string name="biometric_not_recognized" msgid="5770511773560736082">"မသိပါ"</string>
<string name="fingerprint_authenticated" msgid="5309333983002526448">"လက်ဗွေကို အထောက်အထား စိစစ်ပြီးပါပြီ"</string>
<string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"လက်ဗွေရာ ဟာ့ဒ်ဝဲ မရနိုင်ပါ။"</string>
<string name="fingerprint_error_no_space" msgid="1055819001126053318">"လက်ဗွေရာ သိုလှောင်၍မရပါ။ ကျေးဇူးပြု၍ ရှိပြီးလက်ဗွေရာအား ဖယ်ရှားပါ။"</string>
diff --git a/core/res/res/values-nb/strings.xml b/core/res/res/values-nb/strings.xml
index 7d3fe4862221..439b0de35ba9 100644
--- a/core/res/res/values-nb/strings.xml
+++ b/core/res/res/values-nb/strings.xml
@@ -514,6 +514,7 @@
<string name="permdesc_imagesWrite" msgid="7073662756617474375">"Lar appen gjøre endringer i bildesamlingen din."</string>
<string name="permlab_mediaLocation" msgid="8675148183726247864">"lese posisjoner fra mediesamlingen din"</string>
<string name="permdesc_mediaLocation" msgid="2237023389178865130">"Lar appen lese posisjoner fra mediesamlingen din."</string>
+ <string name="biometric_error_hw_unavailable" msgid="645781226537551036">"Biometrisk maskinvare er utilgjengelig"</string>
<string name="fingerprint_acquired_partial" msgid="735082772341716043">"Deler av fingeravtrykket er registrert. Prøv på nytt."</string>
<string name="fingerprint_acquired_insufficient" msgid="4596546021310923214">"Kunne ikke registrere fingeravtrykket. Prøv på nytt."</string>
<string name="fingerprint_acquired_imager_dirty" msgid="1087209702421076105">"Fingeravtrykksensoren er skitten. Rengjør den og prøv på nytt."</string>
@@ -521,7 +522,7 @@
<string name="fingerprint_acquired_too_slow" msgid="59250885689661653">"Du flyttet fingeren for sakte. Prøv på nytt."</string>
<string-array name="fingerprint_acquired_vendor">
</string-array>
- <string name="fingerprint_not_recognized" msgid="2690661881608146617">"Ikke gjenkjent"</string>
+ <string name="biometric_not_recognized" msgid="5770511773560736082">"Ikke gjenkjent"</string>
<string name="fingerprint_authenticated" msgid="5309333983002526448">"Fingeravtrykket er godkjent"</string>
<string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"Maskinvare for fingeravtrykk er ikke tilgjengelig."</string>
<string name="fingerprint_error_no_space" msgid="1055819001126053318">"Fingeravtrykket kan ikke lagres. Fjern et eksisterende fingeravtrykk."</string>
diff --git a/core/res/res/values-ne/strings.xml b/core/res/res/values-ne/strings.xml
index 55e62ff0fe50..d45e28b024d5 100644
--- a/core/res/res/values-ne/strings.xml
+++ b/core/res/res/values-ne/strings.xml
@@ -514,6 +514,7 @@
<string name="permdesc_imagesWrite" msgid="7073662756617474375">"यसले अनुप्रयोगलाई तपाईंको तस्बिरको सङ्ग्रह परिमार्जन गर्न दिन्छ।"</string>
<string name="permlab_mediaLocation" msgid="8675148183726247864">"आफ्नो मिडियाको सङ्ग्रहका स्थानहरू पढ्नुहोस्‌"</string>
<string name="permdesc_mediaLocation" msgid="2237023389178865130">"यसले अनुप्रयोगलाई तपाईंको मिडिया सङ्ग्रहका स्थानहरू पढ्न दिन्छ।"</string>
+ <string name="biometric_error_hw_unavailable" msgid="645781226537551036">"बायोमेट्रिक हार्डवेयर उपलब्ध छैन"</string>
<string name="fingerprint_acquired_partial" msgid="735082772341716043">"आंशिक औठाछाप पत्ता लाग्यो। कृपया फेरि प्रयास गर्नुहोस्।"</string>
<string name="fingerprint_acquired_insufficient" msgid="4596546021310923214">"औठाछाप प्रशोधन गर्न सकिएन। कृपया फेरि प्रयास गर्नुहोस्।"</string>
<string name="fingerprint_acquired_imager_dirty" msgid="1087209702421076105">"औँठाछाप सेन्सर फोहोर छ। कृपया सफा गरेर फेरि प्रयास गर्नुहोस्।"</string>
@@ -521,7 +522,7 @@
<string name="fingerprint_acquired_too_slow" msgid="59250885689661653">"औंला निकै सुस्त सारियो। कृपया फेरि प्रयास गर्नुहोस्।"</string>
<string-array name="fingerprint_acquired_vendor">
</string-array>
- <string name="fingerprint_not_recognized" msgid="2690661881608146617">"चिनिएको छैन"</string>
+ <string name="biometric_not_recognized" msgid="5770511773560736082">"पहिचान भएन"</string>
<string name="fingerprint_authenticated" msgid="5309333983002526448">"फिंगरप्रिन्ट प्रमाणीकरण गरियो"</string>
<string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"औँठाछाप हार्डवेयर उपलब्ध छैन।"</string>
<string name="fingerprint_error_no_space" msgid="1055819001126053318">"औँठाछाप भण्डारण गर्न सकिँदैन। कृपया अवस्थित औठाछाप हटाउनुहोस्।"</string>
diff --git a/core/res/res/values-nl/strings.xml b/core/res/res/values-nl/strings.xml
index 0e131320b633..df152b2f46fb 100644
--- a/core/res/res/values-nl/strings.xml
+++ b/core/res/res/values-nl/strings.xml
@@ -514,6 +514,7 @@
<string name="permdesc_imagesWrite" msgid="7073662756617474375">"Hiermee sta je de app toe je fotocollectie aan te passen."</string>
<string name="permlab_mediaLocation" msgid="8675148183726247864">"locaties van je mediacollecties bekijken"</string>
<string name="permdesc_mediaLocation" msgid="2237023389178865130">"Hiermee sta je de app toe locaties van je mediacollectie te bekijken."</string>
+ <string name="biometric_error_hw_unavailable" msgid="645781226537551036">"Biometrische hardware niet beschikbaar"</string>
<string name="fingerprint_acquired_partial" msgid="735082772341716043">"Gedeeltelijke vingerafdruk gedetecteerd. Probeer het opnieuw."</string>
<string name="fingerprint_acquired_insufficient" msgid="4596546021310923214">"Kan vingerafdruk niet verwerken. Probeer het opnieuw."</string>
<string name="fingerprint_acquired_imager_dirty" msgid="1087209702421076105">"De vingerafdruksensor moet worden schoongemaakt. Probeer het daarna opnieuw."</string>
@@ -521,7 +522,7 @@
<string name="fingerprint_acquired_too_slow" msgid="59250885689661653">"Vinger te langzaam bewogen. Probeer het opnieuw."</string>
<string-array name="fingerprint_acquired_vendor">
</string-array>
- <string name="fingerprint_not_recognized" msgid="2690661881608146617">"Niet herkend"</string>
+ <string name="biometric_not_recognized" msgid="5770511773560736082">"Niet herkend"</string>
<string name="fingerprint_authenticated" msgid="5309333983002526448">"Vingerafdruk geverifieerd"</string>
<string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"Hardware voor vingerafdruk niet beschikbaar."</string>
<string name="fingerprint_error_no_space" msgid="1055819001126053318">"Vingerafdruk kan niet worden opgeslagen. Verwijder een bestaande vingerafdruk."</string>
diff --git a/core/res/res/values-or/strings.xml b/core/res/res/values-or/strings.xml
index b3a2c8144b1d..78566da2c06f 100644
--- a/core/res/res/values-or/strings.xml
+++ b/core/res/res/values-or/strings.xml
@@ -514,6 +514,7 @@
<string name="permdesc_imagesWrite" msgid="7073662756617474375">"ଆପଣଙ୍କ ଫଟୋ ସଂଗ୍ରହ ପରିବର୍ତ୍ତନ କରିବାକୁ ଆପ୍‍ ଅନୁମତି ଦେଇଥାଏ।"</string>
<string name="permlab_mediaLocation" msgid="8675148183726247864">"ଆପଣଙ୍କ ମିଡିଆ ସଂଗ୍ରହ ଠାରୁ ଲୋକେସନ୍‍ଗୁଡିକୁ ପଢନ୍ତୁ"</string>
<string name="permdesc_mediaLocation" msgid="2237023389178865130">"ଆପଣଙ୍କ ମିଡିଆ ସଂଗ୍ରହ ଠାରୁ ଅବସ୍ଥାନଗୁଡିକୁ ପଢିବାକୁ ଆପ୍‍ ଅନୁମତି ଦେଇଥାଏ।"</string>
+ <string name="biometric_error_hw_unavailable" msgid="645781226537551036">"ବାୟୋମେଟ୍ରିକ୍‌ ହାର୍ଡୱେର୍‌ ଉପଲବ୍ଧ ନାହିଁ"</string>
<string name="fingerprint_acquired_partial" msgid="735082772341716043">"ଆଙ୍ଗୁଠି ଚିହ୍ନ ଆଂଶିକ ଚିହ୍ନଟ ହେଲା। ଦୟାକରି ପୁଣି ଚେଷ୍ଟା କରନ୍ତୁ।"</string>
<string name="fingerprint_acquired_insufficient" msgid="4596546021310923214">"ଆଙ୍ଗୁଠି ଚିହ୍ନ ପ୍ରୋସେସ୍‍ କରାଯାଇପାରିଲା ନାହିଁ। ଦୟାକରି ପୁଣି ଚେଷ୍ଟା କରନ୍ତୁ।"</string>
<string name="fingerprint_acquired_imager_dirty" msgid="1087209702421076105">"ଆଙ୍ଗୁଠି ଚିହ୍ନ ସେନ୍ସର୍‍ ମଇଳା ହୋଇଯାଇଛି। ଦୟାକରି ସଫା କରନ୍ତୁ ଓ ପୁଣି ଚେଷ୍ଟା କରନ୍ତୁ।"</string>
@@ -521,7 +522,7 @@
<string name="fingerprint_acquired_too_slow" msgid="59250885689661653">"ଆଙ୍ଗୁଠି ଖୁବ୍‍ ଧୀରେ ନିଆଗଲା। ଦୟାକରି ପୁଣି ଚେଷ୍ଟା କରନ୍ତୁ।"</string>
<string-array name="fingerprint_acquired_vendor">
</string-array>
- <string name="fingerprint_not_recognized" msgid="2690661881608146617">"ଚିହ୍ନଟ ହେଲା ନାହିଁ"</string>
+ <string name="biometric_not_recognized" msgid="5770511773560736082">"ଚିହ୍ନଟ ହେଲାନାହିଁ"</string>
<string name="fingerprint_authenticated" msgid="5309333983002526448">"ଆଙ୍ଗୁଠି ଚିହ୍ନ ପ୍ରମାଣୀକୃତ ହେଲା"</string>
<string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"ଆଙ୍ଗୁଠି ଚିହ୍ନ ହାର୍ଡୱେର୍‍ ଉପଲବ୍ଧ ନାହିଁ।"</string>
<string name="fingerprint_error_no_space" msgid="1055819001126053318">"ଆଙ୍ଗୁଠି ଚିହ୍ନ ଷ୍ଟୋର୍‍ କରାଯାଇପାରିବ ନାହିଁ। ଦୟାକରି ପୂର୍ବରୁ ଥିବା ଆଙ୍ଗୁଠି ଚିହ୍ନକୁ ବାହାର କରିଦିଅନ୍ତୁ।"</string>
diff --git a/core/res/res/values-pa/strings.xml b/core/res/res/values-pa/strings.xml
index d581e6b91e55..bb38c886edd3 100644
--- a/core/res/res/values-pa/strings.xml
+++ b/core/res/res/values-pa/strings.xml
@@ -514,6 +514,7 @@
<string name="permdesc_imagesWrite" msgid="7073662756617474375">"ਐਪ ਨੂੰ ਤੁਹਾਡੇ ਫ਼ੋਟੋ ਸੰਗ੍ਰਹਿ ਨੂੰ ਸੋਧਣ ਦਿੰਦੀ ਹੈ।"</string>
<string name="permlab_mediaLocation" msgid="8675148183726247864">"ਤੁਹਾਡੇ ਮੀਡੀਆ ਸੰਗ੍ਰਹਿ ਦੇ ਟਿਕਾਣਿਆਂ ਨੂੰ ਪੜ੍ਹਨਾ"</string>
<string name="permdesc_mediaLocation" msgid="2237023389178865130">"ਐਪ ਨੂੰ ਤੁਹਾਡੇ ਮੀਡੀਆ ਸੰਗ੍ਰਹਿ ਦੇ ਟਿਕਾਣਿਆਂ ਨੂੰ ਪੜ੍ਹਨ ਦਿੰਦੀ ਹੈ।"</string>
+ <string name="biometric_error_hw_unavailable" msgid="645781226537551036">"ਬਾਇਓਮੈਟ੍ਰਿਕ ਹਾਰਡਵੇਅਰ ਉਪਲਬਧ ਨਹੀਂ ਹੈ"</string>
<string name="fingerprint_acquired_partial" msgid="735082772341716043">"ਅਧੂਰਾ ਫਿੰਗਰਪ੍ਰਿਟ ਮਿਲਿਆ। ਕਿਰਪਾ ਕਰਕੇ ਦੁਬਾਰਾ ਕੋਸ਼ਿਸ਼ ਕਰੋ।"</string>
<string name="fingerprint_acquired_insufficient" msgid="4596546021310923214">"ਫਿੰਗਰਪ੍ਰਿੰਟ ਦੀ ਪ੍ਰਕਿਰਿਆ ਨਹੀਂ ਕਰ ਸਕਿਆ। ਕਿਰਪਾ ਕਰਕੇ ਦੁਬਾਰਾ ਕੋਸ਼ਿਸ਼ ਕਰੋ।"</string>
<string name="fingerprint_acquired_imager_dirty" msgid="1087209702421076105">"ਫਿੰਗਰਪ੍ਰਿੰਟ ਸੰਵੇਦਕ ਗੰਦਾ ਹੈ। ਕਿਰਪਾ ਕਰਕੇ ਇਸਨੂੰ ਸਾਫ਼ ਕਰੋ ਅਤੇ ਦੁਬਾਰਾ ਕੋਸ਼ਿਸ਼ ਕਰੋ।"</string>
@@ -521,7 +522,7 @@
<string name="fingerprint_acquired_too_slow" msgid="59250885689661653">"ਉਂਗਲ ਕਾਫ਼ੀ ਹੌਲੀ ਮੂਵ ਹੋਈ। ਕਿਰਪਾ ਕਰਕੇ ਦੁਬਾਰਾ ਕੋਸ਼ਿਸ਼ ਕਰੋ।"</string>
<string-array name="fingerprint_acquired_vendor">
</string-array>
- <string name="fingerprint_not_recognized" msgid="2690661881608146617">"ਪਛਾਣ ਨਹੀਂ ਹੋਈ"</string>
+ <string name="biometric_not_recognized" msgid="5770511773560736082">"ਪਛਾਣ ਨਹੀਂ ਹੋਈ"</string>
<string name="fingerprint_authenticated" msgid="5309333983002526448">"ਫਿੰਗਰਪ੍ਰਿੰਟ ਪ੍ਰਮਾਣਿਤ ਹੋਇਆ"</string>
<string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"ਫਿੰਗਰਪ੍ਰਿੰਟ ਹਾਰਡਵੇਅਰ ਉਪਲਬਧ ਨਹੀਂ।"</string>
<string name="fingerprint_error_no_space" msgid="1055819001126053318">"ਫਿੰਗਰਪ੍ਰਿੰਟ ਸਟੋਰ ਨਹੀਂ ਕੀਤਾ ਸਕਦਾ। ਕਿਰਪਾ ਕਰਕੇ ਇੱਕ ਮੌਜੂਦਾ ਫਿੰਗਰਪ੍ਰਿੰਟ ਹਟਾਓ।"</string>
diff --git a/core/res/res/values-pl/strings.xml b/core/res/res/values-pl/strings.xml
index 6f56e7f116b4..d59b1386181a 100644
--- a/core/res/res/values-pl/strings.xml
+++ b/core/res/res/values-pl/strings.xml
@@ -520,6 +520,7 @@
<string name="permdesc_imagesWrite" msgid="7073662756617474375">"Zezwala aplikacji na modyfikowanie kolekcji zdjęć."</string>
<string name="permlab_mediaLocation" msgid="8675148183726247864">"odczytywanie lokalizacji z kolekcji multimediów"</string>
<string name="permdesc_mediaLocation" msgid="2237023389178865130">"Zezwala aplikacji na odczytywanie lokalizacji z kolekcji multimediów."</string>
+ <string name="biometric_error_hw_unavailable" msgid="645781226537551036">"Sprzęt biometryczny niedostępny"</string>
<string name="fingerprint_acquired_partial" msgid="735082772341716043">"Odcisk palca został odczytany tylko częściowo. Spróbuj ponownie."</string>
<string name="fingerprint_acquired_insufficient" msgid="4596546021310923214">"Nie udało się przetworzyć odcisku palca. Spróbuj ponownie."</string>
<string name="fingerprint_acquired_imager_dirty" msgid="1087209702421076105">"Czytnik linii papilarnych jest zabrudzony. Wyczyść go i spróbuj ponownie."</string>
@@ -527,7 +528,7 @@
<string name="fingerprint_acquired_too_slow" msgid="59250885689661653">"Palec został obrócony zbyt wolno. Spróbuj ponownie."</string>
<string-array name="fingerprint_acquired_vendor">
</string-array>
- <string name="fingerprint_not_recognized" msgid="2690661881608146617">"Nie rozpoznano odcisku palca."</string>
+ <string name="biometric_not_recognized" msgid="5770511773560736082">"Nie rozpoznano"</string>
<string name="fingerprint_authenticated" msgid="5309333983002526448">"Uwierzytelniono odciskiem palca"</string>
<string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"Czytnik linii papilarnych nie jest dostępny."</string>
<string name="fingerprint_error_no_space" msgid="1055819001126053318">"Nie można zapisać odcisku palca. Usuń istniejący odcisk palca."</string>
diff --git a/core/res/res/values-pt-rBR/strings.xml b/core/res/res/values-pt-rBR/strings.xml
index ad68dde271ea..48302a0d9d4c 100644
--- a/core/res/res/values-pt-rBR/strings.xml
+++ b/core/res/res/values-pt-rBR/strings.xml
@@ -47,12 +47,12 @@
<string name="mismatchPin" msgid="609379054496863419">"Os PINs digitados não correspondem."</string>
<string name="invalidPin" msgid="3850018445187475377">"Digite um PIN com 4 a 8 números."</string>
<string name="invalidPuk" msgid="8761456210898036513">"Digite um PUK com oito números ou mais."</string>
- <string name="needPuk" msgid="919668385956251611">"O seu cartão SIM está bloqueado por um PUK. Digite o código PUK para desbloqueá-lo."</string>
- <string name="needPuk2" msgid="4526033371987193070">"Digite o PUK2 para desbloquear o cartão SIM."</string>
- <string name="enablePin" msgid="209412020907207950">"Falha. Ative o bloqueio do SIM/R-UIM."</string>
+ <string name="needPuk" msgid="919668385956251611">"O seu chip está bloqueado por um PUK. Digite o código PUK para desbloqueá-lo."</string>
+ <string name="needPuk2" msgid="4526033371987193070">"Digite o PUK2 para desbloquear o chip."</string>
+ <string name="enablePin" msgid="209412020907207950">"Falha. Ative o bloqueio do chip/R-UIM."</string>
<plurals name="pinpuk_attempts" formatted="false" msgid="1251012001539225582">
- <item quantity="one">Tentativas restantes: <xliff:g id="NUMBER_1">%d</xliff:g>. Caso o código correto não seja digitado, o SIM será bloqueado.</item>
- <item quantity="other">Tentativas restantes: <xliff:g id="NUMBER_1">%d</xliff:g>. Caso o código correto não seja digitado, o SIM será bloqueado.</item>
+ <item quantity="one">Tentativas restantes: <xliff:g id="NUMBER_1">%d</xliff:g>. Caso o código correto não seja digitado, o chip será bloqueado.</item>
+ <item quantity="other">Tentativas restantes: <xliff:g id="NUMBER_1">%d</xliff:g>. Caso o código correto não seja digitado, o chip será bloqueado.</item>
</plurals>
<string name="imei" msgid="2625429890869005782">"IMEI"</string>
<string name="meid" msgid="4841221237681254195">"MEID"</string>
@@ -82,7 +82,7 @@
<string name="RestrictedOnNormalTitle" msgid="3179574012752700984">"Sem serviço de voz"</string>
<string name="RestrictedOnAllVoiceTitle" msgid="8037246983606545202">"Nenhum serviço de voz nem chamada de emergência"</string>
<string name="RestrictedStateContent" msgid="6538703255570997248">"Temporariamente desativado pela sua operadora"</string>
- <string name="RestrictedStateContentMsimTemplate" msgid="673416791370248176">"Temporariamente desativado pela sua operadora para o SIM <xliff:g id="SIMNUMBER">%d</xliff:g>"</string>
+ <string name="RestrictedStateContentMsimTemplate" msgid="673416791370248176">"Temporariamente desativado pela sua operadora para o chip <xliff:g id="SIMNUMBER">%d</xliff:g>"</string>
<string name="NetworkPreferenceSwitchTitle" msgid="6982395015324165258">"Não foi possível acessar a rede móvel"</string>
<string name="NetworkPreferenceSwitchSummary" msgid="509327194863482733">"Tente alterar a rede preferencial. Toque para alterar."</string>
<string name="EmergencyCallWarningTitle" msgid="813380189532491336">"Chamadas de emergência indisponíveis"</string>
@@ -94,7 +94,7 @@
<string name="notification_channel_sms" msgid="3441746047346135073">"Mensagens SMS"</string>
<string name="notification_channel_voice_mail" msgid="3954099424160511919">"Mensagens do correio de voz"</string>
<string name="notification_channel_wfc" msgid="2130802501654254801">"Chamadas por Wi-Fi"</string>
- <string name="notification_channel_sim" msgid="4052095493875188564">"Status do SIM"</string>
+ <string name="notification_channel_sim" msgid="4052095493875188564">"Status do chip"</string>
<string name="peerTtyModeFull" msgid="6165351790010341421">"TTD modo COMPLETO solicitado"</string>
<string name="peerTtyModeHco" msgid="5728602160669216784">"TTD modo HCO solicitado"</string>
<string name="peerTtyModeVco" msgid="1742404978686538049">"TTD modo VCO solicitado"</string>
@@ -420,8 +420,8 @@
<string name="permdesc_modifyAudioSettings" msgid="3522565366806248517">"Permite que o app modifique configurações de áudio globais como volume e alto-falantes de saída."</string>
<string name="permlab_recordAudio" msgid="3876049771427466323">"gravar áudio"</string>
<string name="permdesc_recordAudio" msgid="4245930455135321433">"Este app pode gravar áudio usando o microfone a qualquer momento."</string>
- <string name="permlab_sim_communication" msgid="2935852302216852065">"enviar comandos para o SIM"</string>
- <string name="permdesc_sim_communication" msgid="5725159654279639498">"Permite que o app envie comandos ao SIM. Muito perigoso."</string>
+ <string name="permlab_sim_communication" msgid="2935852302216852065">"enviar comandos para o chip"</string>
+ <string name="permdesc_sim_communication" msgid="5725159654279639498">"Permite que o app envie comandos ao chip. Muito perigoso."</string>
<string name="permlab_camera" msgid="3616391919559751192">"tirar fotos e gravar vídeos"</string>
<string name="permdesc_camera" msgid="5392231870049240670">"Este app pode tirar fotos e gravar vídeos usando a câmera a qualquer momento."</string>
<string name="permlab_vibrate" msgid="7696427026057705834">"controlar vibração"</string>
@@ -514,6 +514,7 @@
<string name="permdesc_imagesWrite" msgid="7073662756617474375">"Permite que o app modifique sua coleção de fotos."</string>
<string name="permlab_mediaLocation" msgid="8675148183726247864">"ler locais na sua coleção de mídias"</string>
<string name="permdesc_mediaLocation" msgid="2237023389178865130">"Permite que o app leia os locais na sua coleção de mídias."</string>
+ <string name="biometric_error_hw_unavailable" msgid="645781226537551036">"Hardware biométrico indisponível"</string>
<string name="fingerprint_acquired_partial" msgid="735082772341716043">"Impressão digital parcial detectada. Tente novamente."</string>
<string name="fingerprint_acquired_insufficient" msgid="4596546021310923214">"Não foi possível processar a impressão digital. Tente novamente."</string>
<string name="fingerprint_acquired_imager_dirty" msgid="1087209702421076105">"O sensor de impressão digital está sujo. Limpe-o e tente novamente."</string>
@@ -521,7 +522,7 @@
<string name="fingerprint_acquired_too_slow" msgid="59250885689661653">"O movimento do dedo está muito lento. Tente novamente."</string>
<string-array name="fingerprint_acquired_vendor">
</string-array>
- <string name="fingerprint_not_recognized" msgid="2690661881608146617">"Não reconhecido"</string>
+ <string name="biometric_not_recognized" msgid="5770511773560736082">"Não reconhecido"</string>
<string name="fingerprint_authenticated" msgid="5309333983002526448">"Impressão digital autenticada"</string>
<string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"Hardware de impressão digital não disponível."</string>
<string name="fingerprint_error_no_space" msgid="1055819001126053318">"Não foi possível armazenar a impressão digital. Remova uma impressão digital já existente."</string>
@@ -795,14 +796,14 @@
<string name="lockscreen_password_wrong" msgid="5737815393253165301">"Tente novamente"</string>
<string name="lockscreen_storage_locked" msgid="9167551160010625200">"Desbloqueio para todos os recursos e dados"</string>
<string name="faceunlock_multiple_failures" msgid="754137583022792429">"O número máximo de tentativas de Desbloqueio por reconhecimento facial foi excedido"</string>
- <string name="lockscreen_missing_sim_message_short" msgid="5099439277819215399">"Sem cartão SIM"</string>
- <string name="lockscreen_missing_sim_message" product="tablet" msgid="151659196095791474">"Não há um cartão SIM no tablet."</string>
- <string name="lockscreen_missing_sim_message" product="tv" msgid="1943633865476989599">"Nenhum cartão SIM na TV."</string>
- <string name="lockscreen_missing_sim_message" product="default" msgid="2186920585695169078">"Não há um cartão SIM no telefone."</string>
- <string name="lockscreen_missing_sim_instructions" msgid="5372787138023272615">"Insera um cartão SIM."</string>
- <string name="lockscreen_missing_sim_instructions_long" msgid="3526573099019319472">"O cartão SIM não foi inserido ou não é possível lê-lo. Insira um cartão SIM."</string>
- <string name="lockscreen_permanent_disabled_sim_message_short" msgid="5096149665138916184">"Cartão SIM inutilizável."</string>
- <string name="lockscreen_permanent_disabled_sim_instructions" msgid="910904643433151371">"O cartão SIM foi desativado permanentemente.\nEntre em contato com seu provedor de serviços sem fio para obter outro cartão SIM."</string>
+ <string name="lockscreen_missing_sim_message_short" msgid="5099439277819215399">"Sem chip"</string>
+ <string name="lockscreen_missing_sim_message" product="tablet" msgid="151659196095791474">"Não há um chip no tablet."</string>
+ <string name="lockscreen_missing_sim_message" product="tv" msgid="1943633865476989599">"Nenhum chip na TV."</string>
+ <string name="lockscreen_missing_sim_message" product="default" msgid="2186920585695169078">"Não há um chip no telefone."</string>
+ <string name="lockscreen_missing_sim_instructions" msgid="5372787138023272615">"Insera um chip."</string>
+ <string name="lockscreen_missing_sim_instructions_long" msgid="3526573099019319472">"O chip não foi inserido ou não é possível lê-lo. Insira um chip."</string>
+ <string name="lockscreen_permanent_disabled_sim_message_short" msgid="5096149665138916184">"Chip inutilizável."</string>
+ <string name="lockscreen_permanent_disabled_sim_instructions" msgid="910904643433151371">"O chip foi desativado permanentemente.\nEntre em contato com seu provedor de serviços sem fio para obter outro chip."</string>
<string name="lockscreen_transport_prev_description" msgid="6300840251218161534">"Faixa anterior"</string>
<string name="lockscreen_transport_next_description" msgid="573285210424377338">"Próxima faixa"</string>
<string name="lockscreen_transport_pause_description" msgid="3980308465056173363">"Pausar"</string>
@@ -812,10 +813,10 @@
<string name="lockscreen_transport_ffw_description" msgid="42987149870928985">"Avançar"</string>
<string name="emergency_calls_only" msgid="6733978304386365407">"Só chamadas de emergência"</string>
<string name="lockscreen_network_locked_message" msgid="143389224986028501">"Rede bloqueada"</string>
- <string name="lockscreen_sim_puk_locked_message" msgid="7441797339976230">"O cartão SIM está bloqueado pelo PUK."</string>
+ <string name="lockscreen_sim_puk_locked_message" msgid="7441797339976230">"O chip está bloqueado pelo PUK."</string>
<string name="lockscreen_sim_puk_locked_instructions" msgid="8127916255245181063">"Consulte o Guia do usuário ou entre em contato com o Serviço de atendimento ao cliente."</string>
- <string name="lockscreen_sim_locked_message" msgid="8066660129206001039">"O cartão SIM está bloqueado."</string>
- <string name="lockscreen_sim_unlock_progress_dialog_message" msgid="595323214052881264">"Desbloqueando o cartão SIM…"</string>
+ <string name="lockscreen_sim_locked_message" msgid="8066660129206001039">"O chip está bloqueado."</string>
+ <string name="lockscreen_sim_unlock_progress_dialog_message" msgid="595323214052881264">"Desbloqueando o chip…"</string>
<string name="lockscreen_too_many_failed_attempts_dialog_message" msgid="6481623830344107222">"Você desenhou seu padrão de desbloqueio incorretamente <xliff:g id="NUMBER_0">%1$d</xliff:g> vezes. \n\nTente novamente em <xliff:g id="NUMBER_1">%2$d</xliff:g> segundos."</string>
<string name="lockscreen_too_many_failed_password_attempts_dialog_message" msgid="2725973286239344555">"Você digitou sua senha incorretamente <xliff:g id="NUMBER_0">%1$d</xliff:g> vezes. \n\nTente novamente em <xliff:g id="NUMBER_1">%2$d</xliff:g> segundos."</string>
<string name="lockscreen_too_many_failed_pin_attempts_dialog_message" msgid="6216672706545696955">"Você digitou seu PIN incorretamente <xliff:g id="NUMBER_0">%1$d</xliff:g> vezes.\n\nTente novamente em <xliff:g id="NUMBER_1">%2$d</xliff:g> segundos."</string>
@@ -866,8 +867,8 @@
<string name="keyguard_accessibility_pattern_unlock" msgid="1490840706075246612">"Desbloqueio com padrão."</string>
<string name="keyguard_accessibility_face_unlock" msgid="4817282543351718535">"Desbloqueio facial."</string>
<string name="keyguard_accessibility_pin_unlock" msgid="2469687111784035046">"Desbloqueio com PIN."</string>
- <string name="keyguard_accessibility_sim_pin_unlock" msgid="9149698847116962307">"Desbloqueio com PIN do SIM."</string>
- <string name="keyguard_accessibility_sim_puk_unlock" msgid="9106899279724723341">"Desbloqueio com PUK do SIM."</string>
+ <string name="keyguard_accessibility_sim_pin_unlock" msgid="9149698847116962307">"Desbloqueio com PIN do chip."</string>
+ <string name="keyguard_accessibility_sim_puk_unlock" msgid="9106899279724723341">"Desbloqueio com PUK do chip."</string>
<string name="keyguard_accessibility_password_unlock" msgid="7675777623912155089">"Desbloqueio com senha."</string>
<string name="keyguard_accessibility_pattern_area" msgid="7679891324509597904">"Área do padrão."</string>
<string name="keyguard_accessibility_slide_area" msgid="6736064494019979544">"Área de deslize."</string>
@@ -1277,17 +1278,17 @@
<string name="sms_short_code_remember_undo_instruction" msgid="4960944133052287484">"P/ alterar: Configurações &gt; Apps"</string>
<string name="sms_short_code_confirm_always_allow" msgid="3241181154869493368">"Sempre permitir"</string>
<string name="sms_short_code_confirm_never_allow" msgid="446992765774269673">"Nunca permitir"</string>
- <string name="sim_removed_title" msgid="6227712319223226185">"Cartão SIM removido"</string>
- <string name="sim_removed_message" msgid="2333164559970958645">"A rede móvel ficará indisponível até que você reinicie com um cartão SIM válido inserido."</string>
+ <string name="sim_removed_title" msgid="6227712319223226185">"Chip removido"</string>
+ <string name="sim_removed_message" msgid="2333164559970958645">"A rede móvel ficará indisponível até que você reinicie com um chip válido inserido."</string>
<string name="sim_done_button" msgid="827949989369963775">"Concluído"</string>
- <string name="sim_added_title" msgid="3719670512889674693">"Cartão SIM adicionado"</string>
+ <string name="sim_added_title" msgid="3719670512889674693">"Chip adicionado"</string>
<string name="sim_added_message" msgid="6599945301141050216">"Reinicie o dispositivo para acessar a rede móvel."</string>
<string name="sim_restart_button" msgid="4722407842815232347">"Reiniciar"</string>
<string name="install_carrier_app_notification_title" msgid="9056007111024059888">"Ativar serviço móvel"</string>
- <string name="install_carrier_app_notification_text" msgid="3346681446158696001">"Faça o download do app da operadora para ativar seu novo SIM"</string>
- <string name="install_carrier_app_notification_text_app_name" msgid="1196505084835248137">"Faça o download do app <xliff:g id="APP_NAME">%1$s</xliff:g> para ativar seu novo SIM"</string>
+ <string name="install_carrier_app_notification_text" msgid="3346681446158696001">"Faça o download do app da operadora para ativar seu novo chip"</string>
+ <string name="install_carrier_app_notification_text_app_name" msgid="1196505084835248137">"Faça o download do app <xliff:g id="APP_NAME">%1$s</xliff:g> para ativar seu novo chip"</string>
<string name="install_carrier_app_notification_button" msgid="3094206295081900849">"Fazer download do app"</string>
- <string name="carrier_app_notification_title" msgid="8921767385872554621">"Novo SIM inserido"</string>
+ <string name="carrier_app_notification_title" msgid="8921767385872554621">"Novo chip inserido"</string>
<string name="carrier_app_notification_text" msgid="1132487343346050225">"Toque para configurar"</string>
<string name="time_picker_dialog_title" msgid="8349362623068819295">"Definir hora"</string>
<string name="date_picker_dialog_title" msgid="5879450659453782278">"Definir data"</string>
@@ -1572,17 +1573,17 @@
<item quantity="other">Tente novamente em <xliff:g id="NUMBER">%d</xliff:g> segundos.</item>
</plurals>
<string name="kg_pattern_instructions" msgid="398978611683075868">"Desenhe seu padrão"</string>
- <string name="kg_sim_pin_instructions" msgid="2319508550934557331">"Digite o PIN do cartão SIM"</string>
+ <string name="kg_sim_pin_instructions" msgid="2319508550934557331">"Digite o PIN do chip"</string>
<string name="kg_pin_instructions" msgid="2377242233495111557">"Digite o PIN"</string>
<string name="kg_password_instructions" msgid="5753646556186936819">"Digite a senha"</string>
- <string name="kg_puk_enter_puk_hint" msgid="453227143861735537">"O SIM foi desativado. Insira o código PUK para continuar. Entre em contato com a operadora para obter mais detalhes."</string>
+ <string name="kg_puk_enter_puk_hint" msgid="453227143861735537">"O chip foi desativado. Insira o código PUK para continuar. Entre em contato com a operadora para obter mais detalhes."</string>
<string name="kg_puk_enter_pin_hint" msgid="7871604527429602024">"Digite o código PIN desejado"</string>
<string name="kg_enter_confirm_pin_hint" msgid="325676184762529976">"Confirme o código PIN desejado"</string>
- <string name="kg_sim_unlock_progress_dialog_message" msgid="8950398016976865762">"Desbloqueando o cartão SIM…"</string>
+ <string name="kg_sim_unlock_progress_dialog_message" msgid="8950398016976865762">"Desbloqueando o chip…"</string>
<string name="kg_password_wrong_pin_code" msgid="1139324887413846912">"Código PIN incorreto."</string>
<string name="kg_invalid_sim_pin_hint" msgid="8795159358110620001">"Digite um PIN com quatro a oito números."</string>
<string name="kg_invalid_sim_puk_hint" msgid="6025069204539532000">"O código PUK deve ter oito números."</string>
- <string name="kg_invalid_puk" msgid="3638289409676051243">"Introduza novamente o código PUK correto. Muitas tentativas malsucedidas desativarão permanentemente o SIM."</string>
+ <string name="kg_invalid_puk" msgid="3638289409676051243">"Introduza novamente o código PUK correto. Muitas tentativas malsucedidas desativarão permanentemente o chip."</string>
<string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"Os códigos PIN não coincidem"</string>
<string name="kg_login_too_many_attempts" msgid="6486842094005698475">"Muitas tentativas de padrão"</string>
<string name="kg_login_instructions" msgid="1100551261265506448">"Para desbloquear, faça login usando sua Conta do Google."</string>
@@ -1910,9 +1911,9 @@
<string name="etws_primary_default_message_test" msgid="2709597093560037455">"Teste de mensagens de emergência"</string>
<string name="notification_reply_button_accessibility" msgid="3621714652387814344">"Responder"</string>
<string name="etws_primary_default_message_others" msgid="6293148756130398971"></string>
- <string name="mmcc_authentication_reject" msgid="5767701075994754356">"SIM não autorizado para voz"</string>
- <string name="mmcc_imsi_unknown_in_hlr" msgid="5316658473301462825">"SIM não aprovisionado para voz"</string>
- <string name="mmcc_illegal_ms" msgid="807334478177362062">"SIM não autorizado para voz"</string>
+ <string name="mmcc_authentication_reject" msgid="5767701075994754356">"Chip não autorizado para voz"</string>
+ <string name="mmcc_imsi_unknown_in_hlr" msgid="5316658473301462825">"Chip não aprovisionado para voz"</string>
+ <string name="mmcc_illegal_ms" msgid="807334478177362062">"Chip não autorizado para voz"</string>
<string name="mmcc_illegal_me" msgid="1950705155760872972">"Smartphone não autorizado para voz"</string>
<string name="mmcc_authentication_reject_msim_template" msgid="1217031195834766479">"SIM <xliff:g id="SIMNUMBER">%d</xliff:g> não permitido"</string>
<string name="mmcc_imsi_unknown_in_hlr_msim_template" msgid="5636464607596778986">"SIM <xliff:g id="SIMNUMBER">%d</xliff:g> não aprovisionado"</string>
diff --git a/core/res/res/values-pt-rPT/strings.xml b/core/res/res/values-pt-rPT/strings.xml
index 631e9f3941c4..3f02828cf3f3 100644
--- a/core/res/res/values-pt-rPT/strings.xml
+++ b/core/res/res/values-pt-rPT/strings.xml
@@ -514,6 +514,7 @@
<string name="permdesc_imagesWrite" msgid="7073662756617474375">"Permite que a aplicação modifique a sua coleção de fotos."</string>
<string name="permlab_mediaLocation" msgid="8675148183726247864">"ler as localizações a partir da sua coleção de multimédia"</string>
<string name="permdesc_mediaLocation" msgid="2237023389178865130">"Permite que a aplicação leia as localizações a partir da sua coleção de multimédia."</string>
+ <string name="biometric_error_hw_unavailable" msgid="645781226537551036">"Hardware biométrico indisponível."</string>
<string name="fingerprint_acquired_partial" msgid="735082772341716043">"Impressão digital detetada. Tente novamente."</string>
<string name="fingerprint_acquired_insufficient" msgid="4596546021310923214">"Não foi possível processar a impressão digital. Tente novamente."</string>
<string name="fingerprint_acquired_imager_dirty" msgid="1087209702421076105">"O sensor de impressões digitais está sujo. Limpe-o e tente novamente."</string>
@@ -521,7 +522,7 @@
<string name="fingerprint_acquired_too_slow" msgid="59250885689661653">"Moveu o dedo demasiado lentamente. Tente novamente."</string>
<string-array name="fingerprint_acquired_vendor">
</string-array>
- <string name="fingerprint_not_recognized" msgid="2690661881608146617">"Não reconhecido"</string>
+ <string name="biometric_not_recognized" msgid="5770511773560736082">"Não reconhecido."</string>
<string name="fingerprint_authenticated" msgid="5309333983002526448">"A impressão digital foi autenticada."</string>
<string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"Hardware de impressão digital não disponível."</string>
<string name="fingerprint_error_no_space" msgid="1055819001126053318">"Não é possível armazenar a impressão digital. Remova uma impressão digital existente."</string>
diff --git a/core/res/res/values-pt/strings.xml b/core/res/res/values-pt/strings.xml
index ad68dde271ea..48302a0d9d4c 100644
--- a/core/res/res/values-pt/strings.xml
+++ b/core/res/res/values-pt/strings.xml
@@ -47,12 +47,12 @@
<string name="mismatchPin" msgid="609379054496863419">"Os PINs digitados não correspondem."</string>
<string name="invalidPin" msgid="3850018445187475377">"Digite um PIN com 4 a 8 números."</string>
<string name="invalidPuk" msgid="8761456210898036513">"Digite um PUK com oito números ou mais."</string>
- <string name="needPuk" msgid="919668385956251611">"O seu cartão SIM está bloqueado por um PUK. Digite o código PUK para desbloqueá-lo."</string>
- <string name="needPuk2" msgid="4526033371987193070">"Digite o PUK2 para desbloquear o cartão SIM."</string>
- <string name="enablePin" msgid="209412020907207950">"Falha. Ative o bloqueio do SIM/R-UIM."</string>
+ <string name="needPuk" msgid="919668385956251611">"O seu chip está bloqueado por um PUK. Digite o código PUK para desbloqueá-lo."</string>
+ <string name="needPuk2" msgid="4526033371987193070">"Digite o PUK2 para desbloquear o chip."</string>
+ <string name="enablePin" msgid="209412020907207950">"Falha. Ative o bloqueio do chip/R-UIM."</string>
<plurals name="pinpuk_attempts" formatted="false" msgid="1251012001539225582">
- <item quantity="one">Tentativas restantes: <xliff:g id="NUMBER_1">%d</xliff:g>. Caso o código correto não seja digitado, o SIM será bloqueado.</item>
- <item quantity="other">Tentativas restantes: <xliff:g id="NUMBER_1">%d</xliff:g>. Caso o código correto não seja digitado, o SIM será bloqueado.</item>
+ <item quantity="one">Tentativas restantes: <xliff:g id="NUMBER_1">%d</xliff:g>. Caso o código correto não seja digitado, o chip será bloqueado.</item>
+ <item quantity="other">Tentativas restantes: <xliff:g id="NUMBER_1">%d</xliff:g>. Caso o código correto não seja digitado, o chip será bloqueado.</item>
</plurals>
<string name="imei" msgid="2625429890869005782">"IMEI"</string>
<string name="meid" msgid="4841221237681254195">"MEID"</string>
@@ -82,7 +82,7 @@
<string name="RestrictedOnNormalTitle" msgid="3179574012752700984">"Sem serviço de voz"</string>
<string name="RestrictedOnAllVoiceTitle" msgid="8037246983606545202">"Nenhum serviço de voz nem chamada de emergência"</string>
<string name="RestrictedStateContent" msgid="6538703255570997248">"Temporariamente desativado pela sua operadora"</string>
- <string name="RestrictedStateContentMsimTemplate" msgid="673416791370248176">"Temporariamente desativado pela sua operadora para o SIM <xliff:g id="SIMNUMBER">%d</xliff:g>"</string>
+ <string name="RestrictedStateContentMsimTemplate" msgid="673416791370248176">"Temporariamente desativado pela sua operadora para o chip <xliff:g id="SIMNUMBER">%d</xliff:g>"</string>
<string name="NetworkPreferenceSwitchTitle" msgid="6982395015324165258">"Não foi possível acessar a rede móvel"</string>
<string name="NetworkPreferenceSwitchSummary" msgid="509327194863482733">"Tente alterar a rede preferencial. Toque para alterar."</string>
<string name="EmergencyCallWarningTitle" msgid="813380189532491336">"Chamadas de emergência indisponíveis"</string>
@@ -94,7 +94,7 @@
<string name="notification_channel_sms" msgid="3441746047346135073">"Mensagens SMS"</string>
<string name="notification_channel_voice_mail" msgid="3954099424160511919">"Mensagens do correio de voz"</string>
<string name="notification_channel_wfc" msgid="2130802501654254801">"Chamadas por Wi-Fi"</string>
- <string name="notification_channel_sim" msgid="4052095493875188564">"Status do SIM"</string>
+ <string name="notification_channel_sim" msgid="4052095493875188564">"Status do chip"</string>
<string name="peerTtyModeFull" msgid="6165351790010341421">"TTD modo COMPLETO solicitado"</string>
<string name="peerTtyModeHco" msgid="5728602160669216784">"TTD modo HCO solicitado"</string>
<string name="peerTtyModeVco" msgid="1742404978686538049">"TTD modo VCO solicitado"</string>
@@ -420,8 +420,8 @@
<string name="permdesc_modifyAudioSettings" msgid="3522565366806248517">"Permite que o app modifique configurações de áudio globais como volume e alto-falantes de saída."</string>
<string name="permlab_recordAudio" msgid="3876049771427466323">"gravar áudio"</string>
<string name="permdesc_recordAudio" msgid="4245930455135321433">"Este app pode gravar áudio usando o microfone a qualquer momento."</string>
- <string name="permlab_sim_communication" msgid="2935852302216852065">"enviar comandos para o SIM"</string>
- <string name="permdesc_sim_communication" msgid="5725159654279639498">"Permite que o app envie comandos ao SIM. Muito perigoso."</string>
+ <string name="permlab_sim_communication" msgid="2935852302216852065">"enviar comandos para o chip"</string>
+ <string name="permdesc_sim_communication" msgid="5725159654279639498">"Permite que o app envie comandos ao chip. Muito perigoso."</string>
<string name="permlab_camera" msgid="3616391919559751192">"tirar fotos e gravar vídeos"</string>
<string name="permdesc_camera" msgid="5392231870049240670">"Este app pode tirar fotos e gravar vídeos usando a câmera a qualquer momento."</string>
<string name="permlab_vibrate" msgid="7696427026057705834">"controlar vibração"</string>
@@ -514,6 +514,7 @@
<string name="permdesc_imagesWrite" msgid="7073662756617474375">"Permite que o app modifique sua coleção de fotos."</string>
<string name="permlab_mediaLocation" msgid="8675148183726247864">"ler locais na sua coleção de mídias"</string>
<string name="permdesc_mediaLocation" msgid="2237023389178865130">"Permite que o app leia os locais na sua coleção de mídias."</string>
+ <string name="biometric_error_hw_unavailable" msgid="645781226537551036">"Hardware biométrico indisponível"</string>
<string name="fingerprint_acquired_partial" msgid="735082772341716043">"Impressão digital parcial detectada. Tente novamente."</string>
<string name="fingerprint_acquired_insufficient" msgid="4596546021310923214">"Não foi possível processar a impressão digital. Tente novamente."</string>
<string name="fingerprint_acquired_imager_dirty" msgid="1087209702421076105">"O sensor de impressão digital está sujo. Limpe-o e tente novamente."</string>
@@ -521,7 +522,7 @@
<string name="fingerprint_acquired_too_slow" msgid="59250885689661653">"O movimento do dedo está muito lento. Tente novamente."</string>
<string-array name="fingerprint_acquired_vendor">
</string-array>
- <string name="fingerprint_not_recognized" msgid="2690661881608146617">"Não reconhecido"</string>
+ <string name="biometric_not_recognized" msgid="5770511773560736082">"Não reconhecido"</string>
<string name="fingerprint_authenticated" msgid="5309333983002526448">"Impressão digital autenticada"</string>
<string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"Hardware de impressão digital não disponível."</string>
<string name="fingerprint_error_no_space" msgid="1055819001126053318">"Não foi possível armazenar a impressão digital. Remova uma impressão digital já existente."</string>
@@ -795,14 +796,14 @@
<string name="lockscreen_password_wrong" msgid="5737815393253165301">"Tente novamente"</string>
<string name="lockscreen_storage_locked" msgid="9167551160010625200">"Desbloqueio para todos os recursos e dados"</string>
<string name="faceunlock_multiple_failures" msgid="754137583022792429">"O número máximo de tentativas de Desbloqueio por reconhecimento facial foi excedido"</string>
- <string name="lockscreen_missing_sim_message_short" msgid="5099439277819215399">"Sem cartão SIM"</string>
- <string name="lockscreen_missing_sim_message" product="tablet" msgid="151659196095791474">"Não há um cartão SIM no tablet."</string>
- <string name="lockscreen_missing_sim_message" product="tv" msgid="1943633865476989599">"Nenhum cartão SIM na TV."</string>
- <string name="lockscreen_missing_sim_message" product="default" msgid="2186920585695169078">"Não há um cartão SIM no telefone."</string>
- <string name="lockscreen_missing_sim_instructions" msgid="5372787138023272615">"Insera um cartão SIM."</string>
- <string name="lockscreen_missing_sim_instructions_long" msgid="3526573099019319472">"O cartão SIM não foi inserido ou não é possível lê-lo. Insira um cartão SIM."</string>
- <string name="lockscreen_permanent_disabled_sim_message_short" msgid="5096149665138916184">"Cartão SIM inutilizável."</string>
- <string name="lockscreen_permanent_disabled_sim_instructions" msgid="910904643433151371">"O cartão SIM foi desativado permanentemente.\nEntre em contato com seu provedor de serviços sem fio para obter outro cartão SIM."</string>
+ <string name="lockscreen_missing_sim_message_short" msgid="5099439277819215399">"Sem chip"</string>
+ <string name="lockscreen_missing_sim_message" product="tablet" msgid="151659196095791474">"Não há um chip no tablet."</string>
+ <string name="lockscreen_missing_sim_message" product="tv" msgid="1943633865476989599">"Nenhum chip na TV."</string>
+ <string name="lockscreen_missing_sim_message" product="default" msgid="2186920585695169078">"Não há um chip no telefone."</string>
+ <string name="lockscreen_missing_sim_instructions" msgid="5372787138023272615">"Insera um chip."</string>
+ <string name="lockscreen_missing_sim_instructions_long" msgid="3526573099019319472">"O chip não foi inserido ou não é possível lê-lo. Insira um chip."</string>
+ <string name="lockscreen_permanent_disabled_sim_message_short" msgid="5096149665138916184">"Chip inutilizável."</string>
+ <string name="lockscreen_permanent_disabled_sim_instructions" msgid="910904643433151371">"O chip foi desativado permanentemente.\nEntre em contato com seu provedor de serviços sem fio para obter outro chip."</string>
<string name="lockscreen_transport_prev_description" msgid="6300840251218161534">"Faixa anterior"</string>
<string name="lockscreen_transport_next_description" msgid="573285210424377338">"Próxima faixa"</string>
<string name="lockscreen_transport_pause_description" msgid="3980308465056173363">"Pausar"</string>
@@ -812,10 +813,10 @@
<string name="lockscreen_transport_ffw_description" msgid="42987149870928985">"Avançar"</string>
<string name="emergency_calls_only" msgid="6733978304386365407">"Só chamadas de emergência"</string>
<string name="lockscreen_network_locked_message" msgid="143389224986028501">"Rede bloqueada"</string>
- <string name="lockscreen_sim_puk_locked_message" msgid="7441797339976230">"O cartão SIM está bloqueado pelo PUK."</string>
+ <string name="lockscreen_sim_puk_locked_message" msgid="7441797339976230">"O chip está bloqueado pelo PUK."</string>
<string name="lockscreen_sim_puk_locked_instructions" msgid="8127916255245181063">"Consulte o Guia do usuário ou entre em contato com o Serviço de atendimento ao cliente."</string>
- <string name="lockscreen_sim_locked_message" msgid="8066660129206001039">"O cartão SIM está bloqueado."</string>
- <string name="lockscreen_sim_unlock_progress_dialog_message" msgid="595323214052881264">"Desbloqueando o cartão SIM…"</string>
+ <string name="lockscreen_sim_locked_message" msgid="8066660129206001039">"O chip está bloqueado."</string>
+ <string name="lockscreen_sim_unlock_progress_dialog_message" msgid="595323214052881264">"Desbloqueando o chip…"</string>
<string name="lockscreen_too_many_failed_attempts_dialog_message" msgid="6481623830344107222">"Você desenhou seu padrão de desbloqueio incorretamente <xliff:g id="NUMBER_0">%1$d</xliff:g> vezes. \n\nTente novamente em <xliff:g id="NUMBER_1">%2$d</xliff:g> segundos."</string>
<string name="lockscreen_too_many_failed_password_attempts_dialog_message" msgid="2725973286239344555">"Você digitou sua senha incorretamente <xliff:g id="NUMBER_0">%1$d</xliff:g> vezes. \n\nTente novamente em <xliff:g id="NUMBER_1">%2$d</xliff:g> segundos."</string>
<string name="lockscreen_too_many_failed_pin_attempts_dialog_message" msgid="6216672706545696955">"Você digitou seu PIN incorretamente <xliff:g id="NUMBER_0">%1$d</xliff:g> vezes.\n\nTente novamente em <xliff:g id="NUMBER_1">%2$d</xliff:g> segundos."</string>
@@ -866,8 +867,8 @@
<string name="keyguard_accessibility_pattern_unlock" msgid="1490840706075246612">"Desbloqueio com padrão."</string>
<string name="keyguard_accessibility_face_unlock" msgid="4817282543351718535">"Desbloqueio facial."</string>
<string name="keyguard_accessibility_pin_unlock" msgid="2469687111784035046">"Desbloqueio com PIN."</string>
- <string name="keyguard_accessibility_sim_pin_unlock" msgid="9149698847116962307">"Desbloqueio com PIN do SIM."</string>
- <string name="keyguard_accessibility_sim_puk_unlock" msgid="9106899279724723341">"Desbloqueio com PUK do SIM."</string>
+ <string name="keyguard_accessibility_sim_pin_unlock" msgid="9149698847116962307">"Desbloqueio com PIN do chip."</string>
+ <string name="keyguard_accessibility_sim_puk_unlock" msgid="9106899279724723341">"Desbloqueio com PUK do chip."</string>
<string name="keyguard_accessibility_password_unlock" msgid="7675777623912155089">"Desbloqueio com senha."</string>
<string name="keyguard_accessibility_pattern_area" msgid="7679891324509597904">"Área do padrão."</string>
<string name="keyguard_accessibility_slide_area" msgid="6736064494019979544">"Área de deslize."</string>
@@ -1277,17 +1278,17 @@
<string name="sms_short_code_remember_undo_instruction" msgid="4960944133052287484">"P/ alterar: Configurações &gt; Apps"</string>
<string name="sms_short_code_confirm_always_allow" msgid="3241181154869493368">"Sempre permitir"</string>
<string name="sms_short_code_confirm_never_allow" msgid="446992765774269673">"Nunca permitir"</string>
- <string name="sim_removed_title" msgid="6227712319223226185">"Cartão SIM removido"</string>
- <string name="sim_removed_message" msgid="2333164559970958645">"A rede móvel ficará indisponível até que você reinicie com um cartão SIM válido inserido."</string>
+ <string name="sim_removed_title" msgid="6227712319223226185">"Chip removido"</string>
+ <string name="sim_removed_message" msgid="2333164559970958645">"A rede móvel ficará indisponível até que você reinicie com um chip válido inserido."</string>
<string name="sim_done_button" msgid="827949989369963775">"Concluído"</string>
- <string name="sim_added_title" msgid="3719670512889674693">"Cartão SIM adicionado"</string>
+ <string name="sim_added_title" msgid="3719670512889674693">"Chip adicionado"</string>
<string name="sim_added_message" msgid="6599945301141050216">"Reinicie o dispositivo para acessar a rede móvel."</string>
<string name="sim_restart_button" msgid="4722407842815232347">"Reiniciar"</string>
<string name="install_carrier_app_notification_title" msgid="9056007111024059888">"Ativar serviço móvel"</string>
- <string name="install_carrier_app_notification_text" msgid="3346681446158696001">"Faça o download do app da operadora para ativar seu novo SIM"</string>
- <string name="install_carrier_app_notification_text_app_name" msgid="1196505084835248137">"Faça o download do app <xliff:g id="APP_NAME">%1$s</xliff:g> para ativar seu novo SIM"</string>
+ <string name="install_carrier_app_notification_text" msgid="3346681446158696001">"Faça o download do app da operadora para ativar seu novo chip"</string>
+ <string name="install_carrier_app_notification_text_app_name" msgid="1196505084835248137">"Faça o download do app <xliff:g id="APP_NAME">%1$s</xliff:g> para ativar seu novo chip"</string>
<string name="install_carrier_app_notification_button" msgid="3094206295081900849">"Fazer download do app"</string>
- <string name="carrier_app_notification_title" msgid="8921767385872554621">"Novo SIM inserido"</string>
+ <string name="carrier_app_notification_title" msgid="8921767385872554621">"Novo chip inserido"</string>
<string name="carrier_app_notification_text" msgid="1132487343346050225">"Toque para configurar"</string>
<string name="time_picker_dialog_title" msgid="8349362623068819295">"Definir hora"</string>
<string name="date_picker_dialog_title" msgid="5879450659453782278">"Definir data"</string>
@@ -1572,17 +1573,17 @@
<item quantity="other">Tente novamente em <xliff:g id="NUMBER">%d</xliff:g> segundos.</item>
</plurals>
<string name="kg_pattern_instructions" msgid="398978611683075868">"Desenhe seu padrão"</string>
- <string name="kg_sim_pin_instructions" msgid="2319508550934557331">"Digite o PIN do cartão SIM"</string>
+ <string name="kg_sim_pin_instructions" msgid="2319508550934557331">"Digite o PIN do chip"</string>
<string name="kg_pin_instructions" msgid="2377242233495111557">"Digite o PIN"</string>
<string name="kg_password_instructions" msgid="5753646556186936819">"Digite a senha"</string>
- <string name="kg_puk_enter_puk_hint" msgid="453227143861735537">"O SIM foi desativado. Insira o código PUK para continuar. Entre em contato com a operadora para obter mais detalhes."</string>
+ <string name="kg_puk_enter_puk_hint" msgid="453227143861735537">"O chip foi desativado. Insira o código PUK para continuar. Entre em contato com a operadora para obter mais detalhes."</string>
<string name="kg_puk_enter_pin_hint" msgid="7871604527429602024">"Digite o código PIN desejado"</string>
<string name="kg_enter_confirm_pin_hint" msgid="325676184762529976">"Confirme o código PIN desejado"</string>
- <string name="kg_sim_unlock_progress_dialog_message" msgid="8950398016976865762">"Desbloqueando o cartão SIM…"</string>
+ <string name="kg_sim_unlock_progress_dialog_message" msgid="8950398016976865762">"Desbloqueando o chip…"</string>
<string name="kg_password_wrong_pin_code" msgid="1139324887413846912">"Código PIN incorreto."</string>
<string name="kg_invalid_sim_pin_hint" msgid="8795159358110620001">"Digite um PIN com quatro a oito números."</string>
<string name="kg_invalid_sim_puk_hint" msgid="6025069204539532000">"O código PUK deve ter oito números."</string>
- <string name="kg_invalid_puk" msgid="3638289409676051243">"Introduza novamente o código PUK correto. Muitas tentativas malsucedidas desativarão permanentemente o SIM."</string>
+ <string name="kg_invalid_puk" msgid="3638289409676051243">"Introduza novamente o código PUK correto. Muitas tentativas malsucedidas desativarão permanentemente o chip."</string>
<string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"Os códigos PIN não coincidem"</string>
<string name="kg_login_too_many_attempts" msgid="6486842094005698475">"Muitas tentativas de padrão"</string>
<string name="kg_login_instructions" msgid="1100551261265506448">"Para desbloquear, faça login usando sua Conta do Google."</string>
@@ -1910,9 +1911,9 @@
<string name="etws_primary_default_message_test" msgid="2709597093560037455">"Teste de mensagens de emergência"</string>
<string name="notification_reply_button_accessibility" msgid="3621714652387814344">"Responder"</string>
<string name="etws_primary_default_message_others" msgid="6293148756130398971"></string>
- <string name="mmcc_authentication_reject" msgid="5767701075994754356">"SIM não autorizado para voz"</string>
- <string name="mmcc_imsi_unknown_in_hlr" msgid="5316658473301462825">"SIM não aprovisionado para voz"</string>
- <string name="mmcc_illegal_ms" msgid="807334478177362062">"SIM não autorizado para voz"</string>
+ <string name="mmcc_authentication_reject" msgid="5767701075994754356">"Chip não autorizado para voz"</string>
+ <string name="mmcc_imsi_unknown_in_hlr" msgid="5316658473301462825">"Chip não aprovisionado para voz"</string>
+ <string name="mmcc_illegal_ms" msgid="807334478177362062">"Chip não autorizado para voz"</string>
<string name="mmcc_illegal_me" msgid="1950705155760872972">"Smartphone não autorizado para voz"</string>
<string name="mmcc_authentication_reject_msim_template" msgid="1217031195834766479">"SIM <xliff:g id="SIMNUMBER">%d</xliff:g> não permitido"</string>
<string name="mmcc_imsi_unknown_in_hlr_msim_template" msgid="5636464607596778986">"SIM <xliff:g id="SIMNUMBER">%d</xliff:g> não aprovisionado"</string>
diff --git a/core/res/res/values-ro/strings.xml b/core/res/res/values-ro/strings.xml
index efd68ac6ef2e..1c955591ebcd 100644
--- a/core/res/res/values-ro/strings.xml
+++ b/core/res/res/values-ro/strings.xml
@@ -517,6 +517,7 @@
<string name="permdesc_imagesWrite" msgid="7073662756617474375">"Permite aplicației să vă modifice colecția de fotografii."</string>
<string name="permlab_mediaLocation" msgid="8675148183726247864">"citiți locațiile din colecția media"</string>
<string name="permdesc_mediaLocation" msgid="2237023389178865130">"Permite aplicației să citească locațiile din colecția dvs. media."</string>
+ <string name="biometric_error_hw_unavailable" msgid="645781226537551036">"Hardware biometric indisponibil"</string>
<string name="fingerprint_acquired_partial" msgid="735082772341716043">"S-a detectat parțial amprenta. Încercați din nou."</string>
<string name="fingerprint_acquired_insufficient" msgid="4596546021310923214">"Amprenta nu a putut fi procesată. Încercați din nou."</string>
<string name="fingerprint_acquired_imager_dirty" msgid="1087209702421076105">"Senzorul pentru amprente este murdar. Curățați-l și încercați din nou."</string>
@@ -524,7 +525,7 @@
<string name="fingerprint_acquired_too_slow" msgid="59250885689661653">"Ați mișcat degetul prea lent. Încercați din nou."</string>
<string-array name="fingerprint_acquired_vendor">
</string-array>
- <string name="fingerprint_not_recognized" msgid="2690661881608146617">"Nu este recunoscută"</string>
+ <string name="biometric_not_recognized" msgid="5770511773560736082">"Nu este recunoscut"</string>
<string name="fingerprint_authenticated" msgid="5309333983002526448">"Amprentă autentificată"</string>
<string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"Hardware-ul pentru amprentă nu este disponibil."</string>
<string name="fingerprint_error_no_space" msgid="1055819001126053318">"Amprenta nu poate fi stocată. Eliminați o amprentă existentă."</string>
diff --git a/core/res/res/values-ru/strings.xml b/core/res/res/values-ru/strings.xml
index 6cc870c86740..e31f161b5dd4 100644
--- a/core/res/res/values-ru/strings.xml
+++ b/core/res/res/values-ru/strings.xml
@@ -520,6 +520,7 @@
<string name="permdesc_imagesWrite" msgid="7073662756617474375">"Приложение сможет вносить изменения в вашу фотоколлекцию."</string>
<string name="permlab_mediaLocation" msgid="8675148183726247864">"доступ к геоданным в медиаколлекции"</string>
<string name="permdesc_mediaLocation" msgid="2237023389178865130">"Приложение получит доступ к геоданным в вашей медиаколлекции."</string>
+ <string name="biometric_error_hw_unavailable" msgid="645781226537551036">"Биометрическое оборудование недоступно"</string>
<string name="fingerprint_acquired_partial" msgid="735082772341716043">"Отсканирована только часть пальца. Повторите попытку."</string>
<string name="fingerprint_acquired_insufficient" msgid="4596546021310923214">"Не удалось распознать отпечаток. Повторите попытку."</string>
<string name="fingerprint_acquired_imager_dirty" msgid="1087209702421076105">"Очистите сканер и повторите попытку."</string>
@@ -527,7 +528,7 @@
<string name="fingerprint_acquired_too_slow" msgid="59250885689661653">"Вы перемещали палец слишком медленно. Повторите попытку."</string>
<string-array name="fingerprint_acquired_vendor">
</string-array>
- <string name="fingerprint_not_recognized" msgid="2690661881608146617">"Не распознано"</string>
+ <string name="biometric_not_recognized" msgid="5770511773560736082">"Не распознано"</string>
<string name="fingerprint_authenticated" msgid="5309333983002526448">"Отпечаток пальца проверен"</string>
<string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"Сканер недоступен"</string>
<string name="fingerprint_error_no_space" msgid="1055819001126053318">"Чтобы сохранить новый отпечаток, удалите существующий."</string>
diff --git a/core/res/res/values-si/strings.xml b/core/res/res/values-si/strings.xml
index c263589468f8..8b89a977faac 100644
--- a/core/res/res/values-si/strings.xml
+++ b/core/res/res/values-si/strings.xml
@@ -514,6 +514,8 @@
<string name="permdesc_imagesWrite" msgid="7073662756617474375">"ඔබගේ ඡායාරූප එකතුව වෙනස් කිරීමට යෙදුමට ඉඩ දෙයි."</string>
<string name="permlab_mediaLocation" msgid="8675148183726247864">"ඔබගේ මාධ්‍ය එකතුවෙන් ස්ථාන කියවන්න"</string>
<string name="permdesc_mediaLocation" msgid="2237023389178865130">"ඔබගේ මාධ්‍ය එකතුවෙන් ස්ථාන කියවීමට යෙදුමට ඉඩ දෙයි."</string>
+ <!-- no translation found for biometric_error_hw_unavailable (645781226537551036) -->
+ <skip />
<string name="fingerprint_acquired_partial" msgid="735082772341716043">"ඇඟිලි සලකුණ අඩ වශයෙන් අනාවරණය කර ගැනිණි. කරුණාකර නැවත උත්සාහ කරන්න."</string>
<string name="fingerprint_acquired_insufficient" msgid="4596546021310923214">"ඇඟිලි සලකුණ පිරිසැකසීමට නොහැකි විය. කරුණාකර නැවත උත්සාහ කරන්න."</string>
<string name="fingerprint_acquired_imager_dirty" msgid="1087209702421076105">"ඇඟිලි සලකුණු සංවේදකය අපිරිසිදුයි. කරුණාකර පිරිසිදු කර නැවත උත්සාහ කරන්න."</string>
@@ -521,7 +523,8 @@
<string name="fingerprint_acquired_too_slow" msgid="59250885689661653">"ඇඟිල්ල වඩා සෙමෙන් ගෙන යන ලදි. කරුණාකර නැවත උත්සාහ කරන්න."</string>
<string-array name="fingerprint_acquired_vendor">
</string-array>
- <string name="fingerprint_not_recognized" msgid="2690661881608146617">"අඳුනාගත නොහැක"</string>
+ <!-- no translation found for biometric_not_recognized (5770511773560736082) -->
+ <skip />
<string name="fingerprint_authenticated" msgid="5309333983002526448">"ඇඟිලි සලකුණ සත්‍යාපනය කරන ලදී"</string>
<string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"ඇඟිලි සලකුණු දෘඪාංගය ලද නොහැකිය."</string>
<string name="fingerprint_error_no_space" msgid="1055819001126053318">"ඇඟිලි සලකුණ ගබඩා කළ නොහැක. දැනට පවතින ඇඟිලි සලකුණක් ඉවත් කරන්න."</string>
diff --git a/core/res/res/values-sk/strings.xml b/core/res/res/values-sk/strings.xml
index f3569c984c4f..31097024b5e6 100644
--- a/core/res/res/values-sk/strings.xml
+++ b/core/res/res/values-sk/strings.xml
@@ -520,6 +520,7 @@
<string name="permdesc_imagesWrite" msgid="7073662756617474375">"Umožňuje aplikácii upravovať zbierku fotiek."</string>
<string name="permlab_mediaLocation" msgid="8675148183726247864">"čítať polohy zo zbierky médií"</string>
<string name="permdesc_mediaLocation" msgid="2237023389178865130">"Umožňuje aplikácii čítať polohy zo zbierky médií."</string>
+ <string name="biometric_error_hw_unavailable" msgid="645781226537551036">"Biometrický hardvér nie je k dispozícii"</string>
<string name="fingerprint_acquired_partial" msgid="735082772341716043">"Podarilo sa rozpoznať iba časť odtlačku prsta. Skúste to znova."</string>
<string name="fingerprint_acquired_insufficient" msgid="4596546021310923214">"Odtlačok prsta sa nepodarilo spracovať. Skúste to znova."</string>
<string name="fingerprint_acquired_imager_dirty" msgid="1087209702421076105">"Snímač odtlačkov je špinavý. Vyčistite ho a skúste to znova."</string>
@@ -527,7 +528,7 @@
<string name="fingerprint_acquired_too_slow" msgid="59250885689661653">"Pohli ste prstom príliš pomaly. Skúste to znova."</string>
<string-array name="fingerprint_acquired_vendor">
</string-array>
- <string name="fingerprint_not_recognized" msgid="2690661881608146617">"Nebol rozpoznaný"</string>
+ <string name="biometric_not_recognized" msgid="5770511773560736082">"Nerozpoznané"</string>
<string name="fingerprint_authenticated" msgid="5309333983002526448">"Odtlačok bol overený"</string>
<string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"Hardvér na snímanie odtlačku prsta nie je k dispozícii"</string>
<string name="fingerprint_error_no_space" msgid="1055819001126053318">"Odtlačok prsta nie je možné uložiť. Odstráňte existujúci odtlačok."</string>
diff --git a/core/res/res/values-sl/strings.xml b/core/res/res/values-sl/strings.xml
index 0f9d038332ba..4575d00e6497 100644
--- a/core/res/res/values-sl/strings.xml
+++ b/core/res/res/values-sl/strings.xml
@@ -520,6 +520,7 @@
<string name="permdesc_imagesWrite" msgid="7073662756617474375">"Aplikaciji omogoča spreminjanje zbirke fotografij."</string>
<string name="permlab_mediaLocation" msgid="8675148183726247864">"branje lokacij v predstavnostni zbirki"</string>
<string name="permdesc_mediaLocation" msgid="2237023389178865130">"Aplikaciji omogoča branje lokacij v predstavnostni zbirki."</string>
+ <string name="biometric_error_hw_unavailable" msgid="645781226537551036">"Strojna oprema za biometrične podatke ni na voljo"</string>
<string name="fingerprint_acquired_partial" msgid="735082772341716043">"Zaznan delni prstni odtis. Poskusite znova."</string>
<string name="fingerprint_acquired_insufficient" msgid="4596546021310923214">"Prstnega odtisa ni bilo mogoče obdelati. Poskusite znova."</string>
<string name="fingerprint_acquired_imager_dirty" msgid="1087209702421076105">"Tipalo prstnih odtisov je umazano. Očistite ga in poskusite znova."</string>
@@ -527,7 +528,7 @@
<string name="fingerprint_acquired_too_slow" msgid="59250885689661653">"Prepočasen premik prsta. Poskusite znova."</string>
<string-array name="fingerprint_acquired_vendor">
</string-array>
- <string name="fingerprint_not_recognized" msgid="2690661881608146617">"Ni prepoznano"</string>
+ <string name="biometric_not_recognized" msgid="5770511773560736082">"Ni prepoznano"</string>
<string name="fingerprint_authenticated" msgid="5309333983002526448">"Pristnost prstnega odtisa je preverjena"</string>
<string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"Strojna oprema za prstne odtise ni na voljo."</string>
<string name="fingerprint_error_no_space" msgid="1055819001126053318">"Prstnega odtisa ni mogoče shraniti. Odstranite obstoječi prstni odtis."</string>
diff --git a/core/res/res/values-sq/strings.xml b/core/res/res/values-sq/strings.xml
index 17ec70d9c06e..11494218c9bd 100644
--- a/core/res/res/values-sq/strings.xml
+++ b/core/res/res/values-sq/strings.xml
@@ -284,7 +284,7 @@
<string name="permgrouprequest_sms" msgid="7168124215838204719">"Të lejohet që &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; të dërgojë dhe të shikojë mesazhet SMS?"</string>
<string name="permgrouplab_storage" msgid="1971118770546336966">"Hapësira e ruajtjes"</string>
<string name="permgroupdesc_storage" msgid="637758554581589203">"qasjen te fotografitë, përmbajtjet audio-vizuale dhe skedarët në pajisje"</string>
- <string name="permgrouprequest_storage" msgid="7885942926944299560">"Të lejohet që &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; të ketë qasje te fotografitë, media dhe skedarët në pajisjen tënde?"</string>
+ <string name="permgrouprequest_storage" msgid="7885942926944299560">"Të lejohet apl. &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; që të ketë qasje te fotografitë, media dhe skedarët në pajisjen tënde?"</string>
<string name="permgrouplab_microphone" msgid="171539900250043464">"Mikrofoni"</string>
<string name="permgroupdesc_microphone" msgid="4988812113943554584">"regjistro audio"</string>
<string name="permgrouprequest_microphone" msgid="9167492350681916038">"Të lejohet që &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; të regjistrojë audio?"</string>
@@ -514,6 +514,7 @@
<string name="permdesc_imagesWrite" msgid="7073662756617474375">"Lejon aplikacionin të modifikojë koleksionin tënd të fotografive."</string>
<string name="permlab_mediaLocation" msgid="8675148183726247864">"lexo vendndodhjet nga koleksioni yt i medias"</string>
<string name="permdesc_mediaLocation" msgid="2237023389178865130">"Lejon aplikacionin të lexojë vendndodhjet nga koleksioni yt i medias."</string>
+ <string name="biometric_error_hw_unavailable" msgid="645781226537551036">"Nuk ofrohet harduer biometrik"</string>
<string name="fingerprint_acquired_partial" msgid="735082772341716043">"U zbulua një gjurmë gishti e pjesshme. Provo përsëri."</string>
<string name="fingerprint_acquired_insufficient" msgid="4596546021310923214">"Gjurma e gishtit nuk mund të përpunohej. Provo përsëri."</string>
<string name="fingerprint_acquired_imager_dirty" msgid="1087209702421076105">"Sensori i gjurmës së gishtit nuk është i pastër. Pastroje dhe provo përsëri."</string>
@@ -521,7 +522,7 @@
<string name="fingerprint_acquired_too_slow" msgid="59250885689661653">"Gishti lëvizi shumë ngadalë. Provo përsëri."</string>
<string-array name="fingerprint_acquired_vendor">
</string-array>
- <string name="fingerprint_not_recognized" msgid="2690661881608146617">"Nuk njihet"</string>
+ <string name="biometric_not_recognized" msgid="5770511773560736082">"Nuk njihet"</string>
<string name="fingerprint_authenticated" msgid="5309333983002526448">"Gjurma e gishtit u vërtetua"</string>
<string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"Hardueri i gjurmës së gishtit nuk mundësohet."</string>
<string name="fingerprint_error_no_space" msgid="1055819001126053318">"Gjurma e gishtit nuk mund të ruhet. Hiq një gjurmë gishti ekzistuese."</string>
diff --git a/core/res/res/values-sr/strings.xml b/core/res/res/values-sr/strings.xml
index 517815dfdc22..753653195f32 100644
--- a/core/res/res/values-sr/strings.xml
+++ b/core/res/res/values-sr/strings.xml
@@ -517,6 +517,7 @@
<string name="permdesc_imagesWrite" msgid="7073662756617474375">"Дозвољава апликацији да мења колекцију слика."</string>
<string name="permlab_mediaLocation" msgid="8675148183726247864">"читање локација из медијске колекције"</string>
<string name="permdesc_mediaLocation" msgid="2237023389178865130">"Дозвољава апликацији да чита локације из медијске колекције."</string>
+ <string name="biometric_error_hw_unavailable" msgid="645781226537551036">"Биометријски хардвер није доступан"</string>
<string name="fingerprint_acquired_partial" msgid="735082772341716043">"Откривен је делимични отисак прста. Пробајте поново."</string>
<string name="fingerprint_acquired_insufficient" msgid="4596546021310923214">"Није успела обрада отиска прста. Пробајте поново."</string>
<string name="fingerprint_acquired_imager_dirty" msgid="1087209702421076105">"Сензор за отиске прстију је прљав. Очистите га и покушајте поново."</string>
@@ -524,7 +525,7 @@
<string name="fingerprint_acquired_too_slow" msgid="59250885689661653">"Превише споро сте померили прст. Пробајте поново."</string>
<string-array name="fingerprint_acquired_vendor">
</string-array>
- <string name="fingerprint_not_recognized" msgid="2690661881608146617">"Није препознат"</string>
+ <string name="biometric_not_recognized" msgid="5770511773560736082">"Није препознато"</string>
<string name="fingerprint_authenticated" msgid="5309333983002526448">"Отисак прста је потврђен"</string>
<string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"Хардвер за отиске прстију није доступан."</string>
<string name="fingerprint_error_no_space" msgid="1055819001126053318">"Није могуће сачувати отисак прста. Уклоните неки од постојећих отисака прстију."</string>
diff --git a/core/res/res/values-sv/strings.xml b/core/res/res/values-sv/strings.xml
index 835f198214d0..31bb34919c1f 100644
--- a/core/res/res/values-sv/strings.xml
+++ b/core/res/res/values-sv/strings.xml
@@ -514,6 +514,7 @@
<string name="permdesc_imagesWrite" msgid="7073662756617474375">"Tillåter att appen gör ändringar i din fotosamling."</string>
<string name="permlab_mediaLocation" msgid="8675148183726247864">"läsa av platser i din mediesamling"</string>
<string name="permdesc_mediaLocation" msgid="2237023389178865130">"Tillåter att appen läser av platser i din mediesamling."</string>
+ <string name="biometric_error_hw_unavailable" msgid="645781226537551036">"Biometrisk maskinvara är inte tillgänglig"</string>
<string name="fingerprint_acquired_partial" msgid="735082772341716043">"Ofullständigt fingeravtryck. Försök igen."</string>
<string name="fingerprint_acquired_insufficient" msgid="4596546021310923214">"Det gick inte att bearbeta fingeravtrycket. Försök igen."</string>
<string name="fingerprint_acquired_imager_dirty" msgid="1087209702421076105">"Fingeravtryckssensorn är smutsig. Rengör den och försök igen."</string>
@@ -521,7 +522,7 @@
<string name="fingerprint_acquired_too_slow" msgid="59250885689661653">"Du rörde fingret för långsamt. Försök igen."</string>
<string-array name="fingerprint_acquired_vendor">
</string-array>
- <string name="fingerprint_not_recognized" msgid="2690661881608146617">"Identifierades inte"</string>
+ <string name="biometric_not_recognized" msgid="5770511773560736082">"Identifierades inte"</string>
<string name="fingerprint_authenticated" msgid="5309333983002526448">"Fingeravtrycket har autentiserats"</string>
<string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"Det finns ingen maskinvara för fingeravtryck."</string>
<string name="fingerprint_error_no_space" msgid="1055819001126053318">"Fingeravtrycket kan inte lagras. Ta bort ett befintligt fingeravtryck."</string>
diff --git a/core/res/res/values-sw/strings.xml b/core/res/res/values-sw/strings.xml
index c846f08440c2..3d2622469cbf 100644
--- a/core/res/res/values-sw/strings.xml
+++ b/core/res/res/values-sw/strings.xml
@@ -282,7 +282,7 @@
<string name="permgrouprequest_sms" msgid="7168124215838204719">"Ungependa kuiruhusu &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; itume na ione ujumbe wa SMS?"</string>
<string name="permgrouplab_storage" msgid="1971118770546336966">"Hifadhi"</string>
<string name="permgroupdesc_storage" msgid="637758554581589203">"ifikie picha, maudhui na faili kwenye kifaa chako"</string>
- <string name="permgrouprequest_storage" msgid="7885942926944299560">"Ungependa kuiruhusu &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ifikie picha, maudhui na faili kwenye kifaa chako?"</string>
+ <string name="permgrouprequest_storage" msgid="7885942926944299560">"Ungependa &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ifikie picha, maudhui na faili kwenye kifaa chako?"</string>
<string name="permgrouplab_microphone" msgid="171539900250043464">"Kipokea sauti"</string>
<string name="permgroupdesc_microphone" msgid="4988812113943554584">"irekodi sauti"</string>
<string name="permgrouprequest_microphone" msgid="9167492350681916038">"Ungependa kuiruhusu &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; irekodi sauti?"</string>
@@ -512,6 +512,7 @@
<string name="permdesc_imagesWrite" msgid="7073662756617474375">"Inaruhusu programu kubadilisha mkusanyiko wa picha zako."</string>
<string name="permlab_mediaLocation" msgid="8675148183726247864">"kusoma maeneo kwenye mkusanyiko wa vipengee vyako"</string>
<string name="permdesc_mediaLocation" msgid="2237023389178865130">"Inaruhusu programu kusoma maeneo kwenye mkusanyiko wa vipengee vyako."</string>
+ <string name="biometric_error_hw_unavailable" msgid="645781226537551036">"Maunzi ya bayometriki hayapatikani"</string>
<string name="fingerprint_acquired_partial" msgid="735082772341716043">"Kitambuzi kimegundua sehemu ya kitambulisho. Tafadhali jaribu tena."</string>
<string name="fingerprint_acquired_insufficient" msgid="4596546021310923214">"Haikuweza kuchakata kitambulisho. Tafadhali jaribu tena."</string>
<string name="fingerprint_acquired_imager_dirty" msgid="1087209702421076105">"Kitambuzi alama ya kidole ni kichafu. Tafadhali kisafishe na ujaribu tena."</string>
@@ -519,7 +520,7 @@
<string name="fingerprint_acquired_too_slow" msgid="59250885689661653">"Kidole kilisogezwa polepole zaidi. Tafadhali jaribu tena."</string>
<string-array name="fingerprint_acquired_vendor">
</string-array>
- <string name="fingerprint_not_recognized" msgid="2690661881608146617">"Haitambuliwi"</string>
+ <string name="biometric_not_recognized" msgid="5770511773560736082">"Hayatambuliki"</string>
<string name="fingerprint_authenticated" msgid="5309333983002526448">"Imethibitisha alama ya kidole"</string>
<string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"Maunzi ya kitambulisho hayapatikani."</string>
<string name="fingerprint_error_no_space" msgid="1055819001126053318">"Kitambulisho hakiwezi kuhifadhiwa. Tafadhali ondoa kitambulisho kilichopo."</string>
diff --git a/core/res/res/values-ta/strings.xml b/core/res/res/values-ta/strings.xml
index ba58742c940c..b175f75acea9 100644
--- a/core/res/res/values-ta/strings.xml
+++ b/core/res/res/values-ta/strings.xml
@@ -514,6 +514,8 @@
<string name="permdesc_imagesWrite" msgid="7073662756617474375">"உங்களின் படத் தொகுப்பை மாற்ற ஆப்ஸை அனுமதிக்கும்."</string>
<string name="permlab_mediaLocation" msgid="8675148183726247864">"மீடியா தொகுப்பிலிருந்து இடங்களை அறிதல்"</string>
<string name="permdesc_mediaLocation" msgid="2237023389178865130">"உங்களின் மீடியா தொகுப்பிலிருந்து இடங்களை அறிந்துகொள்ள ஆப்ஸை அனுமதிக்கும்."</string>
+ <!-- no translation found for biometric_error_hw_unavailable (645781226537551036) -->
+ <skip />
<string name="fingerprint_acquired_partial" msgid="735082772341716043">"கைரேகையை ஓரளவுதான் கண்டறிய முடிந்தது. மீண்டும் முயலவும்."</string>
<string name="fingerprint_acquired_insufficient" msgid="4596546021310923214">"கைரேகையைச் செயலாக்க முடியவில்லை. மீண்டும் முயலவும்."</string>
<string name="fingerprint_acquired_imager_dirty" msgid="1087209702421076105">"கைரேகை உணர்வியில் தூசி உள்ளது. சுத்தம் செய்து, முயலவும்."</string>
@@ -521,7 +523,8 @@
<string name="fingerprint_acquired_too_slow" msgid="59250885689661653">"விரலை மிகவும் மெதுவாக நகர்த்திவிட்டீர்கள். மீண்டும் முயற்சிக்கவும்."</string>
<string-array name="fingerprint_acquired_vendor">
</string-array>
- <string name="fingerprint_not_recognized" msgid="2690661881608146617">"அறியப்படவில்லை"</string>
+ <!-- no translation found for biometric_not_recognized (5770511773560736082) -->
+ <skip />
<string name="fingerprint_authenticated" msgid="5309333983002526448">"கைரேகை அங்கீகரிக்கப்பட்டது"</string>
<string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"கைரேகை வன்பொருள் இல்லை."</string>
<string name="fingerprint_error_no_space" msgid="1055819001126053318">"கைரேகையைச் சேமிக்க முடியவில்லை. ஏற்கனவே உள்ள கைரேகையை அகற்றவும்."</string>
diff --git a/core/res/res/values-te/strings.xml b/core/res/res/values-te/strings.xml
index b0d7a4dcb637..2027d3333dcf 100644
--- a/core/res/res/values-te/strings.xml
+++ b/core/res/res/values-te/strings.xml
@@ -514,6 +514,7 @@
<string name="permdesc_imagesWrite" msgid="7073662756617474375">"మీ ఫోటో సేకరణను సవరించడానికి యాప్‌ను అనుమతిస్తుంది."</string>
<string name="permlab_mediaLocation" msgid="8675148183726247864">"మీ మీడియా సేకరణ నుండి స్థానాలను చదవండి"</string>
<string name="permdesc_mediaLocation" msgid="2237023389178865130">"మీ మీడియా సేకరణ నుండి స్థానాలను చదవడానికి యాప్‌ను అనుమతిస్తుంది."</string>
+ <string name="biometric_error_hw_unavailable" msgid="645781226537551036">"బయోమెట్రిక్ హార్డ్‌వేర్‌ అందుబాటులో లేదు"</string>
<string name="fingerprint_acquired_partial" msgid="735082772341716043">"పాక్షిక వేలిముద్ర గుర్తించబడింది. దయచేసి మళ్లీ ప్రయత్నించండి."</string>
<string name="fingerprint_acquired_insufficient" msgid="4596546021310923214">"వేలిముద్రను ప్రాసెస్ చేయడం సాధ్యపడలేదు. దయచేసి మళ్లీ ప్రయత్నించండి."</string>
<string name="fingerprint_acquired_imager_dirty" msgid="1087209702421076105">"వేలిముద్ర సెన్సార్ మురికిగా ఉంది. దయచేసి శుభ్రపరిచి, మళ్లీ ప్రయత్నించండి."</string>
@@ -521,7 +522,7 @@
<string name="fingerprint_acquired_too_slow" msgid="59250885689661653">"వేలిని చాలా నెమ్మదిగా కదిలించారు. దయచేసి మళ్లీ ప్రయత్నించండి."</string>
<string-array name="fingerprint_acquired_vendor">
</string-array>
- <string name="fingerprint_not_recognized" msgid="2690661881608146617">"గుర్తించలేదు"</string>
+ <string name="biometric_not_recognized" msgid="5770511773560736082">"గుర్తించలేదు"</string>
<string name="fingerprint_authenticated" msgid="5309333983002526448">"వేలిముద్ర ప్రమాణీకరించబడింది"</string>
<string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"వేలిముద్ర హార్డ్‌వేర్ అందుబాటులో లేదు."</string>
<string name="fingerprint_error_no_space" msgid="1055819001126053318">"వేలిముద్రను నిల్వ చేయడం సాధ్యపడదు. దయచేసి ఇప్పటికే ఉన్న వేలిముద్రను తీసివేయండి."</string>
diff --git a/core/res/res/values-th/strings.xml b/core/res/res/values-th/strings.xml
index 07107cb02e36..84fd018cf11e 100644
--- a/core/res/res/values-th/strings.xml
+++ b/core/res/res/values-th/strings.xml
@@ -514,6 +514,7 @@
<string name="permdesc_imagesWrite" msgid="7073662756617474375">"อนุญาตให้แอปแก้ไขคอลเล็กชันรูปภาพของคุณ"</string>
<string name="permlab_mediaLocation" msgid="8675148183726247864">"อ่านตำแหน่งจากคอลเล็กชันสื่อของคุณ"</string>
<string name="permdesc_mediaLocation" msgid="2237023389178865130">"อนุญาตให้แอปอ่านตำแหน่งจากคอลเล็กชันสื่อของคุณ"</string>
+ <string name="biometric_error_hw_unavailable" msgid="645781226537551036">"ฮาร์ดแวร์ไบโอเมตริกไม่พร้อมใช้งาน"</string>
<string name="fingerprint_acquired_partial" msgid="735082772341716043">"ตรวจพบลายนิ้วมือเพียงบางส่วน โปรดลองอีกครั้ง"</string>
<string name="fingerprint_acquired_insufficient" msgid="4596546021310923214">"ไม่สามารถประมวลผลลายนิ้วมือได้ โปรดลองอีกครั้ง"</string>
<string name="fingerprint_acquired_imager_dirty" msgid="1087209702421076105">"เซ็นเซอร์ลายนิ้วมือไม่สะอาด โปรดทำความสะอาดและลองอีกครั้ง"</string>
@@ -521,7 +522,7 @@
<string name="fingerprint_acquired_too_slow" msgid="59250885689661653">"นิ้วเคลื่อนที่ช้าเกินไป โปรดลองอีกครั้ง"</string>
<string-array name="fingerprint_acquired_vendor">
</string-array>
- <string name="fingerprint_not_recognized" msgid="2690661881608146617">"ไม่รู้จัก"</string>
+ <string name="biometric_not_recognized" msgid="5770511773560736082">"ไม่รู้จัก"</string>
<string name="fingerprint_authenticated" msgid="5309333983002526448">"ตรวจสอบสิทธิ์ลายนิ้วมือแล้ว"</string>
<string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"ฮาร์ดแวร์ลายนิ้วมือไม่พร้อมใช้งาน"</string>
<string name="fingerprint_error_no_space" msgid="1055819001126053318">"ไม่สามารถเก็บลายนิ้วมือได้ โปรดนำลายนิ้วมือที่มีอยู่ออก"</string>
@@ -1509,7 +1510,7 @@
<string name="data_usage_mobile_limit_snoozed_title" msgid="3171402244827034372">"เกินปริมาณเน็ตมือถือที่กำหนดไว้"</string>
<string name="data_usage_wifi_limit_snoozed_title" msgid="3547771791046344188">"เกินขีดจำกัดของข้อมูล Wi-Fi"</string>
<string name="data_usage_limit_snoozed_body" msgid="1671222777207603301">"คุณใช้อินเทอร์เน็ตเกินไป <xliff:g id="SIZE">%s</xliff:g> จากปริมาณที่กำหนดไว้"</string>
- <string name="data_usage_restricted_title" msgid="5965157361036321914">"จำกัดข้อมูลแบ็กกราวด์"</string>
+ <string name="data_usage_restricted_title" msgid="5965157361036321914">"จำกัดอินเทอร์เน็ตที่ใช้งานอยู่เบื้องหลัง"</string>
<string name="data_usage_restricted_body" msgid="469866376337242726">"แตะเพื่อนำข้อจำกัดออก"</string>
<string name="data_usage_rapid_title" msgid="1809795402975261331">"ปริมาณการใช้เน็ตมือถือสูง"</string>
<string name="data_usage_rapid_body" msgid="6897825788682442715">"แอปของคุณใช้อินเทอร์เน็ตมากกว่าปกติ"</string>
diff --git a/core/res/res/values-tl/strings.xml b/core/res/res/values-tl/strings.xml
index c4b14f7f19ec..49318cfd9c77 100644
--- a/core/res/res/values-tl/strings.xml
+++ b/core/res/res/values-tl/strings.xml
@@ -514,6 +514,7 @@
<string name="permdesc_imagesWrite" msgid="7073662756617474375">"Pinapayagan ang app na baguhin ang iyong koleksyon ng larawan."</string>
<string name="permlab_mediaLocation" msgid="8675148183726247864">"basahin ang mga lokasyon mula sa iyong koleksyon ng media"</string>
<string name="permdesc_mediaLocation" msgid="2237023389178865130">"Pinapayagan ang app na basahin ang mga lokasyon mula sa iyong koleksyon ng media."</string>
+ <string name="biometric_error_hw_unavailable" msgid="645781226537551036">"Walang biometric hardware"</string>
<string name="fingerprint_acquired_partial" msgid="735082772341716043">"Hindi buo ang natukoy na fingerprint. Pakisubukang muli."</string>
<string name="fingerprint_acquired_insufficient" msgid="4596546021310923214">"Hindi maproseso ang fingerprint. Pakisubukang muli."</string>
<string name="fingerprint_acquired_imager_dirty" msgid="1087209702421076105">"Marumi ang sensor ng fingerprint. Pakilinis at subukang muli."</string>
@@ -521,7 +522,7 @@
<string name="fingerprint_acquired_too_slow" msgid="59250885689661653">"Masyadong mabagal ang paggalaw ng daliri. Pakisubukang muli."</string>
<string-array name="fingerprint_acquired_vendor">
</string-array>
- <string name="fingerprint_not_recognized" msgid="2690661881608146617">"Hindi nakilala"</string>
+ <string name="biometric_not_recognized" msgid="5770511773560736082">"Hindi nakilala"</string>
<string name="fingerprint_authenticated" msgid="5309333983002526448">"Na-authenticate ang fingerprint"</string>
<string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"Hindi available ang hardware na ginagamitan ng fingerprint."</string>
<string name="fingerprint_error_no_space" msgid="1055819001126053318">"Hindi maiimbak ang fingerprint. Mangyaring mag-alis ng umiiral nang fingerprint."</string>
diff --git a/core/res/res/values-tr/strings.xml b/core/res/res/values-tr/strings.xml
index 67991e13a8e1..c6d18ecad7cd 100644
--- a/core/res/res/values-tr/strings.xml
+++ b/core/res/res/values-tr/strings.xml
@@ -514,6 +514,7 @@
<string name="permdesc_imagesWrite" msgid="7073662756617474375">"Uygulamanın fotoğraf koleksiyonunuzu değiştirmesine izin verir."</string>
<string name="permlab_mediaLocation" msgid="8675148183726247864">"medya koleksiyonunuzdaki konumları okuma"</string>
<string name="permdesc_mediaLocation" msgid="2237023389178865130">"Uygulamanın medya koleksiyonunuzdaki konumları okumasına izin verir."</string>
+ <string name="biometric_error_hw_unavailable" msgid="645781226537551036">"Biyometrik donanım kullanılamıyor"</string>
<string name="fingerprint_acquired_partial" msgid="735082772341716043">"Parmak izinin tümü algılanamadı. Lütfen tekrar deneyin."</string>
<string name="fingerprint_acquired_insufficient" msgid="4596546021310923214">"Parmak izi işlenemedi. Lütfen tekrar deneyin."</string>
<string name="fingerprint_acquired_imager_dirty" msgid="1087209702421076105">"Parmak izi sensörü kirli. Lütfen temizleyin ve tekrar deneyin."</string>
@@ -521,7 +522,7 @@
<string name="fingerprint_acquired_too_slow" msgid="59250885689661653">"Parmak hareketi çok yavaştı. Lütfen tekrar deneyin."</string>
<string-array name="fingerprint_acquired_vendor">
</string-array>
- <string name="fingerprint_not_recognized" msgid="2690661881608146617">"Tanınmadı"</string>
+ <string name="biometric_not_recognized" msgid="5770511773560736082">"Tanınmadı"</string>
<string name="fingerprint_authenticated" msgid="5309333983002526448">"Parmak izi kimlik doğrulaması yapıldı"</string>
<string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"Parmak izi donanımı kullanılamıyor."</string>
<string name="fingerprint_error_no_space" msgid="1055819001126053318">"Parmak izi depolanamıyor. Lütfen mevcut parmak izlerinden birini kaldırın."</string>
diff --git a/core/res/res/values-uk/strings.xml b/core/res/res/values-uk/strings.xml
index 45b8dd4a37f2..6e6dd9a2d163 100644
--- a/core/res/res/values-uk/strings.xml
+++ b/core/res/res/values-uk/strings.xml
@@ -520,6 +520,7 @@
<string name="permdesc_imagesWrite" msgid="7073662756617474375">"Додаток зможе змінювати вашу колекцію фотографій."</string>
<string name="permlab_mediaLocation" msgid="8675148183726247864">"розпізнавати геодані з колекції медіа-вмісту"</string>
<string name="permdesc_mediaLocation" msgid="2237023389178865130">"Додаток зможе розпізнавати геодані з вашої колекції медіа-вмісту."</string>
+ <string name="biometric_error_hw_unavailable" msgid="645781226537551036">"Біометричне апаратне забезпечення недоступне"</string>
<string name="fingerprint_acquired_partial" msgid="735082772341716043">"Відбиток розпізнано частково. Повторіть спробу."</string>
<string name="fingerprint_acquired_insufficient" msgid="4596546021310923214">"Не вдалось обробити відбиток. Повторіть спробу."</string>
<string name="fingerprint_acquired_imager_dirty" msgid="1087209702421076105">"Датчик відбитків забруднився. Очистьте його та повторіть спробу."</string>
@@ -527,7 +528,7 @@
<string name="fingerprint_acquired_too_slow" msgid="59250885689661653">"Ви провели пальцем надто повільно. Повторіть спробу."</string>
<string-array name="fingerprint_acquired_vendor">
</string-array>
- <string name="fingerprint_not_recognized" msgid="2690661881608146617">"Не розпізнано"</string>
+ <string name="biometric_not_recognized" msgid="5770511773560736082">"Не розпізнано"</string>
<string name="fingerprint_authenticated" msgid="5309333983002526448">"Відбиток автентифіковано"</string>
<string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"Апаратне забезпечення для сканування відбитка недоступне."</string>
<string name="fingerprint_error_no_space" msgid="1055819001126053318">"Не вдалося зберегти відбиток. Видаліть наявний відбиток."</string>
diff --git a/core/res/res/values-ur/strings.xml b/core/res/res/values-ur/strings.xml
index fffad9bec9c8..2a2ca621eb9e 100644
--- a/core/res/res/values-ur/strings.xml
+++ b/core/res/res/values-ur/strings.xml
@@ -514,6 +514,7 @@
<string name="permdesc_imagesWrite" msgid="7073662756617474375">"ایپ کو آپ کی تصویر کے مجموعے میں ترمیم کی اجازت دیتا ہے۔"</string>
<string name="permlab_mediaLocation" msgid="8675148183726247864">"اپنی میڈيا کے مجموعے سے مقامات پڑھیں"</string>
<string name="permdesc_mediaLocation" msgid="2237023389178865130">"ایپ کو آپ کی میڈيا کے مجموعے سے مقامات پڑھنے کی اجازت دیتا ہے۔"</string>
+ <string name="biometric_error_hw_unavailable" msgid="645781226537551036">"بایومیٹرک ہارڈ ویئر دستیاب نہیں ہے"</string>
<string name="fingerprint_acquired_partial" msgid="735082772341716043">"جزوی فنگر پرنٹ کی شناخت ہوئی۔ براہ کرم دوبارہ کوشش کریں۔"</string>
<string name="fingerprint_acquired_insufficient" msgid="4596546021310923214">"فنگر پرنٹ پر کارروائی نہیں کی جا سکی۔ براہ کرم دوبارہ کوشش کریں۔"</string>
<string name="fingerprint_acquired_imager_dirty" msgid="1087209702421076105">"فنگر پرنٹ سینسر گندا ہے۔ براہ کرم صاف کریں اور دوبارہ کوشش کریں۔"</string>
@@ -521,7 +522,7 @@
<string name="fingerprint_acquired_too_slow" msgid="59250885689661653">"انگلی کو بہت آہستہ ہٹایا گیا۔ براہ کرم دوبارہ کوشش کریں۔"</string>
<string-array name="fingerprint_acquired_vendor">
</string-array>
- <string name="fingerprint_not_recognized" msgid="2690661881608146617">"تسلیم شدہ نہیں ہے"</string>
+ <string name="biometric_not_recognized" msgid="5770511773560736082">"تسلیم شدہ نہیں ہے"</string>
<string name="fingerprint_authenticated" msgid="5309333983002526448">"فنگر پرنٹ کی تصدیق ہو گئی"</string>
<string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"فنگر پرنٹ ہارڈ ویئر دستیاب نہیں ہے۔"</string>
<string name="fingerprint_error_no_space" msgid="1055819001126053318">"فنگر پرنٹ اسٹور نہیں کیا جا سکتا ہے۔ براہ کرم ایک موجودہ فنگر پرنٹ ہٹائیں۔"</string>
diff --git a/core/res/res/values-uz/strings.xml b/core/res/res/values-uz/strings.xml
index 684e78a50e53..7ffc7e7bb9da 100644
--- a/core/res/res/values-uz/strings.xml
+++ b/core/res/res/values-uz/strings.xml
@@ -284,7 +284,7 @@
<string name="permgrouprequest_sms" msgid="7168124215838204719">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; uchun SMS xabarlarni yuborish va ko‘rishga ruxsat berilsinmi?"</string>
<string name="permgrouplab_storage" msgid="1971118770546336966">"Xotira"</string>
<string name="permgroupdesc_storage" msgid="637758554581589203">"qurilmangizdagi surat, multimedia va fayllarga kirish"</string>
- <string name="permgrouprequest_storage" msgid="7885942926944299560">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; uchun qurilmangizdagi surat, multimedia va fayllarga ruxsat berilsinmi?"</string>
+ <string name="permgrouprequest_storage" msgid="7885942926944299560">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ilovasiga qurilmangizdagi surat, multimedia va fayllarga kirish uchun ruxsat berilsinmi?"</string>
<string name="permgrouplab_microphone" msgid="171539900250043464">"Mikrofon"</string>
<string name="permgroupdesc_microphone" msgid="4988812113943554584">"ovoz yozib olish"</string>
<string name="permgrouprequest_microphone" msgid="9167492350681916038">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; uchun audio yozib olishga ruxsat berilsinmi?"</string>
@@ -514,6 +514,7 @@
<string name="permdesc_imagesWrite" msgid="7073662756617474375">"Ilovaga suratlar to‘plamingizni o‘zgartirishga ruxsat beradi."</string>
<string name="permlab_mediaLocation" msgid="8675148183726247864">"multimedia to‘plamidan joylashuv axborotini o‘qish"</string>
<string name="permdesc_mediaLocation" msgid="2237023389178865130">"Ilovaga multimedia to‘plamingizdan joylashuv axborotini o‘qishga ruxsat beradi."</string>
+ <string name="biometric_error_hw_unavailable" msgid="645781226537551036">"Biometrik sensor ishlamayapti"</string>
<string name="fingerprint_acquired_partial" msgid="735082772341716043">"Barmoq izi qisman aniqlandi. Qayta urinib ko‘ring."</string>
<string name="fingerprint_acquired_insufficient" msgid="4596546021310923214">"Barmoq izi aniqlanmadi. Qayta urinib ko‘ring."</string>
<string name="fingerprint_acquired_imager_dirty" msgid="1087209702421076105">"Barmoq izi skaneri kirlangan. Uni tozalab, keyin qayta urinib ko‘ring."</string>
@@ -521,7 +522,7 @@
<string name="fingerprint_acquired_too_slow" msgid="59250885689661653">"Barmoq juda sekin harakatlandi. Qayta urinib ko‘ring."</string>
<string-array name="fingerprint_acquired_vendor">
</string-array>
- <string name="fingerprint_not_recognized" msgid="2690661881608146617">"Aniqlanmadi"</string>
+ <string name="biometric_not_recognized" msgid="5770511773560736082">"Aniqlanmadi"</string>
<string name="fingerprint_authenticated" msgid="5309333983002526448">"Barmoq izi tekshirildi"</string>
<string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"Barmoq izi skaneri ish holatida emas."</string>
<string name="fingerprint_error_no_space" msgid="1055819001126053318">"Barmoq izini saqlab bo‘lmadi. Mavjud barmoq izlaridan birini o‘chirib tashlang."</string>
diff --git a/core/res/res/values-vi/strings.xml b/core/res/res/values-vi/strings.xml
index b106ec5bc55d..a5f458b097e2 100644
--- a/core/res/res/values-vi/strings.xml
+++ b/core/res/res/values-vi/strings.xml
@@ -514,6 +514,7 @@
<string name="permdesc_imagesWrite" msgid="7073662756617474375">"Cho phép ứng dụng này sửa đổi bộ sưu tập ảnh của bạn."</string>
<string name="permlab_mediaLocation" msgid="8675148183726247864">"đọc vị trí từ bộ sưu tập phương tiện"</string>
<string name="permdesc_mediaLocation" msgid="2237023389178865130">"Cho phép ứng dụng này đọc vị trí từ bộ sưu tập phương tiện của bạn."</string>
+ <string name="biometric_error_hw_unavailable" msgid="645781226537551036">"Không có phần cứng sinh trắc học"</string>
<string name="fingerprint_acquired_partial" msgid="735082772341716043">"Đã phát hiện được một phần vân tay. Vui lòng thử lại."</string>
<string name="fingerprint_acquired_insufficient" msgid="4596546021310923214">"Không thể xử lý vân tay. Vui lòng thử lại."</string>
<string name="fingerprint_acquired_imager_dirty" msgid="1087209702421076105">"Cảm biến vân tay bị bẩn. Hãy làm sạch và thử lại."</string>
@@ -521,7 +522,7 @@
<string name="fingerprint_acquired_too_slow" msgid="59250885689661653">"Di chuyển ngón tay quá chậm. Vui lòng thử lại."</string>
<string-array name="fingerprint_acquired_vendor">
</string-array>
- <string name="fingerprint_not_recognized" msgid="2690661881608146617">"Không nhận dạng được"</string>
+ <string name="biometric_not_recognized" msgid="5770511773560736082">"Không nhận dạng được"</string>
<string name="fingerprint_authenticated" msgid="5309333983002526448">"Đã xác thực vân tay"</string>
<string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"Phần cứng vân tay không khả dụng."</string>
<string name="fingerprint_error_no_space" msgid="1055819001126053318">"Không thể lưu vân tay. Vui lòng xóa vân tay hiện có."</string>
diff --git a/core/res/res/values-watch/config.xml b/core/res/res/values-watch/config.xml
index a96a96ddaf01..cd809b8b55db 100644
--- a/core/res/res/values-watch/config.xml
+++ b/core/res/res/values-watch/config.xml
@@ -70,4 +70,7 @@
<!-- Default Gravity setting for the system Toast view. Equivalent to: Gravity.CENTER -->
<integer name="config_toastDefaultGravity">0x00000011</integer>
+
+ <!-- Default hyphenation frequency setting (0=NONE, 1=NORMAL, 2=FULL). -->
+ <item name="config_preferredHyphenationFrequency" format="integer" type="dimen">1</item>
</resources>
diff --git a/core/res/res/values-zh-rCN/strings.xml b/core/res/res/values-zh-rCN/strings.xml
index 5aca3ffff087..0b04e0875718 100644
--- a/core/res/res/values-zh-rCN/strings.xml
+++ b/core/res/res/values-zh-rCN/strings.xml
@@ -296,7 +296,7 @@
<string name="permgrouprequest_calllog" msgid="8487355309583773267">"允许&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;访问您的手机通话记录吗?"</string>
<string name="permgrouplab_phone" msgid="5229115638567440675">"电话"</string>
<string name="permgroupdesc_phone" msgid="6234224354060641055">"拨打电话和管理通话"</string>
- <string name="permgrouprequest_phone" msgid="9166979577750581037">"允许&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;拨打电话和管理通话吗?"</string>
+ <string name="permgrouprequest_phone" msgid="9166979577750581037">"允许“&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;”拨打电话和管理通话吗?"</string>
<string name="permgrouplab_sensors" msgid="416037179223226722">"身体传感器"</string>
<string name="permgroupdesc_sensors" msgid="7147968539346634043">"访问与您的生命体征相关的传感器数据"</string>
<string name="permgrouprequest_sensors" msgid="6349806962814556786">"允许&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;访问与您的生命体征相关的传感器数据吗?"</string>
@@ -514,6 +514,7 @@
<string name="permdesc_imagesWrite" msgid="7073662756617474375">"允许该应用修改您的照片收藏。"</string>
<string name="permlab_mediaLocation" msgid="8675148183726247864">"从您的媒体收藏中读取位置信息"</string>
<string name="permdesc_mediaLocation" msgid="2237023389178865130">"允许该应用从您的媒体收藏中读取位置信息。"</string>
+ <string name="biometric_error_hw_unavailable" msgid="645781226537551036">"生物识别硬件无法使用"</string>
<string name="fingerprint_acquired_partial" msgid="735082772341716043">"仅检测到部分指纹,请重试。"</string>
<string name="fingerprint_acquired_insufficient" msgid="4596546021310923214">"无法处理指纹,请重试。"</string>
<string name="fingerprint_acquired_imager_dirty" msgid="1087209702421076105">"指纹传感器有脏污。请擦拭干净,然后重试。"</string>
@@ -521,7 +522,7 @@
<string name="fingerprint_acquired_too_slow" msgid="59250885689661653">"手指移动太慢,请重试。"</string>
<string-array name="fingerprint_acquired_vendor">
</string-array>
- <string name="fingerprint_not_recognized" msgid="2690661881608146617">"无法识别"</string>
+ <string name="biometric_not_recognized" msgid="5770511773560736082">"无法识别"</string>
<string name="fingerprint_authenticated" msgid="5309333983002526448">"已验证指纹"</string>
<string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"指纹硬件无法使用。"</string>
<string name="fingerprint_error_no_space" msgid="1055819001126053318">"无法存储指纹。请移除一个现有的指纹。"</string>
diff --git a/core/res/res/values-zh-rHK/strings.xml b/core/res/res/values-zh-rHK/strings.xml
index 79c9cc44688f..87eb41f2acba 100644
--- a/core/res/res/values-zh-rHK/strings.xml
+++ b/core/res/res/values-zh-rHK/strings.xml
@@ -514,6 +514,7 @@
<string name="permdesc_imagesWrite" msgid="7073662756617474375">"允許應用程式修改您的相片集。"</string>
<string name="permlab_mediaLocation" msgid="8675148183726247864">"讀取媒體集的位置"</string>
<string name="permdesc_mediaLocation" msgid="2237023389178865130">"允許應用程式讀取媒體集的位置。"</string>
+ <string name="biometric_error_hw_unavailable" msgid="645781226537551036">"無法使用生物識別硬件"</string>
<string name="fingerprint_acquired_partial" msgid="735082772341716043">"只偵測到部分指紋。請再試一次。"</string>
<string name="fingerprint_acquired_insufficient" msgid="4596546021310923214">"無法處理指紋。請再試一次。"</string>
<string name="fingerprint_acquired_imager_dirty" msgid="1087209702421076105">"指紋感應器不乾淨。請清潔後再試一次。"</string>
@@ -521,7 +522,7 @@
<string name="fingerprint_acquired_too_slow" msgid="59250885689661653">"手指移動太慢,請重試。"</string>
<string-array name="fingerprint_acquired_vendor">
</string-array>
- <string name="fingerprint_not_recognized" msgid="2690661881608146617">"未能辨別"</string>
+ <string name="biometric_not_recognized" msgid="5770511773560736082">"未能識別"</string>
<string name="fingerprint_authenticated" msgid="5309333983002526448">"驗證咗指紋"</string>
<string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"無法使用指紋軟件。"</string>
<string name="fingerprint_error_no_space" msgid="1055819001126053318">"指紋無法儲存。請移除現有指紋。"</string>
diff --git a/core/res/res/values-zh-rTW/strings.xml b/core/res/res/values-zh-rTW/strings.xml
index 5143718e526b..bd4ea2a6610e 100644
--- a/core/res/res/values-zh-rTW/strings.xml
+++ b/core/res/res/values-zh-rTW/strings.xml
@@ -514,6 +514,7 @@
<string name="permdesc_imagesWrite" msgid="7073662756617474375">"允許應用程式修改你的相片收藏。"</string>
<string name="permlab_mediaLocation" msgid="8675148183726247864">"讀取你的媒體收藏的位置資訊"</string>
<string name="permdesc_mediaLocation" msgid="2237023389178865130">"允許應用程式讀取你的媒體收藏的位置資訊。"</string>
+ <string name="biometric_error_hw_unavailable" msgid="645781226537551036">"找不到生物特徵辨識硬體"</string>
<string name="fingerprint_acquired_partial" msgid="735082772341716043">"僅偵測到部分指紋,請再試一次。"</string>
<string name="fingerprint_acquired_insufficient" msgid="4596546021310923214">"無法處理指紋,請再試一次。"</string>
<string name="fingerprint_acquired_imager_dirty" msgid="1087209702421076105">"指紋感應器有髒汙。請清潔感應器,然後再試一次。"</string>
@@ -521,7 +522,7 @@
<string name="fingerprint_acquired_too_slow" msgid="59250885689661653">"手指移動速度過慢,請再試一次。"</string>
<string-array name="fingerprint_acquired_vendor">
</string-array>
- <string name="fingerprint_not_recognized" msgid="2690661881608146617">"無法識別"</string>
+ <string name="biometric_not_recognized" msgid="5770511773560736082">"無法辨識"</string>
<string name="fingerprint_authenticated" msgid="5309333983002526448">"指紋驗證成功"</string>
<string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"指紋硬體無法使用。"</string>
<string name="fingerprint_error_no_space" msgid="1055819001126053318">"無法儲存指紋,請先移除現有指紋。"</string>
diff --git a/core/res/res/values-zu/strings.xml b/core/res/res/values-zu/strings.xml
index fbe0dc7204ed..fd6614cecbe0 100644
--- a/core/res/res/values-zu/strings.xml
+++ b/core/res/res/values-zu/strings.xml
@@ -514,6 +514,7 @@
<string name="permdesc_imagesWrite" msgid="7073662756617474375">"Ivumela uhlelo lwakho lokusebenza ukuthi lilungise iqoqo lakho lesithombe."</string>
<string name="permlab_mediaLocation" msgid="8675148183726247864">"funda izindawo kusukela kuqoqo lakho lemidiya"</string>
<string name="permdesc_mediaLocation" msgid="2237023389178865130">"Ivumela uhlelo lokusebenza ukuthi lifunde izindawo kusukela kuqoqo lakho lemidiya."</string>
+ <string name="biometric_error_hw_unavailable" msgid="645781226537551036">"I-Biometric hardware ayitholakali"</string>
<string name="fingerprint_acquired_partial" msgid="735082772341716043">"Izigxivizo zeminwe ezincane zitholiwe. Sicela uzame futhi."</string>
<string name="fingerprint_acquired_insufficient" msgid="4596546021310923214">"Ayikwazanga ukucubungula izigxivizo zeminwe. Sicela uzame futhi."</string>
<string name="fingerprint_acquired_imager_dirty" msgid="1087209702421076105">"Inzwa yezigxivizo zeminwe ingcolile. Sicela uyihlanze uphinde uzame futhi."</string>
@@ -521,7 +522,7 @@
<string name="fingerprint_acquired_too_slow" msgid="59250885689661653">"Umnwe uhanjiswe kancane kakhulu. Sicela uzame futhi."</string>
<string-array name="fingerprint_acquired_vendor">
</string-array>
- <string name="fingerprint_not_recognized" msgid="2690661881608146617">"Akubonwa"</string>
+ <string name="biometric_not_recognized" msgid="5770511773560736082">"Akwaziwa"</string>
<string name="fingerprint_authenticated" msgid="5309333983002526448">"Isingxivizo somunwe sigunyaziwe"</string>
<string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"Izingxenyekazi zekhompuyutha zezingxivizo zeminwe azitholakali."</string>
<string name="fingerprint_error_no_space" msgid="1055819001126053318">"Izigxivizo zeminwe azikwazi ukugcinwa. Sicela ususe izigxivizo zeminwe ezikhona."</string>
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index 64a9e6dc6a85..3fed8a3a80d3 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -4574,6 +4574,8 @@
<attr name="letterSpacing" format="float" />
<!-- Font feature settings. -->
<attr name="fontFeatureSettings" format="string" />
+ <!-- Font variation settings. -->
+ <attr name="fontVariationSettings" format="string"/>
</declare-styleable>
<declare-styleable name="TextClock">
<!-- Specifies the formatting pattern used to show the time and/or date
@@ -4922,6 +4924,8 @@
<attr name="letterSpacing" />
<!-- Font feature settings. -->
<attr name="fontFeatureSettings" />
+ <!-- Font variation settings. -->
+ <attr name="fontVariationSettings" />
<!-- Break strategy (control over paragraph layout). -->
<attr name="breakStrategy">
<!-- Line breaking uses simple strategy. -->
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 235f85b2c318..293d90e276b3 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -913,7 +913,7 @@
<!-- Control whether to lock day/night mode change from normal application. When it is
true, day / night mode change is only allowed to apps with MODIFY_DAY_NIGHT_MODE
permission. -->
- <bool name="config_lockDayNightMode">false</bool>
+ <bool name="config_lockDayNightMode">true</bool>
<!-- Control the default night mode to use when there is no other mode override set.
One of the following values (see UiModeManager.java):
@@ -3510,6 +3510,9 @@
<item>"wifi"</item>
</string-array>
+ <!-- Default hyphenation frequency setting (0=NONE, 1=NORMAL, 2=FULL). -->
+ <item name="config_preferredHyphenationFrequency" format="integer" type="dimen">0</item>
+
<!-- Package name for ManagedProvisioning which is responsible for provisioning work profiles. -->
<string name="config_managed_provisioning_package" translatable="false">com.android.managedprovisioning</string>
diff --git a/core/res/res/values/styles.xml b/core/res/res/values/styles.xml
index fafcf935b7d6..ef286e2037bf 100644
--- a/core/res/res/values/styles.xml
+++ b/core/res/res/values/styles.xml
@@ -506,13 +506,13 @@ please see styles_device_defaults.xml.
<item name="textEditSuggestionHighlightStyle">?attr/textEditSuggestionHighlightStyle</item>
<item name="textCursorDrawable">?attr/textCursorDrawable</item>
<item name="breakStrategy">high_quality</item>
- <item name="hyphenationFrequency">none</item>
+ <item name="hyphenationFrequency">@dimen/config_preferredHyphenationFrequency</item>
</style>
<style name="Widget.CheckedTextView">
<item name="textAlignment">viewStart</item>
<item name="breakStrategy">high_quality</item>
- <item name="hyphenationFrequency">none</item>
+ <item name="hyphenationFrequency">@dimen/config_preferredHyphenationFrequency</item>
</style>
<style name="Widget.TextView.ListSeparator">
@@ -540,7 +540,7 @@ please see styles_device_defaults.xml.
<item name="textColor">?attr/editTextColor</item>
<item name="gravity">center_vertical</item>
<item name="breakStrategy">simple</item>
- <item name="hyphenationFrequency">none</item>
+ <item name="hyphenationFrequency">@dimen/config_preferredHyphenationFrequency</item>
<item name="defaultFocusHighlightEnabled">false</item>
</style>
diff --git a/core/tests/coretests/src/android/graphics/TypefaceSystemFallbackTest.java b/core/tests/coretests/src/android/graphics/TypefaceSystemFallbackTest.java
index dd34f1fdde1f..1c4039b85441 100644
--- a/core/tests/coretests/src/android/graphics/TypefaceSystemFallbackTest.java
+++ b/core/tests/coretests/src/android/graphics/TypefaceSystemFallbackTest.java
@@ -23,6 +23,7 @@ import static org.junit.Assert.assertTrue;
import android.content.Context;
import android.content.res.AssetManager;
+import android.graphics.fonts.Font;
import android.graphics.fonts.FontFamily;
import android.graphics.fonts.SystemFonts;
import android.support.test.InstrumentationRegistry;
@@ -43,6 +44,7 @@ import java.io.InputStream;
import java.nio.charset.Charset;
import java.nio.file.Files;
import java.nio.file.StandardCopyOption;
+import java.util.HashSet;
import java.util.Locale;
@SmallTest
@@ -110,13 +112,14 @@ public class TypefaceSystemFallbackTest {
private static void buildSystemFallback(String xml,
ArrayMap<String, Typeface> fontMap, ArrayMap<String, FontFamily[]> fallbackMap) {
+ final HashSet<Font> availableFonts = new HashSet<>();
try (FileOutputStream fos = new FileOutputStream(TEST_FONTS_XML)) {
fos.write(xml.getBytes(Charset.forName("UTF-8")));
} catch (IOException e) {
throw new RuntimeException(e);
}
final FontConfig.Alias[] aliases = SystemFonts.buildSystemFallback(TEST_FONTS_XML,
- TEST_FONT_DIR, fallbackMap);
+ TEST_FONT_DIR, fallbackMap, availableFonts);
Typeface.initSystemDefaultTypefaces(fontMap, fallbackMap, aliases);
}
@@ -124,9 +127,10 @@ public class TypefaceSystemFallbackTest {
public void testBuildSystemFallback() {
final ArrayMap<String, Typeface> fontMap = new ArrayMap<>();
final ArrayMap<String, FontFamily[]> fallbackMap = new ArrayMap<>();
+ final HashSet<Font> availableFonts = new HashSet<>();
final FontConfig.Alias[] aliases = SystemFonts.buildSystemFallback(SYSTEM_FONTS_XML,
- SYSTEM_FONT_DIR, fallbackMap);
+ SYSTEM_FONT_DIR, fallbackMap, availableFonts);
assertNotNull(aliases);
assertFalse(fallbackMap.isEmpty());
@@ -487,7 +491,7 @@ public class TypefaceSystemFallbackTest {
+ " <family lang='de'>"
+ " <font weight='400' style='normal'>a3em.ttf</font>"
+ " </family>"
- + " <family lang='it fr'>"
+ + " <family lang='it,fr'>"
+ " <font weight='400' style='normal'>b3em.ttf</font>"
+ " </family>"
+ "</familyset>";
diff --git a/core/tests/coretests/src/android/text/FontFallbackSetup.java b/core/tests/coretests/src/android/text/FontFallbackSetup.java
index 6c34043c1995..355be619ea91 100644
--- a/core/tests/coretests/src/android/text/FontFallbackSetup.java
+++ b/core/tests/coretests/src/android/text/FontFallbackSetup.java
@@ -20,6 +20,7 @@ import android.annotation.NonNull;
import android.content.Context;
import android.content.res.AssetManager;
import android.graphics.Typeface;
+import android.graphics.fonts.Font;
import android.graphics.fonts.FontFamily;
import android.graphics.fonts.SystemFonts;
import android.support.test.InstrumentationRegistry;
@@ -32,6 +33,7 @@ import java.io.InputStream;
import java.nio.charset.Charset;
import java.nio.file.Files;
import java.nio.file.StandardCopyOption;
+import java.util.HashSet;
public class FontFallbackSetup implements AutoCloseable {
private final String[] mTestFontFiles;
@@ -74,8 +76,9 @@ public class FontFallbackSetup implements AutoCloseable {
}
final ArrayMap<String, FontFamily[]> fallbackMap = new ArrayMap<>();
+ final HashSet<Font> availableFonts = new HashSet<>();
final FontConfig.Alias[] aliases = SystemFonts.buildSystemFallback(testFontsXml,
- mTestFontsDir, fallbackMap);
+ mTestFontsDir, fallbackMap, availableFonts);
Typeface.initSystemDefaultTypefaces(mFontMap, fallbackMap, aliases);
}
diff --git a/data/fonts/fonts.xml b/data/fonts/fonts.xml
index be9347ab6771..c84c0354a7c4 100644
--- a/data/fonts/fonts.xml
+++ b/data/fonts/fonts.xml
@@ -137,7 +137,7 @@
<font weight="400" style="normal" fallbackFor="serif">NotoSerifArmenian-Regular.otf</font>
<font weight="700" style="normal" fallbackFor="serif">NotoSerifArmenian-Bold.otf</font>
</family>
- <family lang="und-Geor und-Geok">
+ <family lang="und-Geor,und-Geok">
<font weight="400" style="normal">NotoSansGeorgian-Regular.otf</font>
<font weight="500" style="normal">NotoSansGeorgian-Medium.otf</font>
<font weight="700" style="normal">NotoSansGeorgian-Bold.otf</font>
@@ -538,7 +538,7 @@
<font weight="400" style="normal" index="2">NotoSansCJK-Regular.ttc</font>
<font weight="400" style="normal" index="2" fallbackFor="serif">NotoSerifCJK-Regular.ttc</font>
</family>
- <family lang="zh-Hant zh-Bopo">
+ <family lang="zh-Hant,zh-Bopo">
<font weight="400" style="normal" index="3">NotoSansCJK-Regular.ttc</font>
<font weight="400" style="normal" index="3" fallbackFor="serif">NotoSerifCJK-Regular.ttc</font>
</family>
diff --git a/graphics/java/android/graphics/FontListParser.java b/graphics/java/android/graphics/FontListParser.java
index e3e8380716f3..82435d5511f5 100644
--- a/graphics/java/android/graphics/FontListParser.java
+++ b/graphics/java/android/graphics/FontListParser.java
@@ -74,8 +74,7 @@ public class FontListParser {
private static FontConfig.Family readFamily(XmlPullParser parser)
throws XmlPullParserException, IOException {
final String name = parser.getAttributeValue(null, "name");
- final String lang = parser.getAttributeValue(null, "lang");
- final String[] langs = lang == null ? null : lang.split("\\s+");
+ final String lang = parser.getAttributeValue("", "lang");
final String variant = parser.getAttributeValue(null, "variant");
final List<FontConfig.Font> fonts = new ArrayList<FontConfig.Font>();
while (parser.next() != XmlPullParser.END_TAG) {
@@ -95,7 +94,7 @@ public class FontListParser {
intVariant = FontConfig.Family.VARIANT_ELEGANT;
}
}
- return new FontConfig.Family(name, fonts.toArray(new FontConfig.Font[fonts.size()]), langs,
+ return new FontConfig.Family(name, fonts.toArray(new FontConfig.Font[fonts.size()]), lang,
intVariant);
}
@@ -126,8 +125,8 @@ public class FontListParser {
}
}
String sanitizedName = FILENAME_WHITESPACE_PATTERN.matcher(filename).replaceAll("");
- return new FontConfig.Font(sanitizedName, index,
- axes.toArray(new FontVariationAxis[axes.size()]), weight, isItalic, fallbackFor);
+ return new FontConfig.Font(sanitizedName, index, axes.toArray(
+ new FontVariationAxis[axes.size()]), weight, isItalic, fallbackFor);
}
private static FontVariationAxis readAxis(XmlPullParser parser)
diff --git a/graphics/java/android/graphics/Paint.java b/graphics/java/android/graphics/Paint.java
index 7fc178738055..6f306530868d 100644
--- a/graphics/java/android/graphics/Paint.java
+++ b/graphics/java/android/graphics/Paint.java
@@ -1742,26 +1742,52 @@ public class Paint {
}
/**
- * Get the current value of hyphen edit.
+ * Get the current value of packed hyphen edit.
*
- * @return the current hyphen edit value
+ * You can extract start hyphen edit and end hyphen edit by using
+ * {@link android.text.Hyphenator#unpackStartHyphenEdit(int)} and
+ * {@link android.text.Hyphenator#unpackEndHyphenEdit(int)}.
*
- * @hide
+ * The default value is 0 which is equivalent to packed value of
+ * {@link android.text.Hyphenator#START_HYPHEN_EDIT_NO_EDIT} and
+ * {@link android.text.Hyphenator#END_HYPHEN_EDIT_NO_EDIT}.
+ *
+ * @return the current hyphen edit value
+ * @see #setHyphenEdit(int)
*/
public int getHyphenEdit() {
return nGetHyphenEdit(mNativePaint);
}
/**
- * Set a hyphen edit on the paint (causes a hyphen to be added to text when
- * measured or drawn).
+ * Set a packed hyphen edit on the paint.
*
- * @param hyphen 0 for no edit, 1 for adding a hyphen at the end, etc.
- * Definition of various values are in the HyphenEdit class in Minikin's Hyphenator.h.
+ * By setting hyphen edit, the measurement and drawing is performed with modifying hyphenation
+ * at the start of line and end of line. For example, by passing
+ * {@link android.text.Hyphenator#END_HYPHEN_EDIT_INSERT_HYPHEN} like as follows, HYPHEN(U+2010)
+ * character is appended at the end of line.
*
- * @hide
+ * <pre>
+ * <code>
+ * Paint paint = new Paint();
+ * paint.setHyphenEdit(Hyphenator.packHyphenEdit(
+ * Hyphenator.START_HYPHEN_EDIT_NO_EDIT,
+ * Hyphenator.END_HYPHEN_EDIT_INSERT_HYPHEN));
+ * paint.measureText("abc", 0, 3); // Returns the width of "abc‐"
+ * Canvas.drawText("abc", 0, 3, 0f, 0f, paint); // Draws "abc‐"
+ * </code>
+ * </pre>
+ *
+ * You can pack start hyphen edit and end hyphen edit by
+ * {@link android.text.Hyphenator#packHyphenEdit(int,int)}
+ *
+ * The default value is 0 which is equivalent to packed value of
+ * {@link android.text.Hyphenator#START_HYPHEN_EDIT_NO_EDIT} and
+ * {@link android.text.Hyphenator#END_HYPHEN_EDIT_NO_EDIT}.
+ *
+ * @param hyphen a packed hyphen edit value.
+ * @see #getHyphenEdit()
*/
- @UnsupportedAppUsage
public void setHyphenEdit(int hyphen) {
nSetHyphenEdit(mNativePaint, hyphen);
}
diff --git a/graphics/java/android/graphics/Typeface.java b/graphics/java/android/graphics/Typeface.java
index 52806423c336..5aa09cef0c4e 100644
--- a/graphics/java/android/graphics/Typeface.java
+++ b/graphics/java/android/graphics/Typeface.java
@@ -148,13 +148,7 @@ public class Typeface {
@UnsupportedAppUsage
private @Style int mStyle = 0;
- /**
- * A maximum value for the weight value.
- * @hide
- */
- public static final int MAX_WEIGHT = 1000;
-
- private @IntRange(from = 0, to = MAX_WEIGHT) int mWeight = 0;
+ private @IntRange(from = 0, to = android.graphics.fonts.Font.FONT_WEIGHT_MAX) int mWeight = 0;
// Value for weight and italic. Indicates the value is resolved by font metadata.
// Must be the same as the C++ constant in core/jni/android/graphics/FontFamily.cpp
@@ -673,6 +667,128 @@ public class Typeface {
}
/**
+ * A builder class for creating new Typeface instance.
+ *
+ * <p>
+ * Examples,
+ * 1) Create Typeface from single ttf file.
+ * <pre>
+ * <code>
+ * Font font = new Font.Builder("your_font_file.ttf").build();
+ * FontFamily family = new FontFamily.Builder(font).build();
+ * Typeface typeface = new Typeface.CustomFallbackBuilder(family).build();
+ * </code>
+ * </pre>
+ *
+ * 2) Create Typeface from multiple font files and select bold style by default.
+ * <pre>
+ * <code>
+ * Font regularFont = new Font.Builder("regular.ttf").build();
+ * Font boldFont = new Font.Builder("bold.ttf").build();
+ * FontFamily family = new FontFamily.Builder(regularFont)
+ * .addFont(boldFont).build();
+ * Typeface typeface = new Typeface.CustomFallbackBuilder(family)
+ * .setWeight(Font.FONT_WEIGHT_BOLD) // Set bold style as the default style.
+ * // If the font family doesn't have bold style font,
+ * // system will select the closest font.
+ * .build();
+ * </code>
+ * </pre>
+ *
+ * 3) Create Typeface from single ttf file and if that font does not have glyph for the
+ * characters, use "serif" font family instead.
+ * <pre>
+ * <code>
+ * Font font = new Font.Builder("your_font_file.ttf").build();
+ * FontFamily family = new FontFamily.Builder(font).build();
+ * Typeface typeface = new Typeface.CustomFallbackBuilder(family)
+ * .setFallback("serif") // Set serif font family as the fallback.
+ * .build();
+ * </code>
+ * </pre>
+ * </p>
+ */
+ public static class CustomFallbackBuilder {
+ // TODO: Remove package modifier once android.graphics.FontFamily is deprecated.
+ private final android.graphics.fonts.FontFamily mFamily;
+ private String mFallbackName = null;
+ private @IntRange(from = 0, to = 1000) int mWeight = 400;
+ private boolean mItalic = false;
+
+ /**
+ * Constructs a builder with a font family.
+ *
+ * @param family a family object
+ */
+ // TODO: Remove package modifier once android.graphics.FontFamily is deprecated.
+ public CustomFallbackBuilder(@NonNull android.graphics.fonts.FontFamily family) {
+ Preconditions.checkNotNull(family);
+ mFamily = family;
+ }
+
+ /**
+ * Sets a system fallback by name.
+ *
+ * @param familyName a family name to be used for fallback if the provided fonts can not be
+ * used
+ */
+ public CustomFallbackBuilder setFallback(@NonNull String familyName) {
+ Preconditions.checkNotNull(familyName);
+ mFallbackName = familyName;
+ return this;
+ }
+
+ /**
+ * Sets a weight of the Typeface.
+ *
+ * If the font family doesn't have a font of given weight, system will select the closest
+ * font from font family. For example, if a font family has fonts of 300 weight and 700
+ * weight then setWeight(400) is called, system will select the font of 300 weight.
+ *
+ * @see Font#FONT_WEIGHT_THIN
+ * @see Font#FONT_WEIGHT_EXTRA_LIGHT
+ * @see Font#FONT_WEIGHT_LIGHT
+ * @see Font#FONT_WEIGHT_NORMAL
+ * @see Font#FONT_WEIGHT_MEDIUM
+ * @see Font#FONT_WEIGHT_SEMI_BOLD
+ * @see Font#FONT_WEIGHT_BOLD
+ * @see Font#FONT_WEIGHT_EXTRA_BOLD
+ * @see Font#FONT_WEIGHT_BLACK
+ * @param weight a weight value
+ */
+ public CustomFallbackBuilder setWeight(@IntRange(from = 0, to = 1000) int weight) {
+ mWeight = weight;
+ return this;
+ }
+
+ /**
+ * Sets a italic style of the Typeface.
+ *
+ * @param italic true if italic, otherwise false
+ */
+ public CustomFallbackBuilder setItalic(boolean italic) {
+ mItalic = italic;
+ return this;
+ }
+
+ /**
+ * Create the Typeface based on the configured values.
+ *
+ * @return the Typeface object
+ */
+ public Typeface build() {
+ final android.graphics.fonts.FontFamily[] fallback =
+ SystemFonts.getSystemFallback(mFallbackName);
+ final long[] ptrArray = new long[fallback.length + 1];
+ ptrArray[0] = mFamily.getNativePtr();
+ for (int i = 0; i < fallback.length; ++i) {
+ ptrArray[i + 1] = fallback[i].getNativePtr();
+ }
+ return new Typeface(nativeCreateFromArray(ptrArray, mWeight, mItalic ? 1 : 0));
+ }
+ }
+
+ /**
* Create a typeface object given a family name, and option style information.
* If null is passed for the name, then the "default" font will be chosen.
* The resulting typeface object can be queried (getStyle()) to discover what
diff --git a/graphics/java/android/graphics/drawable/Icon.java b/graphics/java/android/graphics/drawable/Icon.java
index accc08157ac5..a33777314116 100644
--- a/graphics/java/android/graphics/drawable/Icon.java
+++ b/graphics/java/android/graphics/drawable/Icon.java
@@ -21,6 +21,7 @@ import android.annotation.DrawableRes;
import android.annotation.IdRes;
import android.annotation.IntDef;
import android.annotation.NonNull;
+import android.annotation.SystemApi;
import android.annotation.UnsupportedAppUsage;
import android.content.ContentResolver;
import android.content.Context;
@@ -568,7 +569,7 @@ public final class Icon implements Parcelable {
* Version of createWithResource that takes Resources. Do not use.
* @hide
*/
- @UnsupportedAppUsage
+ @SystemApi
public static Icon createWithResource(Resources res, @DrawableRes int resId) {
if (res == null) {
throw new IllegalArgumentException("Resource must not be null.");
diff --git a/graphics/java/android/graphics/fonts/Font.java b/graphics/java/android/graphics/fonts/Font.java
index f0c519922fdd..8aa48456ebff 100644
--- a/graphics/java/android/graphics/fonts/Font.java
+++ b/graphics/java/android/graphics/fonts/Font.java
@@ -21,6 +21,7 @@ import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.res.AssetManager;
import android.content.res.Resources;
+import android.os.LocaleList;
import android.util.TypedValue;
import com.android.internal.util.Preconditions;
@@ -50,6 +51,11 @@ public final class Font {
private static final int STYLE_NORMAL = 0;
/**
+ * A minimum weight value for the font
+ */
+ public static final int FONT_WEIGHT_MIN = 1;
+
+ /**
* A font weight value for the thin weight
*/
public static final int FONT_WEIGHT_THIN = 100;
@@ -95,6 +101,11 @@ public final class Font {
public static final int FONT_WEIGHT_BLACK = 900;
/**
+ * A maximum weight value for the font
+ */
+ public static final int FONT_WEIGHT_MAX = 1000;
+
+ /**
* A builder class for creating new Font.
*/
public static class Builder {
@@ -107,6 +118,8 @@ public final class Font {
nGetReleaseNativeFont(), 64);
private @Nullable ByteBuffer mBuffer;
+ private @Nullable File mFile;
+ private @NonNull LocaleList mLocaleList = LocaleList.getEmptyLocaleList();
private @IntRange(from = -1, to = 1000) int mWeight = NOT_SPECIFIED;
private @IntRange(from = -1, to = 1) int mItalic = NOT_SPECIFIED;
private @IntRange(from = 0) int mTtcIndex = 0;
@@ -131,6 +144,19 @@ public final class Font {
}
/**
+ * Construct a builder with a byte buffer and file path.
+ *
+ * This method is intended to be called only from SystemFonts.
+ * @hide
+ */
+ public Builder(@NonNull ByteBuffer buffer, @NonNull File path,
+ @NonNull LocaleList localeList) {
+ this(buffer);
+ mFile = path;
+ mLocaleList = localeList;
+ }
+
+ /**
* Constructs a builder with a file path.
*
* @param path a file path to the font file
@@ -143,6 +169,7 @@ public final class Font {
} catch (IOException e) {
mException = e;
}
+ mFile = path;
}
/**
@@ -305,8 +332,9 @@ public final class Font {
* @param weight a weight value
* @return this builder
*/
- public @NonNull Builder setWeight(@IntRange(from = 1, to = 1000) int weight) {
- Preconditions.checkArgument(1 <= weight && weight <= 1000);
+ public @NonNull Builder setWeight(
+ @IntRange(from = FONT_WEIGHT_MIN, to = FONT_WEIGHT_MAX) int weight) {
+ Preconditions.checkArgument(FONT_WEIGHT_MIN <= weight && weight <= FONT_WEIGHT_MAX);
mWeight = weight;
return this;
}
@@ -386,6 +414,7 @@ public final class Font {
mItalic = STYLE_NORMAL;
}
}
+ mWeight = Math.max(FONT_WEIGHT_MIN, Math.min(FONT_WEIGHT_MAX, mWeight));
final boolean italic = (mItalic == STYLE_ITALIC);
final long builderPtr = nInitBuilder();
if (mAxes != null) {
@@ -394,7 +423,8 @@ public final class Font {
}
}
final long ptr = nBuild(builderPtr, mBuffer, mWeight, italic, mTtcIndex);
- final Font font = new Font(ptr, mBuffer, mWeight, italic, mTtcIndex, mAxes);
+ final Font font = new Font(ptr, mBuffer, mFile, mWeight, italic, mTtcIndex, mAxes,
+ mLocaleList);
sFontRegistory.registerNativeAllocation(font, ptr);
return font;
}
@@ -422,23 +452,48 @@ public final class Font {
private final long mNativePtr; // address of the shared ptr of minikin::Font
private final @NonNull ByteBuffer mBuffer;
+ private final @Nullable File mFile;
private final @IntRange(from = 0, to = 1000) int mWeight;
private final boolean mItalic;
private final @IntRange(from = 0) int mTtcIndex;
private final @Nullable FontVariationAxis[] mAxes;
+ private final @NonNull LocaleList mLocaleList;
/**
* Use Builder instead
*/
- private Font(long nativePtr, @NonNull ByteBuffer buffer,
+ private Font(long nativePtr, @NonNull ByteBuffer buffer, @Nullable File file,
@IntRange(from = 0, to = 1000) int weight, boolean italic,
- @IntRange(from = 0) int ttcIndex, @Nullable FontVariationAxis[] axes) {
+ @IntRange(from = 0) int ttcIndex, @Nullable FontVariationAxis[] axes,
+ @NonNull LocaleList localeList) {
mBuffer = buffer;
+ mFile = file;
mWeight = weight;
mItalic = italic;
mNativePtr = nativePtr;
mTtcIndex = ttcIndex;
mAxes = axes;
+ mLocaleList = localeList;
+ }
+
+ /**
+ * Retuns a font file buffer.
+ *
+ * @return a font buffer
+ */
+ public @NonNull ByteBuffer getBuffer() {
+ return mBuffer;
+ }
+
+ /**
+ * Returns a file path of this font.
+ *
+ * This returns null if this font is not created from regular file.
+ *
+ * @return a file path of the font
+ */
+ public @Nullable File getFile() {
+ return mFile;
}
/**
@@ -484,6 +539,16 @@ public final class Font {
return mAxes == null ? null : mAxes.clone();
}
+ /**
+ * Get a locale list of this font.
+ *
+ * This is always empty if this font is not a system font.
+ * @return a locale list
+ */
+ public @NonNull LocaleList getLocaleList() {
+ return mLocaleList;
+ }
+
/** @hide */
public long getNativePtr() {
return mNativePtr;
@@ -504,11 +569,19 @@ public final class Font {
@Override
public int hashCode() {
- return Objects.hash(mWeight, mItalic, mTtcIndex, mAxes, mBuffer);
+ return Objects.hash(mWeight, mItalic, mTtcIndex, Arrays.hashCode(mAxes), mBuffer);
}
@Override
public String toString() {
- return "Font {weight=" + mWeight + ", italic=" + mItalic + "}";
+ return "Font {"
+ + "path=" + mFile
+ + ", weight=" + mWeight
+ + ", italic=" + mItalic
+ + ", ttcIndex=" + mTtcIndex
+ + ", axes=" + FontVariationAxis.toFontVariationSettings(mAxes)
+ + ", localeList=" + mLocaleList.toLanguageTags()
+ + ", buffer=" + mBuffer
+ + "}";
}
}
diff --git a/graphics/java/android/graphics/fonts/FontFamily.java b/graphics/java/android/graphics/fonts/FontFamily.java
index c914ecedd761..3bcdc31a3160 100644
--- a/graphics/java/android/graphics/fonts/FontFamily.java
+++ b/graphics/java/android/graphics/fonts/FontFamily.java
@@ -18,9 +18,7 @@ package android.graphics.fonts;
import android.annotation.IntRange;
import android.annotation.NonNull;
-import android.annotation.Nullable;
import android.text.FontConfig;
-import android.text.TextUtils;
import com.android.internal.util.Preconditions;
@@ -110,25 +108,16 @@ public final class FontFamily {
* @return a font family
*/
public @NonNull FontFamily build() {
- return build(null, FontConfig.Family.VARIANT_DEFAULT);
+ return build("", FontConfig.Family.VARIANT_DEFAULT);
}
/** @hide */
- public @NonNull FontFamily build(@Nullable String[] langTags, int variant) {
+ public @NonNull FontFamily build(@NonNull String langTags, int variant) {
final long builderPtr = nInitBuilder();
for (int i = 0; i < mFonts.size(); ++i) {
nAddFont(builderPtr, mFonts.get(i).getNativePtr());
}
- final String langString;
- if (langTags == null || langTags.length == 0) {
- langString = null;
- } else if (langTags.length == 1) {
- langString = langTags[0];
- } else {
- langString = TextUtils.join(",", langTags);
- }
-
- final long ptr = nBuild(builderPtr, langString, variant);
+ final long ptr = nBuild(builderPtr, langTags, variant);
final FontFamily family = new FontFamily(mFonts, ptr);
sFamilyRegistory.registerNativeAllocation(family, ptr);
return family;
diff --git a/graphics/java/android/graphics/fonts/SystemFonts.java b/graphics/java/android/graphics/fonts/SystemFonts.java
index 26b4ec530072..1c957b8880b9 100644
--- a/graphics/java/android/graphics/fonts/SystemFonts.java
+++ b/graphics/java/android/graphics/fonts/SystemFonts.java
@@ -19,6 +19,7 @@ package android.graphics.fonts;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.graphics.FontListParser;
+import android.os.LocaleList;
import android.text.FontConfig;
import android.util.ArrayMap;
import android.util.Log;
@@ -28,6 +29,7 @@ import com.android.internal.util.ArrayUtils;
import org.xmlpull.v1.XmlPullParserException;
+import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.nio.ByteBuffer;
@@ -36,12 +38,13 @@ import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
+import java.util.HashSet;
import java.util.List;
import java.util.Map;
+import java.util.Set;
/**
* Provides the system font configurations.
- * @hide
*/
public class SystemFonts {
private static final String TAG = "SystemFonts";
@@ -49,8 +52,19 @@ public class SystemFonts {
private SystemFonts() {} // Do not instansiate.
- static final Map<String, FontFamily[]> sSystemFallbackMap;
- static final FontConfig.Alias[] sAliases;
+ private static final Map<String, FontFamily[]> sSystemFallbackMap;
+ private static final FontConfig.Alias[] sAliases;
+ private static final Set<Font> sAvailableFonts;
+
+ /**
+ * Returns all available font files in the system.
+ *
+ * Note: The order of this font doesn't indicates anything.
+ * @return an array of system fonts
+ */
+ public static @NonNull Set<Font> getAvailableFonts() {
+ return sAvailableFonts;
+ }
/**
* Returns fallback list for the given family name.
@@ -58,6 +72,7 @@ public class SystemFonts {
* If no fallback found for the given family name, returns fallback for the default family.
*
* @param familyName family name, e.g. "serif"
+ * @hide
*/
public static @NonNull FontFamily[] getSystemFallback(@Nullable String familyName) {
final FontFamily[] families = sSystemFallbackMap.get(familyName);
@@ -68,6 +83,7 @@ public class SystemFonts {
* Returns raw system fallback map.
*
* This method is intended to be used only by Typeface static initializer.
+ * @hide
*/
public static @NonNull Map<String, FontFamily[]> getRawSystemFallbackMap() {
return sSystemFallbackMap;
@@ -77,6 +93,7 @@ public class SystemFonts {
* Returns a list of aliases.
*
* This method is intended to be used only by Typeface static initializer.
+ * @hide
*/
public static @NonNull FontConfig.Alias[] getAliases() {
return sAliases;
@@ -96,9 +113,10 @@ public class SystemFonts {
private static void pushFamilyToFallback(@NonNull FontConfig.Family xmlFamily,
@NonNull ArrayMap<String, ArrayList<FontFamily>> fallbackMap,
@NonNull Map<String, ByteBuffer> cache,
- @NonNull String fontDir) {
+ @NonNull String fontDir,
+ @NonNull HashSet<Font> availableFonts) {
- final String[] languageTags = xmlFamily.getLanguages();
+ final String languageTags = xmlFamily.getLanguages();
final int variant = xmlFamily.getVariant();
final ArrayList<FontConfig.Font> defaultFonts = new ArrayList<>();
@@ -120,7 +138,8 @@ public class SystemFonts {
}
final FontFamily defaultFamily = defaultFonts.isEmpty() ? null : createFontFamily(
- xmlFamily.getName(), defaultFonts, languageTags, variant, cache, fontDir);
+ xmlFamily.getName(), defaultFonts, languageTags, variant, cache, fontDir,
+ availableFonts);
// Insert family into fallback map.
for (int i = 0; i < fallbackMap.size(); i++) {
@@ -132,7 +151,8 @@ public class SystemFonts {
}
} else {
final FontFamily family = createFontFamily(
- xmlFamily.getName(), fallback, languageTags, variant, cache, fontDir);
+ xmlFamily.getName(), fallback, languageTags, variant, cache, fontDir,
+ availableFonts);
if (family != null) {
fallbackMap.valueAt(i).add(family);
} else if (defaultFamily != null) {
@@ -146,15 +166,17 @@ public class SystemFonts {
private static @Nullable FontFamily createFontFamily(@NonNull String familyName,
@NonNull List<FontConfig.Font> fonts,
- @NonNull String[] languageTags,
+ @NonNull String languageTags,
@FontConfig.Family.Variant int variant,
@NonNull Map<String, ByteBuffer> cache,
- @NonNull String fontDir) {
+ @NonNull String fontDir,
+ @NonNull HashSet<Font> availableFonts) {
if (fonts.size() == 0) {
return null;
}
FontFamily.Builder b = null;
+ final LocaleList localeList = LocaleList.forLanguageTags(languageTags);
for (int i = 0; i < fonts.size(); i++) {
final FontConfig.Font fontConfig = fonts.get(i);
final String fullPath = fontDir + fontConfig.getFontName();
@@ -172,7 +194,7 @@ public class SystemFonts {
final Font font;
try {
- font = new Font.Builder(buffer)
+ font = new Font.Builder(buffer, new File(fullPath), localeList)
.setWeight(fontConfig.getWeight())
.setItalic(fontConfig.isItalic())
.setTtcIndex(fontConfig.getTtcIndex())
@@ -182,6 +204,7 @@ public class SystemFonts {
throw new RuntimeException(e); // Never reaches here
}
+ availableFonts.add(font);
if (b == null) {
b = new FontFamily.Builder(font);
} else {
@@ -204,7 +227,8 @@ public class SystemFonts {
@VisibleForTesting
public static FontConfig.Alias[] buildSystemFallback(@NonNull String xmlPath,
@NonNull String fontDir,
- @NonNull ArrayMap<String, FontFamily[]> fallbackMap) {
+ @NonNull ArrayMap<String, FontFamily[]> fallbackMap,
+ @NonNull HashSet<Font> availableFonts) {
try {
final FileInputStream fontsIn = new FileInputStream(xmlPath);
final FontConfig fontConfig = FontListParser.parse(fontsIn);
@@ -221,7 +245,8 @@ public class SystemFonts {
}
final FontFamily family = createFontFamily(
xmlFamily.getName(), Arrays.asList(xmlFamily.getFonts()),
- xmlFamily.getLanguages(), xmlFamily.getVariant(), bufferCache, fontDir);
+ xmlFamily.getLanguages(), xmlFamily.getVariant(), bufferCache, fontDir,
+ availableFonts);
if (family == null) {
continue;
}
@@ -236,7 +261,8 @@ public class SystemFonts {
// The first family (usually the sans-serif family) is always placed immediately
// after the primary family in the fallback.
if (i == 0 || xmlFamily.getName() == null) {
- pushFamilyToFallback(xmlFamily, fallbackListMap, bufferCache, fontDir);
+ pushFamilyToFallback(xmlFamily, fallbackListMap, bufferCache, fontDir,
+ availableFonts);
}
}
@@ -258,9 +284,11 @@ public class SystemFonts {
static {
final ArrayMap<String, FontFamily[]> systemFallbackMap = new ArrayMap<>();
+ final HashSet<Font> availableFonts = new HashSet<>();
sAliases = buildSystemFallback("/system/etc/fonts.xml", "/system/fonts/",
- systemFallbackMap);
+ systemFallbackMap, availableFonts);
sSystemFallbackMap = Collections.unmodifiableMap(systemFallbackMap);
+ sAvailableFonts = Collections.unmodifiableSet(availableFonts);
}
}
diff --git a/keystore/java/android/security/KeyChain.java b/keystore/java/android/security/KeyChain.java
index 78dbb6ae0df3..5d5e40fd3ac3 100644
--- a/keystore/java/android/security/KeyChain.java
+++ b/keystore/java/android/security/KeyChain.java
@@ -40,6 +40,7 @@ import android.security.keystore.KeyProperties;
import java.io.ByteArrayInputStream;
import java.io.Closeable;
+import java.io.Serializable;
import java.security.KeyPair;
import java.security.Principal;
import java.security.PrivateKey;
@@ -55,6 +56,8 @@ import java.util.Locale;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
+import javax.security.auth.x500.X500Principal;
+
import com.android.org.conscrypt.TrustedCertificateStore;
/**
@@ -142,6 +145,18 @@ public final class KeyChain {
public static final String EXTRA_SENDER = "sender";
/**
+ * Extra for use with {@link #ACTION_CHOOSER}
+ * @hide Also used by KeyChainActivity implementation
+ */
+ public static final String EXTRA_KEY_TYPES = "key_types";
+
+ /**
+ * Extra for use with {@link #ACTION_CHOOSER}
+ * @hide Also used by KeyChainActivity implementation
+ */
+ public static final String EXTRA_ISSUERS = "issuers";
+
+ /**
* Action to bring up the CertInstaller.
*/
private static final String ACTION_INSTALL = "android.credentials.INSTALL";
@@ -365,9 +380,10 @@ public final class KeyChain {
* onChoosePrivateKeyAlias}.
*
* <p>{@code keyTypes} and {@code issuers} may be used to
- * highlight suggested choices to the user, although to cope with
- * sometimes erroneous values provided by servers, the user may be
- * able to override these suggestions.
+ * narrow down suggested choices to the user. If either {@code keyTypes}
+ * or {@code issuers} is specified and non-empty, and there are no
+ * matching certificates in the KeyChain, then the certificate
+ * selection prompt would be suppressed entirely.
*
* <p>{@code host} and {@code port} may be used to give the user
* more context about the server requesting the credentials.
@@ -382,7 +398,7 @@ public final class KeyChain {
* @param response Callback to invoke when the request completes;
* must not be null.
* @param keyTypes The acceptable types of asymmetric keys such as
- * "RSA" or "DSA", or null.
+ * "RSA", "EC" or null.
* @param issuers The acceptable certificate issuers for the
* certificate matching the private key, or null.
* @param host The host name of the server requesting the
@@ -419,9 +435,10 @@ public final class KeyChain {
* onChoosePrivateKeyAlias}.
*
* <p>{@code keyTypes} and {@code issuers} may be used to
- * highlight suggested choices to the user, although to cope with
- * sometimes erroneous values provided by servers, the user may be
- * able to override these suggestions.
+ * narrow down suggested choices to the user. If either {@code keyTypes}
+ * or {@code issuers} is specified and non-empty, and there are no
+ * matching certificates in the KeyChain, then the certificate
+ * selection prompt would be suppressed entirely.
*
* <p>{@code uri} may be used to give the user more context about
* the server requesting the credentials.
@@ -436,13 +453,15 @@ public final class KeyChain {
* @param response Callback to invoke when the request completes;
* must not be null.
* @param keyTypes The acceptable types of asymmetric keys such as
- * "EC" or "RSA", or null.
+ * "RSA", "EC" or null.
* @param issuers The acceptable certificate issuers for the
* certificate matching the private key, or null.
* @param uri The full URI the server is requesting the certificate
* for, or null if unavailable.
* @param alias The alias to preselect if available, or null if
* unavailable.
+ * @throws IllegalArgumentException if the specified issuers are not
+ * of type {@code X500Principal}.
*/
public static void choosePrivateKeyAlias(@NonNull Activity activity,
@NonNull KeyChainAliasCallback response,
@@ -450,20 +469,21 @@ public final class KeyChain {
@Nullable Principal[] issuers,
@Nullable Uri uri, @Nullable String alias) {
/*
- * TODO currently keyTypes, issuers are unused. They are meant
- * to follow the semantics and purpose of X509KeyManager
- * method arguments.
- *
- * keyTypes would allow the list to be filtered and typically
- * will be set correctly by the server. In practice today,
- * most all users will want only RSA or EC, and usually
- * only a small number of certs will be available.
+ * Specifying keyTypes excludes certificates with different key types
+ * from the list of certificates presented to the user.
+ * In practice today, most servers would require RSA or EC
+ * certificates.
*
- * issuers is typically not useful. Some servers historically
- * will send the entire list of public CAs known to the
- * server. Others will send none. If this is used, if there
- * are no matches after applying the constraint, it should be
- * ignored.
+ * Specifying issuers narrows down the list by filtering out
+ * certificates with issuers which are not matching the provided ones.
+ * This has been reported to Chrome several times (crbug.com/731769).
+ * There's no concrete description on what to do when the client has no
+ * certificates that match the provided issuers.
+ * To be conservative, Android will not present the user with any
+ * certificates to choose from.
+ * If the list of issuers is empty then the client may send any
+ * certificate, see:
+ * https://tools.ietf.org/html/rfc5246#section-7.4.4
*/
if (activity == null) {
throw new NullPointerException("activity == null");
@@ -476,6 +496,26 @@ public final class KeyChain {
intent.putExtra(EXTRA_RESPONSE, new AliasResponse(response));
intent.putExtra(EXTRA_URI, uri);
intent.putExtra(EXTRA_ALIAS, alias);
+ intent.putExtra(EXTRA_KEY_TYPES, keyTypes);
+ ArrayList<byte[]> issuersList = new ArrayList();
+ if (issuers != null) {
+ for (Principal issuer: issuers) {
+ // In a TLS client context (like Chrome), issuers would only
+ // be specified as X500Principals. No other use cases for
+ // specifying principals have been brought up. Under these
+ // circumstances, only allow issuers specified as
+ // X500Principals.
+ if (!(issuer instanceof X500Principal)) {
+ throw new IllegalArgumentException(String.format(
+ "Issuer %s is of type %s, not X500Principal",
+ issuer.toString(), issuer.getClass()));
+ }
+ // Pass the DER-encoded issuer as that's the most accurate
+ // representation and what is sent over the wire.
+ issuersList.add(((X500Principal) issuer).getEncoded());
+ }
+ }
+ intent.putExtra(EXTRA_ISSUERS, (Serializable) issuersList);
// the PendingIntent is used to get calling package name
intent.putExtra(EXTRA_SENDER, PendingIntent.getActivity(activity, 0, new Intent(), 0));
activity.startActivity(intent);
diff --git a/libs/hwui/Android.bp b/libs/hwui/Android.bp
index 2baacbf541dc..04bbe248263f 100644
--- a/libs/hwui/Android.bp
+++ b/libs/hwui/Android.bp
@@ -170,7 +170,6 @@ cc_defaults {
"pipeline/skia/SkiaDisplayList.cpp",
"pipeline/skia/SkiaMemoryTracer.cpp",
"pipeline/skia/SkiaOpenGLPipeline.cpp",
- "pipeline/skia/SkiaOpenGLReadback.cpp",
"pipeline/skia/SkiaPipeline.cpp",
"pipeline/skia/SkiaProfileRenderer.cpp",
"pipeline/skia/SkiaRecordingCanvas.cpp",
@@ -197,7 +196,6 @@ cc_defaults {
"utils/GLUtils.cpp",
"utils/LinearAllocator.cpp",
"utils/StringUtils.cpp",
- "utils/TestWindowContext.cpp",
"utils/VectorDrawableUtils.cpp",
"AnimationContext.cpp",
"Animator.cpp",
@@ -217,13 +215,13 @@ cc_defaults {
"Layer.cpp",
"LayerUpdateQueue.cpp",
"Matrix.cpp",
- "EglReadback.cpp",
"PathParser.cpp",
"ProfileData.cpp",
"ProfileDataContainer.cpp",
"Properties.cpp",
"PropertyValuesAnimatorSet.cpp",
"PropertyValuesHolder.cpp",
+ "Readback.cpp",
"RecordingCanvas.cpp",
"RenderNode.cpp",
"RenderProperties.cpp",
diff --git a/libs/hwui/DeferredLayerUpdater.cpp b/libs/hwui/DeferredLayerUpdater.cpp
index 00916559a9c2..837d5461d2a8 100644
--- a/libs/hwui/DeferredLayerUpdater.cpp
+++ b/libs/hwui/DeferredLayerUpdater.cpp
@@ -49,6 +49,7 @@ void DeferredLayerUpdater::destroyLayer() {
}
mLayer->postDecStrong();
+
mLayer = nullptr;
}
diff --git a/libs/hwui/EglReadback.cpp b/libs/hwui/EglReadback.cpp
deleted file mode 100644
index 65becf88b930..000000000000
--- a/libs/hwui/EglReadback.cpp
+++ /dev/null
@@ -1,95 +0,0 @@
-/*
- * Copyright (C) 2016 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.
- */
-
-#include "EglReadback.h"
-
-#include "renderthread/EglManager.h"
-
-#include <gui/Surface.h>
-#include <ui/Fence.h>
-#include <ui/GraphicBuffer.h>
-
-namespace android {
-namespace uirenderer {
-
-CopyResult EglReadback::copySurfaceInto(Surface& surface, const Rect& srcRect, SkBitmap* bitmap) {
- ATRACE_CALL();
- // Setup the source
- sp<GraphicBuffer> sourceBuffer;
- sp<Fence> sourceFence;
- Matrix4 texTransform;
- status_t err = surface.getLastQueuedBuffer(&sourceBuffer, &sourceFence, texTransform.data);
- texTransform.invalidateType();
- if (err != NO_ERROR) {
- ALOGW("Failed to get last queued buffer, error = %d", err);
- return CopyResult::UnknownError;
- }
- if (!sourceBuffer.get()) {
- ALOGW("Surface doesn't have any previously queued frames, nothing to readback from");
- return CopyResult::SourceEmpty;
- }
- if (sourceBuffer->getUsage() & GRALLOC_USAGE_PROTECTED) {
- ALOGW("Surface is protected, unable to copy from it");
- return CopyResult::SourceInvalid;
- }
- err = sourceFence->wait(500 /* ms */);
- if (err != NO_ERROR) {
- ALOGE("Timeout (500ms) exceeded waiting for buffer fence, abandoning readback attempt");
- return CopyResult::Timeout;
- }
-
- return copyGraphicBufferInto(sourceBuffer.get(), texTransform, srcRect, bitmap);
-}
-
-CopyResult EglReadback::copyGraphicBufferInto(GraphicBuffer* graphicBuffer, Matrix4& texTransform,
- const Rect& srcRect, SkBitmap* bitmap) {
- mRenderThread.requireGlContext();
- // TODO: Can't use Image helper since it forces GL_TEXTURE_2D usage via
- // GL_OES_EGL_image, which doesn't work since we need samplerExternalOES
- // to be able to properly sample from the buffer.
-
- // Create the EGLImage object that maps the GraphicBuffer
- EGLDisplay display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
- EGLClientBuffer clientBuffer = (EGLClientBuffer)graphicBuffer->getNativeBuffer();
- EGLint attrs[] = {EGL_IMAGE_PRESERVED_KHR, EGL_TRUE, EGL_NONE};
-
- EGLImageKHR sourceImage = eglCreateImageKHR(display, EGL_NO_CONTEXT, EGL_NATIVE_BUFFER_ANDROID,
- clientBuffer, attrs);
-
- if (sourceImage == EGL_NO_IMAGE_KHR) {
- ALOGW("eglCreateImageKHR failed (%#x)", eglGetError());
- return CopyResult::UnknownError;
- }
-
- uint32_t width = graphicBuffer->getWidth();
- uint32_t height = graphicBuffer->getHeight();
- CopyResult copyResult =
- copyImageInto(sourceImage, texTransform, width, height, srcRect, bitmap);
-
- eglDestroyImageKHR(display, sourceImage);
- return copyResult;
-}
-
-CopyResult EglReadback::copyGraphicBufferInto(GraphicBuffer* graphicBuffer, SkBitmap* bitmap) {
- Rect srcRect;
- Matrix4 transform;
- transform.loadScale(1, -1, 1);
- transform.translate(0, -1);
- return copyGraphicBufferInto(graphicBuffer, transform, srcRect, bitmap);
-}
-
-} // namespace uirenderer
-} // namespace android
diff --git a/libs/hwui/EglReadback.h b/libs/hwui/EglReadback.h
deleted file mode 100644
index e723169ad795..000000000000
--- a/libs/hwui/EglReadback.h
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * Copyright (C) 2016 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.
- */
-
-#pragma once
-
-#include "Readback.h"
-
-#include "Matrix.h"
-
-#include <EGL/egl.h>
-#include <EGL/eglext.h>
-
-namespace android {
-namespace uirenderer {
-
-class EglReadback : public Readback {
-public:
- virtual CopyResult copySurfaceInto(Surface& surface, const Rect& srcRect,
- SkBitmap* bitmap) override;
- virtual CopyResult copyGraphicBufferInto(GraphicBuffer* graphicBuffer,
- SkBitmap* bitmap) override;
-
-protected:
- explicit EglReadback(renderthread::RenderThread& thread) : Readback(thread) {}
- virtual ~EglReadback() {}
-
- virtual CopyResult copyImageInto(EGLImageKHR eglImage, const Matrix4& imgTransform,
- int imgWidth, int imgHeight, const Rect& srcRect,
- SkBitmap* bitmap) = 0;
-
-private:
- CopyResult copyGraphicBufferInto(GraphicBuffer* graphicBuffer, Matrix4& texTransform,
- const Rect& srcRect, SkBitmap* bitmap);
-};
-
-} // namespace uirenderer
-} // namespace android
diff --git a/libs/hwui/Layer.cpp b/libs/hwui/Layer.cpp
index f59a2e6ee5c1..cc95051fc952 100644
--- a/libs/hwui/Layer.cpp
+++ b/libs/hwui/Layer.cpp
@@ -26,8 +26,7 @@ namespace uirenderer {
Layer::Layer(RenderState& renderState, sk_sp<SkColorFilter> colorFilter, int alpha,
SkBlendMode mode)
- : GpuMemoryTracker(GpuObjectType::Layer)
- , mRenderState(renderState)
+ : mRenderState(renderState)
, mColorFilter(colorFilter)
, alpha(alpha)
, mode(mode) {
diff --git a/libs/hwui/Layer.h b/libs/hwui/Layer.h
index c4e4c1c96ba6..6f07a43ceb58 100644
--- a/libs/hwui/Layer.h
+++ b/libs/hwui/Layer.h
@@ -16,7 +16,6 @@
#pragma once
-#include <GpuMemoryTracker.h>
#include <utils/RefBase.h>
#include <SkBlendMode.h>
@@ -39,21 +38,21 @@ class RenderState;
/**
* A layer has dimensions and is backed by a backend specific texture or framebuffer.
*/
-class Layer : public VirtualLightRefBase, GpuMemoryTracker {
+class Layer : public VirtualLightRefBase {
public:
Layer(RenderState& renderState, sk_sp<SkColorFilter>, int alpha, SkBlendMode mode);
~Layer();
- virtual uint32_t getWidth() const { return mWidth; }
+ uint32_t getWidth() const { return mWidth; }
- virtual uint32_t getHeight() const { return mHeight; }
+ uint32_t getHeight() const { return mHeight; }
- virtual void setSize(uint32_t width, uint32_t height) { mWidth = width; mHeight = height; }
+ void setSize(uint32_t width, uint32_t height) { mWidth = width; mHeight = height; }
- virtual void setBlend(bool blend) { mBlend = blend; }
+ void setBlend(bool blend) { mBlend = blend; }
- virtual bool isBlend() const { return mBlend; }
+ bool isBlend() const { return mBlend; }
inline void setForceFilter(bool forceFilter) { this->forceFilter = forceFilter; }
diff --git a/libs/hwui/Readback.cpp b/libs/hwui/Readback.cpp
new file mode 100644
index 000000000000..80f2b5714659
--- /dev/null
+++ b/libs/hwui/Readback.cpp
@@ -0,0 +1,287 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "Readback.h"
+
+#include "pipeline/skia/LayerDrawable.h"
+#include "renderthread/EglManager.h"
+#include "renderthread/VulkanManager.h"
+
+#include <SkToSRGBColorFilter.h>
+#include <gui/Surface.h>
+#include <ui/Fence.h>
+#include <ui/GraphicBuffer.h>
+#include "DeferredLayerUpdater.h"
+#include "Properties.h"
+#include "hwui/Bitmap.h"
+#include "utils/Color.h"
+#include "utils/MathUtils.h"
+
+using namespace android::uirenderer::renderthread;
+
+namespace android {
+namespace uirenderer {
+
+CopyResult Readback::copySurfaceInto(Surface& surface, const Rect& srcRect, SkBitmap* bitmap) {
+ ATRACE_CALL();
+ // Setup the source
+ sp<GraphicBuffer> sourceBuffer;
+ sp<Fence> sourceFence;
+ Matrix4 texTransform;
+ status_t err = surface.getLastQueuedBuffer(&sourceBuffer, &sourceFence, texTransform.data);
+ texTransform.invalidateType();
+ if (err != NO_ERROR) {
+ ALOGW("Failed to get last queued buffer, error = %d", err);
+ return CopyResult::UnknownError;
+ }
+ if (!sourceBuffer.get()) {
+ ALOGW("Surface doesn't have any previously queued frames, nothing to readback from");
+ return CopyResult::SourceEmpty;
+ }
+ if (sourceBuffer->getUsage() & GRALLOC_USAGE_PROTECTED) {
+ ALOGW("Surface is protected, unable to copy from it");
+ return CopyResult::SourceInvalid;
+ }
+ err = sourceFence->wait(500 /* ms */);
+ if (err != NO_ERROR) {
+ ALOGE("Timeout (500ms) exceeded waiting for buffer fence, abandoning readback attempt");
+ return CopyResult::Timeout;
+ }
+ if (!sourceBuffer.get()) {
+ return CopyResult::UnknownError;
+ }
+
+ sk_sp<SkColorSpace> colorSpace =
+ DataSpaceToColorSpace(static_cast<android_dataspace>(surface.getBuffersDataSpace()));
+ sk_sp<SkColorFilter> colorSpaceFilter;
+ if (colorSpace && !colorSpace->isSRGB()) {
+ colorSpaceFilter = SkToSRGBColorFilter::Make(colorSpace);
+ }
+ sk_sp<SkImage> image = SkImage::MakeFromAHardwareBuffer(
+ reinterpret_cast<AHardwareBuffer*>(sourceBuffer.get()), kPremul_SkAlphaType);
+ return copyImageInto(image, colorSpaceFilter, texTransform, srcRect, bitmap);
+}
+
+CopyResult Readback::copyHWBitmapInto(Bitmap* hwBitmap, SkBitmap* bitmap) {
+ LOG_ALWAYS_FATAL_IF(!hwBitmap->isHardware());
+
+ Rect srcRect;
+ Matrix4 transform;
+ transform.loadScale(1, -1, 1);
+ transform.translate(0, -1);
+
+ // TODO: Try to take and reuse the image inside HW bitmap with "hwBitmap->makeImage".
+ // TODO: When this was attempted, it resulted in instability.
+ sk_sp<SkColorFilter> colorSpaceFilter;
+ sk_sp<SkColorSpace> colorSpace = hwBitmap->info().refColorSpace();
+ if (colorSpace && !colorSpace->isSRGB()) {
+ colorSpaceFilter = SkToSRGBColorFilter::Make(colorSpace);
+ }
+ sk_sp<SkImage> image = SkImage::MakeFromAHardwareBuffer(
+ reinterpret_cast<AHardwareBuffer*>(hwBitmap->graphicBuffer()), kPremul_SkAlphaType);
+
+ // HW Bitmap currently can only attach to a GraphicBuffer with PIXEL_FORMAT_RGBA_8888 format
+ // and SRGB color space. ImageDecoder can create a new HW Bitmap with non-SRGB color space: for
+ // example see android.graphics.cts.BitmapColorSpaceTest#testEncodeP3hardware test.
+ return copyImageInto(image, colorSpaceFilter, transform, srcRect, bitmap);
+}
+
+CopyResult Readback::copyLayerInto(DeferredLayerUpdater* deferredLayer, SkBitmap* bitmap) {
+ if (!mRenderThread.getGrContext()) {
+ return CopyResult::UnknownError;
+ }
+
+ // acquire most recent buffer for drawing
+ deferredLayer->updateTexImage();
+ deferredLayer->apply();
+ const SkRect dstRect = SkRect::MakeIWH(bitmap->width(), bitmap->height());
+ CopyResult copyResult = CopyResult::UnknownError;
+ Layer* layer = deferredLayer->backingLayer();
+ if (layer) {
+ if (copyLayerInto(layer, nullptr, &dstRect, bitmap)) {
+ copyResult = CopyResult::Success;
+ }
+ }
+ return copyResult;
+}
+
+CopyResult Readback::copyImageInto(const sk_sp<SkImage>& image,
+ sk_sp<SkColorFilter>& colorSpaceFilter, Matrix4& texTransform,
+ const Rect& srcRect, SkBitmap* bitmap) {
+ if (Properties::getRenderPipelineType() == RenderPipelineType::SkiaGL) {
+ mRenderThread.requireGlContext();
+ } else {
+ mRenderThread.vulkanManager().initialize();
+ }
+ if (!image.get()) {
+ return CopyResult::UnknownError;
+ }
+ int imgWidth = image->width();
+ int imgHeight = image->height();
+ sk_sp<GrContext> grContext = sk_ref_sp(mRenderThread.getGrContext());
+
+ if (bitmap->colorType() == kRGBA_F16_SkColorType &&
+ !grContext->colorTypeSupportedAsSurface(bitmap->colorType())) {
+ ALOGW("Can't copy surface into bitmap, RGBA_F16 config is not supported");
+ return CopyResult::DestinationInvalid;
+ }
+
+ CopyResult copyResult = CopyResult::UnknownError;
+
+ int displayedWidth = imgWidth, displayedHeight = imgHeight;
+ // If this is a 90 or 270 degree rotation we need to swap width/height to get the device
+ // size.
+ if (texTransform[Matrix4::kSkewX] >= 0.5f || texTransform[Matrix4::kSkewX] <= -0.5f) {
+ std::swap(displayedWidth, displayedHeight);
+ }
+ SkRect skiaDestRect = SkRect::MakeWH(bitmap->width(), bitmap->height());
+ SkRect skiaSrcRect = srcRect.toSkRect();
+ if (skiaSrcRect.isEmpty()) {
+ skiaSrcRect = SkRect::MakeIWH(displayedWidth, displayedHeight);
+ }
+ bool srcNotEmpty = skiaSrcRect.intersect(SkRect::MakeIWH(displayedWidth, displayedHeight));
+ if (!srcNotEmpty) {
+ return copyResult;
+ }
+
+ // See Readback::copyLayerInto for an overview of color space conversion.
+ // HW Bitmap are allowed to be in a non-SRGB color space (for example coming from ImageDecoder).
+ // For Surface and HW Bitmap readback flows we pass colorSpaceFilter, which does the conversion.
+ // TextureView readback is using Layer::setDataSpace, which creates a SkColorFilter internally.
+ Layer layer(mRenderThread.renderState(), colorSpaceFilter, 255, SkBlendMode::kSrc);
+ bool disableFilter = MathUtils::areEqual(skiaSrcRect.width(), skiaDestRect.width()) &&
+ MathUtils::areEqual(skiaSrcRect.height(), skiaDestRect.height());
+ layer.setForceFilter(!disableFilter);
+ layer.setSize(displayedWidth, displayedHeight);
+ texTransform.copyTo(layer.getTexTransform());
+ layer.setImage(image);
+ if (copyLayerInto(&layer, &skiaSrcRect, &skiaDestRect, bitmap)) {
+ copyResult = CopyResult::Success;
+ }
+
+ return copyResult;
+}
+
+bool Readback::copyLayerInto(Layer* layer, const SkRect* srcRect, const SkRect* dstRect,
+ SkBitmap* bitmap) {
+ /*
+ * In the past only TextureView readback was setting the temporary surface color space to null.
+ * Now all 3 readback flows are drawing into a SkSurface with null color space.
+ * At readback there are 3 options to convert the source image color space to the destination
+ * color space requested in "bitmap->info().colorSpace()":
+ * 1. Set color space for temporary surface render target to null (disables color management),
+ * colorspace tag from source SkImage is ignored by Skia,
+ * convert SkImage to SRGB at draw time with SkColorFilter/SkToSRGBColorFilter,
+ * do a readback from temporary SkSurface to a temporary SRGB SkBitmap "bitmap2",
+ * read back from SRGB "bitmap2" into non-SRGB "bitmap" which will do a CPU color conversion.
+ *
+ * 2. Set color space for temporary surface render target to SRGB (not nullptr),
+ * colorspace tag on the source SkImage is used by Skia to enable conversion,
+ * convert SkImage to SRGB at draw time with drawImage (no filters),
+ * do a readback from temporary SkSurface, which will do a color conversion from SRGB to
+ * bitmap->info().colorSpace() on the CPU.
+ *
+ * 3. Set color space for temporary surface render target to bitmap->info().colorSpace(),
+ * colorspace tag on the source SkImage is used by Skia to enable conversion,
+ * convert SkImage to bitmap->info().colorSpace() at draw time with drawImage (no filters),
+ * do a readback from SkSurface, which will not do any color conversion, because
+ * surface was created with the same color space as the "bitmap".
+ *
+ * Option 1 is used for all readback flows.
+ * Options 2 and 3 are new, because skia added support for non-SRGB render targets without
+ * linear blending.
+ * TODO: evaluate if options 2 or 3 for color space conversion are better.
+ */
+
+ // drop the colorSpace from the temporary surface.
+ SkImageInfo surfaceInfo = bitmap->info().makeColorSpace(nullptr);
+
+ /* This intermediate surface is present to work around a bug in SwiftShader that
+ * prevents us from reading the contents of the layer's texture directly. The
+ * workaround involves first rendering that texture into an intermediate buffer and
+ * then reading from the intermediate buffer into the bitmap.
+ * Another reason to render in an offscreen buffer is to scale and to avoid an issue b/62262733
+ * with reading incorrect data from EGLImage backed SkImage (likely a driver bug).
+ */
+ sk_sp<SkSurface> tmpSurface = SkSurface::MakeRenderTarget(mRenderThread.getGrContext(),
+ SkBudgeted::kYes, surfaceInfo);
+
+ if (!tmpSurface.get()) {
+ surfaceInfo = surfaceInfo.makeColorType(SkColorType::kN32_SkColorType);
+ tmpSurface = SkSurface::MakeRenderTarget(mRenderThread.getGrContext(), SkBudgeted::kYes,
+ surfaceInfo);
+ if (!tmpSurface.get()) {
+ ALOGW("Unable to readback GPU contents into the provided bitmap");
+ return false;
+ }
+ }
+
+ if (skiapipeline::LayerDrawable::DrawLayer(mRenderThread.getGrContext(),
+ tmpSurface->getCanvas(), layer, srcRect, dstRect,
+ false)) {
+ // If bitmap->info().colorSpace() is non-SRGB, convert the data from SRGB to non-SRGB on
+ // CPU. We can't just pass bitmap->info() to SkSurface::readPixels, because "tmpSurface" has
+ // disabled color conversion.
+ SkColorSpace* destColorSpace = bitmap->info().colorSpace();
+ SkBitmap tempSRGBBitmap;
+ SkBitmap tmpN32Bitmap;
+ SkBitmap* bitmapInSRGB;
+ if (destColorSpace && !destColorSpace->isSRGB()) {
+ tempSRGBBitmap.allocPixels(bitmap->info().makeColorSpace(SkColorSpace::MakeSRGB()));
+ bitmapInSRGB = &tempSRGBBitmap; // Need to convert latter from SRGB to non-SRGB.
+ } else {
+ bitmapInSRGB = bitmap; // No need for color conversion - write directly into output.
+ }
+ bool success = false;
+
+ // TODO: does any of the readbacks below clamp F16 exSRGB?
+ // Readback into a SRGB SkBitmap.
+ if (tmpSurface->readPixels(bitmapInSRGB->info(), bitmapInSRGB->getPixels(),
+ bitmapInSRGB->rowBytes(), 0, 0)) {
+ success = true;
+ } else {
+ // if we fail to readback from the GPU directly (e.g. 565) then we attempt to read into
+ // 8888 and then convert that into the destination format before giving up.
+ SkImageInfo bitmapInfo =
+ SkImageInfo::MakeN32(bitmap->width(), bitmap->height(), bitmap->alphaType(),
+ SkColorSpace::MakeSRGB());
+ if (tmpN32Bitmap.tryAllocPixels(bitmapInfo) &&
+ tmpSurface->readPixels(bitmapInfo, tmpN32Bitmap.getPixels(),
+ tmpN32Bitmap.rowBytes(), 0, 0)) {
+ success = true;
+ bitmapInSRGB = &tmpN32Bitmap;
+ }
+ }
+
+ if (success) {
+ if (bitmapInSRGB != bitmap) {
+ // Convert from SRGB to non-SRGB color space if needed. Convert from N32 to
+ // destination bitmap color format if needed.
+ if (!bitmapInSRGB->readPixels(bitmap->info(), bitmap->getPixels(),
+ bitmap->rowBytes(), 0, 0)) {
+ return false;
+ }
+ }
+ bitmap->notifyPixelsChanged();
+ return true;
+ }
+ }
+
+ return false;
+}
+
+} /* namespace uirenderer */
+} /* namespace android */
diff --git a/libs/hwui/Readback.h b/libs/hwui/Readback.h
index ad3a8b690617..d9e10cedc0e8 100644
--- a/libs/hwui/Readback.h
+++ b/libs/hwui/Readback.h
@@ -16,16 +16,21 @@
#pragma once
+#include "Matrix.h"
#include "Rect.h"
#include "renderthread/RenderThread.h"
#include <SkBitmap.h>
namespace android {
+class Bitmap;
class GraphicBuffer;
class Surface;
namespace uirenderer {
+class DeferredLayerUpdater;
+class Layer;
+
// Keep in sync with PixelCopy.java codes
enum class CopyResult {
Success = 0,
@@ -38,15 +43,22 @@ enum class CopyResult {
class Readback {
public:
+ explicit Readback(renderthread::RenderThread& thread) : mRenderThread(thread) {}
/**
* Copies the surface's most recently queued buffer into the provided bitmap.
*/
- virtual CopyResult copySurfaceInto(Surface& surface, const Rect& srcRect, SkBitmap* bitmap) = 0;
- virtual CopyResult copyGraphicBufferInto(GraphicBuffer* graphicBuffer, SkBitmap* bitmap) = 0;
+ CopyResult copySurfaceInto(Surface& surface, const Rect& srcRect, SkBitmap* bitmap);
-protected:
- explicit Readback(renderthread::RenderThread& thread) : mRenderThread(thread) {}
- virtual ~Readback() {}
+ CopyResult copyHWBitmapInto(Bitmap* hwBitmap, SkBitmap* bitmap);
+
+ CopyResult copyLayerInto(DeferredLayerUpdater* layer, SkBitmap* bitmap);
+
+private:
+ CopyResult copyImageInto(const sk_sp<SkImage>& image, sk_sp<SkColorFilter>& colorSpaceFilter,
+ Matrix4& texTransform, const Rect& srcRect, SkBitmap* bitmap);
+
+ bool copyLayerInto(Layer* layer, const SkRect* srcRect, const SkRect* dstRect,
+ SkBitmap* bitmap);
renderthread::RenderThread& mRenderThread;
};
diff --git a/libs/hwui/hwui/Bitmap.cpp b/libs/hwui/hwui/Bitmap.cpp
index 3939696692d2..440620a6a417 100644
--- a/libs/hwui/hwui/Bitmap.cpp
+++ b/libs/hwui/hwui/Bitmap.cpp
@@ -290,7 +290,7 @@ void Bitmap::getSkBitmap(SkBitmap* outBitmap) {
if (isHardware()) {
outBitmap->allocPixels(SkImageInfo::Make(info().width(), info().height(),
info().colorType(), info().alphaType(), nullptr));
- uirenderer::renderthread::RenderProxy::copyGraphicBufferInto(graphicBuffer(), outBitmap);
+ uirenderer::renderthread::RenderProxy::copyHWBitmapInto(this, outBitmap);
if (mInfo.colorSpace()) {
sk_sp<SkPixelRef> pixelRef = sk_ref_sp(outBitmap->pixelRef());
outBitmap->setInfo(mInfo);
diff --git a/libs/hwui/pipeline/skia/LayerDrawable.cpp b/libs/hwui/pipeline/skia/LayerDrawable.cpp
index b6cd4b08e5fe..3ca0f8139c02 100644
--- a/libs/hwui/pipeline/skia/LayerDrawable.cpp
+++ b/libs/hwui/pipeline/skia/LayerDrawable.cpp
@@ -28,12 +28,13 @@ namespace skiapipeline {
void LayerDrawable::onDraw(SkCanvas* canvas) {
Layer* layer = mLayerUpdater->backingLayer();
if (layer) {
- DrawLayer(canvas->getGrContext(), canvas, layer);
+ DrawLayer(canvas->getGrContext(), canvas, layer, nullptr, nullptr, true);
}
}
bool LayerDrawable::DrawLayer(GrContext* context, SkCanvas* canvas, Layer* layer,
- const SkRect* dstRect) {
+ const SkRect* srcRect, const SkRect* dstRect,
+ bool useLayerTransform) {
if (context == nullptr) {
SkDEBUGF(("Attempting to draw LayerDrawable into an unsupported surface"));
return false;
@@ -60,12 +61,10 @@ bool LayerDrawable::DrawLayer(GrContext* context, SkCanvas* canvas, Layer* layer
}
SkMatrix matrix;
- if (dstRect) {
- // Destination rectangle is set only when we are trying to read back the content
- // of the layer. In this case we don't want to apply layer transform.
- matrix = textureMatrix;
- } else {
+ if (useLayerTransform) {
matrix = SkMatrix::Concat(layerTransform, textureMatrix);
+ } else {
+ matrix = textureMatrix;
}
SkPaint paint;
@@ -81,16 +80,26 @@ bool LayerDrawable::DrawLayer(GrContext* context, SkCanvas* canvas, Layer* layer
canvas->save();
canvas->concat(matrix);
}
- if (dstRect) {
+ if (dstRect || srcRect) {
SkMatrix matrixInv;
if (!matrix.invert(&matrixInv)) {
matrixInv = matrix;
}
- SkRect srcRect = SkRect::MakeIWH(layerWidth, layerHeight);
- matrixInv.mapRect(&srcRect);
- SkRect skiaDestRect = *dstRect;
+ SkRect skiaSrcRect;
+ if (srcRect) {
+ skiaSrcRect = *srcRect;
+ } else {
+ skiaSrcRect = SkRect::MakeIWH(layerWidth, layerHeight);
+ }
+ matrixInv.mapRect(&skiaSrcRect);
+ SkRect skiaDestRect;
+ if (dstRect) {
+ skiaDestRect = *dstRect;
+ } else {
+ skiaDestRect = SkRect::MakeIWH(layerWidth, layerHeight);
+ }
matrixInv.mapRect(&skiaDestRect);
- canvas->drawImageRect(layerImage.get(), srcRect, skiaDestRect, &paint,
+ canvas->drawImageRect(layerImage.get(), skiaSrcRect, skiaDestRect, &paint,
SkCanvas::kFast_SrcRectConstraint);
} else {
canvas->drawImage(layerImage.get(), 0, 0, &paint);
diff --git a/libs/hwui/pipeline/skia/LayerDrawable.h b/libs/hwui/pipeline/skia/LayerDrawable.h
index 18d118405a39..5c125908ffb2 100644
--- a/libs/hwui/pipeline/skia/LayerDrawable.h
+++ b/libs/hwui/pipeline/skia/LayerDrawable.h
@@ -33,7 +33,7 @@ public:
explicit LayerDrawable(DeferredLayerUpdater* layerUpdater) : mLayerUpdater(layerUpdater) {}
static bool DrawLayer(GrContext* context, SkCanvas* canvas, Layer* layer,
- const SkRect* dstRect = nullptr);
+ const SkRect* srcRect, const SkRect* dstRect, bool useLayerTransform);
protected:
virtual SkRect onGetBounds() override {
diff --git a/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp b/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp
index 2ae37233098e..d58b59e83380 100644
--- a/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp
+++ b/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp
@@ -127,65 +127,6 @@ bool SkiaOpenGLPipeline::swapBuffers(const Frame& frame, bool drew, const SkRect
return *requireSwap;
}
-bool SkiaOpenGLPipeline::copyLayerInto(DeferredLayerUpdater* deferredLayer, SkBitmap* bitmap) {
- if (!mRenderThread.getGrContext()) {
- return false;
- }
-
- // acquire most recent buffer for drawing
- deferredLayer->updateTexImage();
- deferredLayer->apply();
-
- // drop the colorSpace as we only support readback into sRGB or extended sRGB
- SkImageInfo surfaceInfo = bitmap->info().makeColorSpace(nullptr);
-
- /* This intermediate surface is present to work around a bug in SwiftShader that
- * prevents us from reading the contents of the layer's texture directly. The
- * workaround involves first rendering that texture into an intermediate buffer and
- * then reading from the intermediate buffer into the bitmap.
- */
- sk_sp<SkSurface> tmpSurface = SkSurface::MakeRenderTarget(mRenderThread.getGrContext(),
- SkBudgeted::kYes, surfaceInfo);
-
- if (!tmpSurface.get()) {
- surfaceInfo = surfaceInfo.makeColorType(SkColorType::kN32_SkColorType);
- tmpSurface = SkSurface::MakeRenderTarget(mRenderThread.getGrContext(), SkBudgeted::kYes,
- surfaceInfo);
- if (!tmpSurface.get()) {
- ALOGW("Unable to readback GPU contents into the provided bitmap");
- return false;
- }
- }
-
- Layer* layer = deferredLayer->backingLayer();
- const SkRect dstRect = SkRect::MakeIWH(bitmap->width(), bitmap->height());
- if (LayerDrawable::DrawLayer(mRenderThread.getGrContext(), tmpSurface->getCanvas(), layer,
- &dstRect)) {
- sk_sp<SkImage> tmpImage = tmpSurface->makeImageSnapshot();
- if (tmpImage->readPixels(surfaceInfo, bitmap->getPixels(), bitmap->rowBytes(), 0, 0)) {
- bitmap->notifyPixelsChanged();
- return true;
- }
-
- // if we fail to readback from the GPU directly (e.g. 565) then we attempt to read into 8888
- // and then draw that into the destination format before giving up.
- SkBitmap tmpBitmap;
- SkImageInfo bitmapInfo =
- SkImageInfo::MakeN32(bitmap->width(), bitmap->height(), bitmap->alphaType());
- if (tmpBitmap.tryAllocPixels(bitmapInfo) &&
- tmpImage->readPixels(bitmapInfo, tmpBitmap.getPixels(), tmpBitmap.rowBytes(), 0, 0)) {
- SkCanvas canvas(*bitmap);
- SkPaint paint;
- paint.setBlendMode(SkBlendMode::kSrc);
- canvas.drawBitmap(tmpBitmap, 0, 0, &paint);
- bitmap->notifyPixelsChanged();
- return true;
- }
- }
-
- return false;
-}
-
DeferredLayerUpdater* SkiaOpenGLPipeline::createTextureLayer() {
mRenderThread.requireGlContext();
return new DeferredLayerUpdater(mRenderThread.renderState());
diff --git a/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.h b/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.h
index 2e2e1522b717..808685ad4460 100644
--- a/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.h
+++ b/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.h
@@ -40,7 +40,6 @@ public:
FrameInfoVisualizer* profiler) override;
bool swapBuffers(const renderthread::Frame& frame, bool drew, const SkRect& screenDirty,
FrameInfo* currentFrameInfo, bool* requireSwap) override;
- bool copyLayerInto(DeferredLayerUpdater* layer, SkBitmap* bitmap) override;
DeferredLayerUpdater* createTextureLayer() override;
bool setSurface(Surface* window, renderthread::SwapBehavior swapBehavior,
renderthread::ColorMode colorMode) override;
diff --git a/libs/hwui/pipeline/skia/SkiaOpenGLReadback.cpp b/libs/hwui/pipeline/skia/SkiaOpenGLReadback.cpp
deleted file mode 100644
index f2f5056bb195..000000000000
--- a/libs/hwui/pipeline/skia/SkiaOpenGLReadback.cpp
+++ /dev/null
@@ -1,147 +0,0 @@
-/*
- * Copyright (C) 2016 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.
- */
-
-#include "SkiaOpenGLReadback.h"
-
-#include <GLES2/gl2.h>
-#include <GLES2/gl2ext.h>
-#include <GrBackendSurface.h>
-#include <SkCanvas.h>
-#include <SkSurface.h>
-#include <gl/GrGLInterface.h>
-#include <gl/GrGLTypes.h>
-#include "DeviceInfo.h"
-#include "Matrix.h"
-#include "Properties.h"
-#include "utils/MathUtils.h"
-
-using namespace android::uirenderer::renderthread;
-
-namespace android {
-namespace uirenderer {
-namespace skiapipeline {
-
-CopyResult SkiaOpenGLReadback::copyImageInto(EGLImageKHR eglImage, const Matrix4& imgTransform,
- int imgWidth, int imgHeight, const Rect& srcRect,
- SkBitmap* bitmap) {
- GLuint sourceTexId;
- glGenTextures(1, &sourceTexId);
- glBindTexture(GL_TEXTURE_EXTERNAL_OES, sourceTexId);
- glEGLImageTargetTexture2DOES(GL_TEXTURE_EXTERNAL_OES, eglImage);
-
- sk_sp<GrContext> grContext = sk_ref_sp(mRenderThread.getGrContext());
- if (Properties::getRenderPipelineType() == RenderPipelineType::SkiaVulkan) {
- sk_sp<const GrGLInterface> glInterface(GrGLCreateNativeInterface());
- LOG_ALWAYS_FATAL_IF(!glInterface.get());
- grContext = GrContext::MakeGL(std::move(glInterface));
- } else {
- grContext->resetContext();
- }
-
- if (bitmap->colorType() == kRGBA_F16_SkColorType &&
- !grContext->colorTypeSupportedAsSurface(bitmap->colorType())) {
- ALOGW("Can't copy surface into bitmap, RGBA_F16 config is not supported");
- return CopyResult::DestinationInvalid;
- }
-
- GrGLTextureInfo externalTexture;
- externalTexture.fTarget = GL_TEXTURE_EXTERNAL_OES;
- externalTexture.fID = sourceTexId;
- switch (bitmap->colorType()) {
- case kRGBA_F16_SkColorType:
- externalTexture.fFormat = GL_RGBA16F;
- break;
- case kN32_SkColorType:
- default:
- externalTexture.fFormat = GL_RGBA8;
- break;
- }
-
- GrBackendTexture backendTexture(imgWidth, imgHeight, GrMipMapped::kNo, externalTexture);
-
- CopyResult copyResult = CopyResult::UnknownError;
- sk_sp<SkImage> image(SkImage::MakeFromAdoptedTexture(grContext.get(), backendTexture,
- kTopLeft_GrSurfaceOrigin,
- bitmap->colorType()));
- if (image) {
- int displayedWidth = imgWidth, displayedHeight = imgHeight;
- // If this is a 90 or 270 degree rotation we need to swap width/height to get the device
- // size.
- if (imgTransform[Matrix4::kSkewX] >= 0.5f || imgTransform[Matrix4::kSkewX] <= -0.5f) {
- std::swap(displayedWidth, displayedHeight);
- }
- SkRect skiaDestRect = SkRect::MakeWH(bitmap->width(), bitmap->height());
- SkRect skiaSrcRect = srcRect.toSkRect();
- if (skiaSrcRect.isEmpty()) {
- skiaSrcRect = SkRect::MakeIWH(displayedWidth, displayedHeight);
- }
- bool srcNotEmpty = skiaSrcRect.intersect(SkRect::MakeIWH(displayedWidth, displayedHeight));
-
- if (srcNotEmpty) {
- SkMatrix textureMatrixInv;
- imgTransform.copyTo(textureMatrixInv);
- // TODO: after skia bug https://bugs.chromium.org/p/skia/issues/detail?id=7075 is fixed
- // use bottom left origin and remove flipV and invert transformations.
- SkMatrix flipV;
- flipV.setAll(1, 0, 0, 0, -1, 1, 0, 0, 1);
- textureMatrixInv.preConcat(flipV);
- textureMatrixInv.preScale(1.0f / displayedWidth, 1.0f / displayedHeight);
- textureMatrixInv.postScale(imgWidth, imgHeight);
- SkMatrix textureMatrix;
- if (!textureMatrixInv.invert(&textureMatrix)) {
- textureMatrix = textureMatrixInv;
- }
-
- textureMatrixInv.mapRect(&skiaSrcRect);
- textureMatrixInv.mapRect(&skiaDestRect);
-
- // we render in an offscreen buffer to scale and to avoid an issue b/62262733
- // with reading incorrect data from EGLImage backed SkImage (likely a driver bug)
- sk_sp<SkSurface> scaledSurface =
- SkSurface::MakeRenderTarget(grContext.get(), SkBudgeted::kYes, bitmap->info());
- SkPaint paint;
- paint.setBlendMode(SkBlendMode::kSrc);
- // Apply a filter, which is matching OpenGL pipeline readback behaviour. Filter usage
- // is codified by tests using golden images like DecodeAccuracyTest.
- bool disableFilter = MathUtils::areEqual(skiaSrcRect.width(), skiaDestRect.width())
- && MathUtils::areEqual(skiaSrcRect.height(), skiaDestRect.height());
- if (!disableFilter) {
- paint.setFilterQuality(kLow_SkFilterQuality);
- }
- scaledSurface->getCanvas()->concat(textureMatrix);
- scaledSurface->getCanvas()->drawImageRect(image, skiaSrcRect, skiaDestRect, &paint,
- SkCanvas::kFast_SrcRectConstraint);
-
- image = scaledSurface->makeImageSnapshot();
-
- if (image->readPixels(bitmap->info(), bitmap->getPixels(), bitmap->rowBytes(), 0, 0)) {
- bitmap->notifyPixelsChanged();
- copyResult = CopyResult::Success;
- }
- }
- }
-
- // make sure that we have deleted the texture (in the SkImage) before we
- // destroy the EGLImage that it was created from
- image.reset();
- glFinish();
-
- return copyResult;
-}
-
-} /* namespace skiapipeline */
-} /* namespace uirenderer */
-} /* namespace android */
diff --git a/libs/hwui/pipeline/skia/SkiaOpenGLReadback.h b/libs/hwui/pipeline/skia/SkiaOpenGLReadback.h
deleted file mode 100644
index 1ce4773e7d67..000000000000
--- a/libs/hwui/pipeline/skia/SkiaOpenGLReadback.h
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * Copyright (C) 2016 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.
- */
-
-#pragma once
-
-#include "EglReadback.h"
-
-namespace android {
-namespace uirenderer {
-namespace skiapipeline {
-
-class SkiaOpenGLReadback : public EglReadback {
-public:
- SkiaOpenGLReadback(renderthread::RenderThread& thread) : EglReadback(thread) {}
-
-protected:
- virtual CopyResult copyImageInto(EGLImageKHR eglImage, const Matrix4& imgTransform,
- int imgWidth, int imgHeight, const Rect& srcRect,
- SkBitmap* bitmap) override;
-};
-
-} /* namespace skiapipeline */
-} /* namespace uirenderer */
-} /* namespace android */
diff --git a/libs/hwui/pipeline/skia/SkiaVulkanPipeline.cpp b/libs/hwui/pipeline/skia/SkiaVulkanPipeline.cpp
index 5f2eee4523fc..611a34c069d4 100644
--- a/libs/hwui/pipeline/skia/SkiaVulkanPipeline.cpp
+++ b/libs/hwui/pipeline/skia/SkiaVulkanPipeline.cpp
@@ -108,11 +108,6 @@ bool SkiaVulkanPipeline::swapBuffers(const Frame& frame, bool drew, const SkRect
return *requireSwap;
}
-bool SkiaVulkanPipeline::copyLayerInto(DeferredLayerUpdater* layer, SkBitmap* bitmap) {
- // TODO: implement copyLayerInto for vulkan.
- return false;
-}
-
DeferredLayerUpdater* SkiaVulkanPipeline::createTextureLayer() {
mVkManager.initialize();
diff --git a/libs/hwui/pipeline/skia/SkiaVulkanPipeline.h b/libs/hwui/pipeline/skia/SkiaVulkanPipeline.h
index 7806b42e03dc..900b054e35bd 100644
--- a/libs/hwui/pipeline/skia/SkiaVulkanPipeline.h
+++ b/libs/hwui/pipeline/skia/SkiaVulkanPipeline.h
@@ -38,7 +38,6 @@ public:
FrameInfoVisualizer* profiler) override;
bool swapBuffers(const renderthread::Frame& frame, bool drew, const SkRect& screenDirty,
FrameInfo* currentFrameInfo, bool* requireSwap) override;
- bool copyLayerInto(DeferredLayerUpdater* layer, SkBitmap* bitmap) override;
DeferredLayerUpdater* createTextureLayer() override;
bool setSurface(Surface* window, renderthread::SwapBehavior swapBehavior,
renderthread::ColorMode colorMode) override;
diff --git a/libs/hwui/pipeline/skia/SkiaVulkanReadback.h b/libs/hwui/pipeline/skia/SkiaVulkanReadback.h
deleted file mode 100644
index 65b89d617f7b..000000000000
--- a/libs/hwui/pipeline/skia/SkiaVulkanReadback.h
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#pragma once
-
-#include "Readback.h"
-
-namespace android {
-namespace uirenderer {
-namespace skiapipeline {
-
-class SkiaVulkanReadback : public Readback {
-public:
- SkiaVulkanReadback(renderthread::RenderThread& thread) : Readback(thread) {}
-
- virtual CopyResult copySurfaceInto(Surface& surface, const Rect& srcRect,
- SkBitmap* bitmap) override {
- //TODO: implement Vulkan readback.
- return CopyResult::UnknownError;
- }
-
- virtual CopyResult copyGraphicBufferInto(GraphicBuffer* graphicBuffer,
- SkBitmap* bitmap) override {
- //TODO: implement Vulkan readback.
- return CopyResult::UnknownError;
- }
-};
-
-} /* namespace skiapipeline */
-} /* namespace uirenderer */
-} /* namespace android */
diff --git a/libs/hwui/renderthread/CanvasContext.cpp b/libs/hwui/renderthread/CanvasContext.cpp
index 8b07d1dadeb6..727cef3035f5 100644
--- a/libs/hwui/renderthread/CanvasContext.cpp
+++ b/libs/hwui/renderthread/CanvasContext.cpp
@@ -562,10 +562,6 @@ void CanvasContext::buildLayer(RenderNode* node) {
mPrefetchedLayers.insert(node);
}
-bool CanvasContext::copyLayerInto(DeferredLayerUpdater* layer, SkBitmap* bitmap) {
- return mRenderPipeline->copyLayerInto(layer, bitmap);
-}
-
void CanvasContext::destroyHardwareResources() {
stopDrawing();
if (mRenderPipeline->isContextReady()) {
diff --git a/libs/hwui/renderthread/CanvasContext.h b/libs/hwui/renderthread/CanvasContext.h
index 8ca54af13baa..02ee72f05f04 100644
--- a/libs/hwui/renderthread/CanvasContext.h
+++ b/libs/hwui/renderthread/CanvasContext.h
@@ -135,7 +135,6 @@ public:
void prepareAndDraw(RenderNode* node);
void buildLayer(RenderNode* node);
- bool copyLayerInto(DeferredLayerUpdater* layer, SkBitmap* bitmap);
void markLayerInUse(RenderNode* node);
void destroyHardwareResources();
diff --git a/libs/hwui/renderthread/IRenderPipeline.h b/libs/hwui/renderthread/IRenderPipeline.h
index b94a7588a507..b7b7853e6ed7 100644
--- a/libs/hwui/renderthread/IRenderPipeline.h
+++ b/libs/hwui/renderthread/IRenderPipeline.h
@@ -60,7 +60,6 @@ public:
FrameInfoVisualizer* profiler) = 0;
virtual bool swapBuffers(const Frame& frame, bool drew, const SkRect& screenDirty,
FrameInfo* currentFrameInfo, bool* requireSwap) = 0;
- virtual bool copyLayerInto(DeferredLayerUpdater* layer, SkBitmap* bitmap) = 0;
virtual DeferredLayerUpdater* createTextureLayer() = 0;
virtual bool setSurface(Surface* window, SwapBehavior swapBehavior, ColorMode colorMode) = 0;
virtual void onStop() = 0;
diff --git a/libs/hwui/renderthread/RenderProxy.cpp b/libs/hwui/renderthread/RenderProxy.cpp
index e3807e634890..7a5348ac85d9 100644
--- a/libs/hwui/renderthread/RenderProxy.cpp
+++ b/libs/hwui/renderthread/RenderProxy.cpp
@@ -160,8 +160,10 @@ void RenderProxy::buildLayer(RenderNode* node) {
}
bool RenderProxy::copyLayerInto(DeferredLayerUpdater* layer, SkBitmap& bitmap) {
- return mRenderThread.queue().runSync(
- [&]() -> bool { return mContext->copyLayerInto(layer, &bitmap); });
+ auto& thread = RenderThread::getInstance();
+ return thread.queue().runSync(
+ [&]() -> bool { return thread.readback().copyLayerInto(layer, &bitmap)
+ == CopyResult::Success; });
}
void RenderProxy::pushLayerUpdate(DeferredLayerUpdater* layer) {
@@ -331,14 +333,14 @@ void RenderProxy::prepareToDraw(Bitmap& bitmap) {
}
}
-int RenderProxy::copyGraphicBufferInto(GraphicBuffer* buffer, SkBitmap* bitmap) {
+int RenderProxy::copyHWBitmapInto(Bitmap* hwBitmap, SkBitmap* bitmap) {
RenderThread& thread = RenderThread::getInstance();
if (gettid() == thread.getTid()) {
// TODO: fix everything that hits this. We should never be triggering a readback ourselves.
- return (int)thread.readback().copyGraphicBufferInto(buffer, bitmap);
+ return (int)thread.readback().copyHWBitmapInto(hwBitmap, bitmap);
} else {
return thread.queue().runSync([&]() -> int {
- return (int)thread.readback().copyGraphicBufferInto(buffer, bitmap);
+ return (int)thread.readback().copyHWBitmapInto(hwBitmap, bitmap);
});
}
}
diff --git a/libs/hwui/renderthread/RenderProxy.h b/libs/hwui/renderthread/RenderProxy.h
index c2964a4e3515..969ad00d7443 100644
--- a/libs/hwui/renderthread/RenderProxy.h
+++ b/libs/hwui/renderthread/RenderProxy.h
@@ -125,7 +125,7 @@ public:
int bottom, SkBitmap* bitmap);
ANDROID_API static void prepareToDraw(Bitmap& bitmap);
- static int copyGraphicBufferInto(GraphicBuffer* buffer, SkBitmap* bitmap);
+ static int copyHWBitmapInto(Bitmap* hwBitmap, SkBitmap* bitmap);
static void onBitmapDestroyed(uint32_t pixelRefId);
diff --git a/libs/hwui/renderthread/RenderThread.cpp b/libs/hwui/renderthread/RenderThread.cpp
index 2322fbf21f27..7258a0aa4f02 100644
--- a/libs/hwui/renderthread/RenderThread.cpp
+++ b/libs/hwui/renderthread/RenderThread.cpp
@@ -19,13 +19,12 @@
#include "CanvasContext.h"
#include "DeviceInfo.h"
#include "EglManager.h"
+#include "Readback.h"
#include "RenderProxy.h"
#include "VulkanManager.h"
#include "hwui/Bitmap.h"
#include "pipeline/skia/SkiaOpenGLPipeline.h"
-#include "pipeline/skia/SkiaOpenGLReadback.h"
#include "pipeline/skia/SkiaVulkanPipeline.h"
-#include "pipeline/skia/SkiaVulkanReadback.h"
#include "renderstate/RenderState.h"
#include "utils/FatVector.h"
#include "utils/TimeUtils.h"
@@ -235,18 +234,7 @@ void RenderThread::dumpGraphicsMemory(int fd) {
Readback& RenderThread::readback() {
if (!mReadback) {
- auto renderType = Properties::getRenderPipelineType();
- switch (renderType) {
- case RenderPipelineType::SkiaGL:
- mReadback = new skiapipeline::SkiaOpenGLReadback(*this);
- break;
- case RenderPipelineType::SkiaVulkan:
- mReadback = new skiapipeline::SkiaVulkanReadback(*this);
- break;
- default:
- LOG_ALWAYS_FATAL("canvas context type %d not supported", (int32_t)renderType);
- break;
- }
+ mReadback = new Readback(*this);
}
return *mReadback;
diff --git a/libs/hwui/utils/TestWindowContext.cpp b/libs/hwui/utils/TestWindowContext.cpp
deleted file mode 100644
index 8ac6e1f2d39a..000000000000
--- a/libs/hwui/utils/TestWindowContext.cpp
+++ /dev/null
@@ -1,197 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-#include "TestWindowContext.h"
-
-#include "AnimationContext.h"
-#include "IContextFactory.h"
-#include "RenderNode.h"
-#include "SkTypes.h"
-#include "gui/BufferQueue.h"
-#include "gui/CpuConsumer.h"
-#include "gui/IGraphicBufferConsumer.h"
-#include "gui/IGraphicBufferProducer.h"
-#include "gui/Surface.h"
-#include "hwui/Canvas.h"
-#include "renderthread/RenderProxy.h"
-
-#include <cutils/memory.h>
-
-namespace {
-
-/**
- * Helper class for setting up android::uirenderer::renderthread::RenderProxy.
- */
-class ContextFactory : public android::uirenderer::IContextFactory {
-public:
- android::uirenderer::AnimationContext* createAnimationContext(
- android::uirenderer::renderthread::TimeLord& clock) override {
- return new android::uirenderer::AnimationContext(clock);
- }
-};
-
-} // anonymous namespace
-
-namespace android {
-namespace uirenderer {
-
-/**
- Android strong pointers (android::sp) can't hold forward-declared classes,
- so we have to use pointer-to-implementation here if we want to hide the
- details from our non-framework users.
-*/
-
-class TestWindowContext::TestWindowData {
-public:
- explicit TestWindowData(SkISize size) : mSize(size) {
- android::BufferQueue::createBufferQueue(&mProducer, &mConsumer);
- mCpuConsumer = new android::CpuConsumer(mConsumer, 1);
- mCpuConsumer->setName(android::String8("TestWindowContext"));
- mCpuConsumer->setDefaultBufferSize(mSize.width(), mSize.height());
- mAndroidSurface = new android::Surface(mProducer);
- native_window_set_buffers_dimensions(mAndroidSurface.get(), mSize.width(), mSize.height());
- native_window_set_buffers_format(mAndroidSurface.get(), android::PIXEL_FORMAT_RGBA_8888);
- native_window_set_usage(mAndroidSurface.get(), GRALLOC_USAGE_SW_READ_OFTEN |
- GRALLOC_USAGE_SW_WRITE_NEVER |
- GRALLOC_USAGE_HW_RENDER);
- mRootNode.reset(new android::uirenderer::RenderNode());
- mRootNode->incStrong(nullptr);
- mRootNode->mutateStagingProperties().setLeftTopRightBottom(0, 0, mSize.width(),
- mSize.height());
- mRootNode->mutateStagingProperties().setClipToBounds(false);
- mRootNode->setPropertyFieldsDirty(android::uirenderer::RenderNode::GENERIC);
- ContextFactory factory;
- mProxy.reset(new android::uirenderer::renderthread::RenderProxy(false, mRootNode.get(),
- &factory));
- mProxy->loadSystemProperties();
- mProxy->initialize(mAndroidSurface.get());
- float lightX = mSize.width() / 2.0f;
- android::uirenderer::Vector3 lightVector{lightX, -200.0f, 800.0f};
- mProxy->setup(800.0f, 255 * 0.075f, 255 * 0.15f);
- mProxy->setLightCenter(lightVector);
- mCanvas.reset(Canvas::create_recording_canvas(mSize.width(), mSize.height(), mRootNode.get()));
- }
-
- SkCanvas* prepareToDraw() {
- // mCanvas->reset(mSize.width(), mSize.height());
- mCanvas->clipRect(0, 0, mSize.width(), mSize.height(), SkClipOp::kReplace_deprecated);
- return mCanvas->asSkCanvas();
- }
-
- void finishDrawing() {
- mRootNode->setStagingDisplayList(mCanvas->finishRecording());
- mProxy->syncAndDrawFrame();
- // Surprisingly, calling mProxy->fence() here appears to make no difference to
- // the timings we record.
- }
-
- void fence() { mProxy->fence(); }
-
- bool capturePixels(SkBitmap* bmp) {
- sk_sp<SkColorSpace> colorSpace = SkColorSpace::MakeSRGB();
- SkImageInfo destinationConfig =
- SkImageInfo::Make(mSize.width(), mSize.height(), kRGBA_8888_SkColorType,
- kPremul_SkAlphaType, colorSpace);
- bmp->allocPixels(destinationConfig);
- android_memset32((uint32_t*)bmp->getPixels(), SK_ColorRED,
- mSize.width() * mSize.height() * 4);
-
- android::CpuConsumer::LockedBuffer nativeBuffer;
- android::status_t retval = mCpuConsumer->lockNextBuffer(&nativeBuffer);
- if (retval == android::BAD_VALUE) {
- SkDebugf("write_canvas_png() got no buffer; returning transparent");
- // No buffer ready to read - commonly triggered by dm sending us
- // a no-op source, or calling code that doesn't do anything on this
- // backend.
- bmp->eraseColor(SK_ColorTRANSPARENT);
- return false;
- } else if (retval) {
- SkDebugf("Failed to lock buffer to read pixels: %d.", retval);
- return false;
- }
-
- // Move the pixels into the destination SkBitmap
-
- LOG_ALWAYS_FATAL_IF(nativeBuffer.format != android::PIXEL_FORMAT_RGBA_8888,
- "Native buffer not RGBA!");
- SkImageInfo nativeConfig = SkImageInfo::Make(nativeBuffer.width, nativeBuffer.height,
- kRGBA_8888_SkColorType, kPremul_SkAlphaType);
-
- // Android stride is in pixels, Skia stride is in bytes
- SkBitmap nativeWrapper;
- bool success = nativeWrapper.installPixels(nativeConfig, nativeBuffer.data,
- nativeBuffer.stride * 4);
- if (!success) {
- SkDebugf("Failed to wrap HWUI buffer in a SkBitmap");
- return false;
- }
-
- LOG_ALWAYS_FATAL_IF(bmp->colorType() != kRGBA_8888_SkColorType,
- "Destination buffer not RGBA!");
- success = nativeWrapper.readPixels(destinationConfig, bmp->getPixels(), bmp->rowBytes(), 0,
- 0);
- if (!success) {
- SkDebugf("Failed to extract pixels from HWUI buffer");
- return false;
- }
-
- mCpuConsumer->unlockBuffer(nativeBuffer);
-
- return true;
- }
-
-private:
- std::unique_ptr<android::uirenderer::RenderNode> mRootNode;
- std::unique_ptr<android::uirenderer::renderthread::RenderProxy> mProxy;
- std::unique_ptr<android::Canvas> mCanvas;
- android::sp<android::IGraphicBufferProducer> mProducer;
- android::sp<android::IGraphicBufferConsumer> mConsumer;
- android::sp<android::CpuConsumer> mCpuConsumer;
- android::sp<android::Surface> mAndroidSurface;
- SkISize mSize;
-};
-
-TestWindowContext::TestWindowContext() : mData(nullptr) {}
-
-TestWindowContext::~TestWindowContext() {
- delete mData;
-}
-
-void TestWindowContext::initialize(int width, int height) {
- mData = new TestWindowData(SkISize::Make(width, height));
-}
-
-SkCanvas* TestWindowContext::prepareToDraw() {
- return mData ? mData->prepareToDraw() : nullptr;
-}
-
-void TestWindowContext::finishDrawing() {
- if (mData) {
- mData->finishDrawing();
- }
-}
-
-void TestWindowContext::fence() {
- if (mData) {
- mData->fence();
- }
-}
-
-bool TestWindowContext::capturePixels(SkBitmap* bmp) {
- return mData ? mData->capturePixels(bmp) : false;
-}
-
-} // namespace uirenderer
-} // namespace android
diff --git a/libs/hwui/utils/TestWindowContext.h b/libs/hwui/utils/TestWindowContext.h
deleted file mode 100644
index 17ad1e3fef55..000000000000
--- a/libs/hwui/utils/TestWindowContext.h
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-#ifndef TESTWINDOWCONTEXT_H_
-#define TESTWINDOWCONTEXT_H_
-
-#include <cutils/compiler.h>
-
-class SkBitmap;
-class SkCanvas;
-
-namespace android {
-
-namespace uirenderer {
-
-/**
- Wraps all libui/libgui classes and types that external tests depend on,
- exposing only primitive Skia types.
-*/
-
-class ANDROID_API TestWindowContext {
-public:
- TestWindowContext();
- ~TestWindowContext();
-
- /// We need to know the size of the window.
- void initialize(int width, int height);
-
- /// Returns a canvas to draw into; NULL if not yet initialize()d.
- SkCanvas* prepareToDraw();
-
- /// Flushes all drawing commands to HWUI; no-op if not yet initialize()d.
- void finishDrawing();
-
- /// Blocks until HWUI has processed all pending drawing commands;
- /// no-op if not yet initialize()d.
- void fence();
-
- /// Returns false if not yet initialize()d.
- bool capturePixels(SkBitmap* bmp);
-
-private:
- /// Hidden implementation.
- class TestWindowData;
-
- TestWindowData* mData;
-};
-
-} // namespace uirenderer
-} // namespace android
-
-#endif // TESTWINDOWCONTEXT_H_
diff --git a/location/java/android/location/LocationManager.java b/location/java/android/location/LocationManager.java
index b5d94315f97f..6d10c2d692b1 100644
--- a/location/java/android/location/LocationManager.java
+++ b/location/java/android/location/LocationManager.java
@@ -2378,4 +2378,17 @@ public class LocationManager {
throw new IllegalArgumentException("invalid geofence: " + fence);
}
}
+
+ /**
+ * @hide
+ */
+ @SystemApi
+ public String getNetworkProviderPackage() {
+ try {
+ return mService.getNetworkProviderPackage();
+ } catch (RemoteException e) {
+ e.rethrowFromSystemServer();
+ return null;
+ }
+ }
}
diff --git a/media/java/android/media/AudioAttributes.java b/media/java/android/media/AudioAttributes.java
index 047622222065..5ad73653a615 100644
--- a/media/java/android/media/AudioAttributes.java
+++ b/media/java/android/media/AudioAttributes.java
@@ -715,6 +715,7 @@ public final class AudioAttributes implements Parcelable {
break;
case AudioSystem.STREAM_TTS:
mContentType = CONTENT_TYPE_SONIFICATION;
+ mFlags |= FLAG_BEACON;
break;
case AudioSystem.STREAM_ACCESSIBILITY:
mContentType = CONTENT_TYPE_SPEECH;
@@ -1039,6 +1040,10 @@ public final class AudioAttributes implements Parcelable {
return fromGetVolumeControlStream ?
AudioSystem.STREAM_VOICE_CALL : AudioSystem.STREAM_BLUETOOTH_SCO;
}
+ if ((aa.getAllFlags() & FLAG_BEACON) == FLAG_BEACON) {
+ return fromGetVolumeControlStream ?
+ AudioSystem.STREAM_MUSIC : AudioSystem.STREAM_TTS;
+ }
// usage to stream type mapping
switch (aa.getUsage()) {
diff --git a/media/java/android/media/AudioSystem.java b/media/java/android/media/AudioSystem.java
index 39f3b317d210..e8fe9fed6bfa 100644
--- a/media/java/android/media/AudioSystem.java
+++ b/media/java/android/media/AudioSystem.java
@@ -882,6 +882,10 @@ public class AudioSystem
public static native int listAudioPatches(ArrayList<AudioPatch> patches, int[] generation);
public static native int setAudioPortConfig(AudioPortConfig config);
+ public static native int startAudioSource(AudioPortConfig config,
+ AudioAttributes audioAttributes);
+ public static native int stopAudioSource(int handle);
+
// declare this instance as having a dynamic policy callback handler
private static native final void native_register_dynamic_policy_callback();
// declare this instance as having a recording configuration update callback handler
diff --git a/media/java/android/media/MediaPlayer2.java b/media/java/android/media/MediaPlayer2.java
index aa78b0d0721d..89827bc98a7e 100644
--- a/media/java/android/media/MediaPlayer2.java
+++ b/media/java/android/media/MediaPlayer2.java
@@ -773,22 +773,6 @@ public abstract class MediaPlayer2 implements SubtitleController.Listener
}
/**
- * Invoke a generic method on the native player using opaque
- * parcels for the request and reply. Both payloads' format is a
- * convention between the java caller and the native player.
- * Must be called after setDataSource to make sure a native player
- * exists. On failure, a RuntimeException is thrown.
- *
- * @param request Parcel with the data for the extension. The
- * caller must use {@link #newRequest()} to get one.
- *
- * @param reply Output parcel with the data returned by the
- * native player.
- * {@hide}
- */
- public void invoke(Parcel request, Parcel reply) { }
-
- /**
* Insert a task in the command queue to help the client to identify whether a batch
* of commands has been finished. When this command is processed, a notification
* {@code EventCallback.onCommandLabelReached} will be fired with the
diff --git a/media/java/android/media/MediaPlayer2Impl.java b/media/java/android/media/MediaPlayer2Impl.java
index c06b97b65735..6ae4d408fca2 100644
--- a/media/java/android/media/MediaPlayer2Impl.java
+++ b/media/java/android/media/MediaPlayer2Impl.java
@@ -25,6 +25,10 @@ import android.content.ContentResolver;
import android.content.Context;
import android.content.res.AssetFileDescriptor;
import android.graphics.SurfaceTexture;
+import android.graphics.Rect;
+import android.media.MediaPlayer2Proto;
+import android.media.MediaPlayer2Proto.PlayerMessage;
+import android.media.MediaPlayer2Proto.Value;
import android.media.SubtitleController.Anchor;
import android.media.SubtitleTrack.RenderingWidget;
import android.net.Uri;
@@ -49,6 +53,7 @@ import android.view.Surface;
import android.view.SurfaceHolder;
import android.widget.VideoView;
+import com.android.framework.protobuf.InvalidProtocolBufferException;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.util.Preconditions;
@@ -72,6 +77,7 @@ import java.util.ArrayList;
import java.util.Arrays;
import java.util.BitSet;
import java.util.HashMap;
+import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
@@ -555,28 +561,30 @@ public final class MediaPlayer2Impl extends MediaPlayer2 {
}
/**
- * Invoke a generic method on the native player using opaque
- * parcels for the request and reply. Both payloads' format is a
+ * Invoke a generic method on the native player using opaque protocol
+ * buffer message for the request and reply. Both payloads' format is a
* convention between the java caller and the native player.
- * Must be called after setDataSource or setPlaylist to make sure a native player
- * exists. On failure, a RuntimeException is thrown.
*
- * @param request Parcel with the data for the extension. The
+ * @param request PlayerMessage for the extension. The
* caller must use {@link #newRequest()} to get one.
*
- * @param reply Output parcel with the data returned by the
+ * @return PlayerMessage with the data returned by the
* native player.
- * {@hide}
*/
- @Override
- public void invoke(Parcel request, Parcel reply) {
- int retcode = native_invoke(request, reply);
- reply.setDataPosition(0);
- if (retcode != 0) {
- throw new RuntimeException("failure code: " + retcode);
+ private PlayerMessage invoke(PlayerMessage msg) {
+ byte[] ret = _invoke(msg.toByteArray());
+ if (ret == null) {
+ return null;
+ }
+ try {
+ return PlayerMessage.parseFrom(ret);
+ } catch (InvalidProtocolBufferException e) {
+ return null;
}
}
+ private native byte[] _invoke(byte[] request);
+
@Override
public void notifyWhenCommandLabelReached(Object label) {
addTask(new Task(CALL_COMPLETED_NOTIFY_WHEN_COMMAND_LABEL_REACHED, false) {
@@ -683,16 +691,12 @@ public final class MediaPlayer2Impl extends MediaPlayer2 {
final String msg = "Scaling mode " + mode + " is not supported";
throw new IllegalArgumentException(msg);
}
- Parcel request = Parcel.obtain();
- Parcel reply = Parcel.obtain();
- try {
- request.writeInt(INVOKE_ID_SET_VIDEO_SCALE_MODE);
- request.writeInt(mode);
- invoke(request, reply);
- } finally {
- request.recycle();
- reply.recycle();
- }
+ PlayerMessage request = PlayerMessage.newBuilder()
+ .addValues(Value.newBuilder()
+ .setInt32Value(INVOKE_ID_SET_VIDEO_SCALE_MODE))
+ .addValues(Value.newBuilder().setInt32Value(mode))
+ .build();
+ invoke(request);
}
});
}
@@ -1799,14 +1803,6 @@ public final class MediaPlayer2Impl extends MediaPlayer2 {
private native void _setAuxEffectSendLevel(float level);
/*
- * @param request Parcel destinated to the media player.
- * @param reply[out] Parcel that will contain the reply.
- * @return The status code.
- */
- private native final int native_invoke(Parcel request, Parcel reply);
-
-
- /*
* @param update_only If true fetch only the set of metadata that have
* changed since the last invocation of getMetadata.
* The set is built using the unfiltered
@@ -1886,18 +1882,18 @@ public final class MediaPlayer2Impl extends MediaPlayer2 {
final int mTrackType;
final MediaFormat mFormat;
- TrackInfoImpl(Parcel in) {
- mTrackType = in.readInt();
- // TODO: parcel in the full MediaFormat; currently we are using createSubtitleFormat
+ TrackInfoImpl(Iterator<Value> in) {
+ mTrackType = in.next().getInt32Value();
+ // TODO: build the full MediaFormat; currently we are using createSubtitleFormat
// even for audio/video tracks, meaning we only set the mime and language.
- String mime = in.readString();
- String language = in.readString();
+ String mime = in.next().getStringValue();
+ String language = in.next().getStringValue();
mFormat = MediaFormat.createSubtitleFormat(mime, language);
if (mTrackType == MEDIA_TRACK_TYPE_SUBTITLE) {
- mFormat.setInteger(MediaFormat.KEY_IS_AUTOSELECT, in.readInt());
- mFormat.setInteger(MediaFormat.KEY_IS_DEFAULT, in.readInt());
- mFormat.setInteger(MediaFormat.KEY_IS_FORCED_SUBTITLE, in.readInt());
+ mFormat.setInteger(MediaFormat.KEY_IS_AUTOSELECT, in.next().getInt32Value());
+ mFormat.setInteger(MediaFormat.KEY_IS_DEFAULT, in.next().getInt32Value());
+ mFormat.setInteger(MediaFormat.KEY_IS_FORCED_SUBTITLE, in.next().getInt32Value());
}
}
@@ -1952,23 +1948,6 @@ public final class MediaPlayer2Impl extends MediaPlayer2 {
out.append("}");
return out.toString();
}
-
- /**
- * Used to read a TrackInfoImpl from a Parcel.
- */
- /* package private */ static final Parcelable.Creator<TrackInfoImpl> CREATOR
- = new Parcelable.Creator<TrackInfoImpl>() {
- @Override
- public TrackInfoImpl createFromParcel(Parcel in) {
- return new TrackInfoImpl(in);
- }
-
- @Override
- public TrackInfoImpl[] newArray(int size) {
- return new TrackInfoImpl[size];
- }
- };
-
};
// We would like domain specific classes with more informative names than the `first` and `second`
@@ -2010,17 +1989,23 @@ public final class MediaPlayer2Impl extends MediaPlayer2 {
}
private TrackInfoImpl[] getInbandTrackInfoImpl() throws IllegalStateException {
- Parcel request = Parcel.obtain();
- Parcel reply = Parcel.obtain();
- try {
- request.writeInt(INVOKE_ID_GET_TRACK_INFO);
- invoke(request, reply);
- TrackInfoImpl trackInfo[] = reply.createTypedArray(TrackInfoImpl.CREATOR);
- return trackInfo;
- } finally {
- request.recycle();
- reply.recycle();
+ PlayerMessage request = PlayerMessage.newBuilder()
+ .addValues(Value.newBuilder().setInt32Value(INVOKE_ID_GET_TRACK_INFO))
+ .build();
+ PlayerMessage response = invoke(request);
+ if (response == null) {
+ return null;
+ }
+ Iterator<Value> in = response.getValuesList().iterator();
+ int size = in.next().getInt32Value();
+ if (size == 0) {
+ return null;
}
+ TrackInfoImpl trackInfo[] = new TrackInfoImpl[size];
+ for (int i = 0; i < size; ++i) {
+ trackInfo[i] = new TrackInfoImpl(in);
+ }
+ return trackInfo;
}
/*
@@ -2481,26 +2466,24 @@ public final class MediaPlayer2Impl extends MediaPlayer2 {
}
}
- Parcel request = Parcel.obtain();
- Parcel reply = Parcel.obtain();
- try {
- request.writeInt(INVOKE_ID_GET_SELECTED_TRACK);
- request.writeInt(trackType);
- invoke(request, reply);
- int inbandTrackIndex = reply.readInt();
- synchronized (mIndexTrackPairs) {
- for (int i = 0; i < mIndexTrackPairs.size(); i++) {
- Pair<Integer, SubtitleTrack> p = mIndexTrackPairs.get(i);
- if (p.first != null && p.first == inbandTrackIndex) {
- return i;
- }
+ PlayerMessage request = PlayerMessage.newBuilder()
+ .addValues(Value.newBuilder().setInt32Value(INVOKE_ID_GET_SELECTED_TRACK))
+ .addValues(Value.newBuilder().setInt32Value(trackType))
+ .build();
+ PlayerMessage response = invoke(request);
+ if (response == null) {
+ return -1;
+ }
+ int inbandTrackIndex = response.getValues(0).getInt32Value();
+ synchronized (mIndexTrackPairs) {
+ for (int i = 0; i < mIndexTrackPairs.size(); i++) {
+ Pair<Integer, SubtitleTrack> p = mIndexTrackPairs.get(i);
+ if (p.first != null && p.first == inbandTrackIndex) {
+ return i;
}
}
- return -1;
- } finally {
- request.recycle();
- reply.recycle();
}
+ return -1;
}
/**
@@ -2617,16 +2600,12 @@ public final class MediaPlayer2Impl extends MediaPlayer2 {
private void selectOrDeselectInbandTrack(int index, boolean select)
throws IllegalStateException {
- Parcel request = Parcel.obtain();
- Parcel reply = Parcel.obtain();
- try {
- request.writeInt(select? INVOKE_ID_SELECT_TRACK: INVOKE_ID_DESELECT_TRACK);
- request.writeInt(index);
- invoke(request, reply);
- } finally {
- request.recycle();
- reply.recycle();
- }
+ PlayerMessage request = PlayerMessage.newBuilder()
+ .addValues(Value.newBuilder().setInt32Value(
+ select? INVOKE_ID_SELECT_TRACK: INVOKE_ID_DESELECT_TRACK))
+ .addValues(Value.newBuilder().setInt32Value(index))
+ .build();
+ invoke(request);
}
// Have to declare protected for finalize() since it is protected
@@ -2791,8 +2770,8 @@ public final class MediaPlayer2Impl extends MediaPlayer2 {
{
if (msg.obj == null) {
Log.w(TAG, "MEDIA_DRM_INFO msg.obj=NULL");
- } else if (msg.obj instanceof Parcel) {
- // The parcel was parsed already in postEventFromNative
+ } else if (msg.obj instanceof byte[]) {
+ // The PlayerMessage was parsed already in postEventFromNative
final DrmInfoImpl drmInfo;
synchronized (mDrmLock) {
@@ -2935,20 +2914,7 @@ public final class MediaPlayer2Impl extends MediaPlayer2 {
case MEDIA_INFO:
{
- synchronized (mEventCbLock) {
- for (Pair<Executor, EventCallback> cb : mEventCallbackRecords) {
- cb.first.execute(() -> cb.second.onInfo(
- mMediaPlayer, dsd, what, extra));
- }
- }
-
switch (msg.arg1) {
- case MEDIA_INFO_DATA_SOURCE_START:
- if (isCurrentSrcId) {
- prepareNextDataSource();
- }
- break;
-
case MEDIA_INFO_VIDEO_TRACK_LAGGING:
Log.i(TAG, "Info (" + msg.arg1 + "," + msg.arg2 + ")");
break;
@@ -2980,6 +2946,20 @@ public final class MediaPlayer2Impl extends MediaPlayer2 {
}
break;
}
+
+ synchronized (mEventCbLock) {
+ for (Pair<Executor, EventCallback> cb : mEventCallbackRecords) {
+ cb.first.execute(() -> cb.second.onInfo(
+ mMediaPlayer, dsd, what, extra));
+ }
+ }
+
+ if (msg.arg1 == MEDIA_INFO_DATA_SOURCE_START) {
+ if (isCurrentSrcId) {
+ prepareNextDataSource();
+ }
+ }
+
// No real default action so far.
return;
}
@@ -2996,10 +2976,15 @@ public final class MediaPlayer2Impl extends MediaPlayer2 {
case MEDIA_TIMED_TEXT:
{
final TimedText text;
- if (msg.obj instanceof Parcel) {
- Parcel parcel = (Parcel)msg.obj;
- text = new TimedText(parcel);
- parcel.recycle();
+ if (msg.obj instanceof byte[]) {
+ PlayerMessage playerMsg;
+ try {
+ playerMsg = PlayerMessage.parseFrom((byte[]) msg.obj);
+ } catch (InvalidProtocolBufferException e) {
+ Log.w(TAG, "Failed to parse timed text.", e);
+ return;
+ }
+ text = TimedTextUtil.parsePlayerMessage(playerMsg);
} else {
text = null;
}
@@ -3015,10 +3000,20 @@ public final class MediaPlayer2Impl extends MediaPlayer2 {
case MEDIA_SUBTITLE_DATA:
{
- if (msg.obj instanceof Parcel) {
- Parcel parcel = (Parcel) msg.obj;
- SubtitleData data = new SubtitleData(parcel);
- parcel.recycle();
+ if (msg.obj instanceof byte[]) {
+ PlayerMessage playerMsg;
+ try {
+ playerMsg = PlayerMessage.parseFrom((byte[]) msg.obj);
+ } catch (InvalidProtocolBufferException e) {
+ Log.w(TAG, "Failed to parse subtitle data.", e);
+ return;
+ }
+ Iterator<Value> in = playerMsg.getValuesList().iterator();
+ SubtitleData data = new SubtitleData(
+ in.next().getInt32Value(), // trackIndex
+ in.next().getInt64Value(), // startTimeUs
+ in.next().getInt64Value(), // durationUs
+ in.next().getBytesValue().toByteArray()); // data
synchronized (mEventCbLock) {
for (Pair<Executor, EventCallback> cb : mEventCallbackRecords) {
cb.first.execute(() -> cb.second.onSubtitleData(
@@ -3032,10 +3027,18 @@ public final class MediaPlayer2Impl extends MediaPlayer2 {
case MEDIA_META_DATA:
{
final TimedMetaData data;
- if (msg.obj instanceof Parcel) {
- Parcel parcel = (Parcel) msg.obj;
- data = TimedMetaData.createTimedMetaDataFromParcel(parcel);
- parcel.recycle();
+ if (msg.obj instanceof byte[]) {
+ PlayerMessage playerMsg;
+ try {
+ playerMsg = PlayerMessage.parseFrom((byte[]) msg.obj);
+ } catch (InvalidProtocolBufferException e) {
+ Log.w(TAG, "Failed to parse timed meta data.", e);
+ return;
+ }
+ Iterator<Value> in = playerMsg.getValuesList().iterator();
+ data = new TimedMetaData(
+ in.next().getInt64Value(), // timestampUs
+ in.next().getBytesValue().toByteArray()); // metaData
} else {
data = null;
}
@@ -3083,7 +3086,7 @@ public final class MediaPlayer2Impl extends MediaPlayer2 {
* the cookie passed to native_setup().)
*/
private static void postEventFromNative(Object mediaplayer2_ref, long srcId,
- int what, int arg1, int arg2, Object obj)
+ int what, int arg1, int arg2, byte[] obj)
{
final MediaPlayer2Impl mp = (MediaPlayer2Impl)((WeakReference)mediaplayer2_ref).get();
if (mp == null) {
@@ -3097,9 +3100,15 @@ public final class MediaPlayer2Impl extends MediaPlayer2 {
// notification looper so its handleMessage might process the event after prepare()
// has returned.
Log.v(TAG, "postEventFromNative MEDIA_DRM_INFO");
- if (obj instanceof Parcel) {
- Parcel parcel = (Parcel)obj;
- DrmInfoImpl drmInfo = new DrmInfoImpl(parcel);
+ if (obj != null) {
+ PlayerMessage playerMsg;
+ try {
+ playerMsg = PlayerMessage.parseFrom(obj);
+ } catch (InvalidProtocolBufferException e) {
+ Log.w(TAG, "MEDIA_DRM_INFO failed to parse msg.obj " + obj);
+ break;
+ }
+ DrmInfoImpl drmInfo = new DrmInfoImpl(playerMsg);
synchronized (mp.mDrmLock) {
mp.mDrmInfoImpl = drmInfo;
}
@@ -3766,22 +3775,21 @@ public final class MediaPlayer2Impl extends MediaPlayer2 {
supportedSchemes = SupportedSchemes;
}
- private DrmInfoImpl(Parcel parcel) {
- Log.v(TAG, "DrmInfoImpl(" + parcel + ") size " + parcel.dataSize());
+ private DrmInfoImpl(PlayerMessage msg) {
+ Log.v(TAG, "DrmInfoImpl(" + msg + ")");
- int psshsize = parcel.readInt();
- byte[] pssh = new byte[psshsize];
- parcel.readByteArray(pssh);
+ Iterator<Value> in = msg.getValuesList().iterator();
+ byte[] pssh = in.next().getBytesValue().toByteArray();
Log.v(TAG, "DrmInfoImpl() PSSH: " + arrToHex(pssh));
- mapPssh = parsePSSH(pssh, psshsize);
+ mapPssh = parsePSSH(pssh, pssh.length);
Log.v(TAG, "DrmInfoImpl() PSSH: " + mapPssh);
- int supportedDRMsCount = parcel.readInt();
+ int supportedDRMsCount = in.next().getInt32Value();
supportedSchemes = new UUID[supportedDRMsCount];
for (int i = 0; i < supportedDRMsCount; i++) {
byte[] uuid = new byte[16];
- parcel.readByteArray(uuid);
+ in.next().getBytesValue().copyTo(uuid, uuid.length);
supportedSchemes[i] = bytesToUUID(uuid);
@@ -3789,7 +3797,7 @@ public final class MediaPlayer2Impl extends MediaPlayer2 {
supportedSchemes[i]);
}
- Log.v(TAG, "DrmInfoImpl() Parcel psshsize: " + psshsize +
+ Log.v(TAG, "DrmInfoImpl() Parcel psshsize: " + pssh.length +
" supportedDRMsCount: " + supportedDRMsCount);
}
@@ -4269,6 +4277,60 @@ public final class MediaPlayer2Impl extends MediaPlayer2 {
mode == VIDEO_SCALING_MODE_SCALE_TO_FIT_WITH_CROPPING);
}
+ private static class TimedTextUtil {
+ // These keys must be in sync with the keys in TextDescription2.h
+ private static final int KEY_START_TIME = 7; // int
+ private static final int KEY_STRUCT_TEXT_POS = 14; // TextPos
+ private static final int KEY_STRUCT_TEXT = 16; // Text
+ private static final int KEY_GLOBAL_SETTING = 101;
+ private static final int KEY_LOCAL_SETTING = 102;
+
+ private static TimedText parsePlayerMessage(PlayerMessage playerMsg) {
+ if (playerMsg.getValuesCount() == 0) {
+ return null;
+ }
+
+ String textChars = null;
+ Rect textBounds = null;
+ Iterator<Value> in = playerMsg.getValuesList().iterator();
+ int type = in.next().getInt32Value();
+ if (type == KEY_LOCAL_SETTING) {
+ type = in.next().getInt32Value();
+ if (type != KEY_START_TIME) {
+ return null;
+ }
+ int startTimeMs = in.next().getInt32Value();
+
+ type = in.next().getInt32Value();
+ if (type != KEY_STRUCT_TEXT) {
+ return null;
+ }
+
+ byte[] text = in.next().getBytesValue().toByteArray();
+ if (text == null || text.length == 0) {
+ textChars = null;
+ } else {
+ textChars = new String(text);
+ }
+
+ } else if (type != KEY_GLOBAL_SETTING) {
+ Log.w(TAG, "Invalid timed text key found: " + type);
+ return null;
+ }
+ if (in.hasNext()) {
+ type = in.next().getInt32Value();
+ if (type == KEY_STRUCT_TEXT_POS) {
+ int top = in.next().getInt32Value();
+ int left = in.next().getInt32Value();
+ int bottom = in.next().getInt32Value();
+ int right = in.next().getInt32Value();
+ textBounds = new Rect(left, top, right, bottom);
+ }
+ }
+ return new TimedText(textChars, textBounds);
+ }
+ }
+
/** @hide */
static class TimeProvider implements MediaTimeProvider {
private static final String TAG = "MTP";
diff --git a/media/java/android/media/SubtitleData.java b/media/java/android/media/SubtitleData.java
index 9797828db891..ba37b9b66360 100644
--- a/media/java/android/media/SubtitleData.java
+++ b/media/java/android/media/SubtitleData.java
@@ -79,6 +79,14 @@ public final class SubtitleData
}
}
+ /** @hide */
+ public SubtitleData(int trackIndex, long startTimeUs, long durationUs, byte[] data) {
+ mTrackIndex = trackIndex;
+ mStartTimeUs = startTimeUs;
+ mDurationUs = durationUs;
+ mData = data;
+ }
+
/**
* Returns the index of the MediaPlayer track which contains this subtitle data.
* @return an index in the array returned by {@link MediaPlayer#getTrackInfo()}.
diff --git a/media/java/android/media/TimedMetaData.java b/media/java/android/media/TimedMetaData.java
index 03c877013ead..97e6bfa170d8 100644
--- a/media/java/android/media/TimedMetaData.java
+++ b/media/java/android/media/TimedMetaData.java
@@ -48,6 +48,14 @@ public final class TimedMetaData {
}
/**
+ * @hide
+ */
+ public TimedMetaData(long timestampUs, byte[] metaData) {
+ mTimestampUs = timestampUs;
+ mMetaData = metaData;
+ }
+
+ /**
* @return the timestamp associated with this metadata access unit in microseconds;
* 0 denotes playback start.
*/
diff --git a/media/java/android/media/TimedText.java b/media/java/android/media/TimedText.java
index ebcea1995261..d8cdf9c12e09 100644
--- a/media/java/android/media/TimedText.java
+++ b/media/java/android/media/TimedText.java
@@ -364,6 +364,16 @@ public final class TimedText
}
/**
+ * @param text the characters in the timed text.
+ * @param bounds the rectangle area or region for rendering the timed text.
+ * {@hide}
+ */
+ public TimedText(String text, Rect bounds) {
+ mTextChars = text;
+ mTextBounds = bounds;
+ }
+
+ /**
* Get the characters in the timed text.
*
* @return the characters as a String object in the TimedText. Applications
diff --git a/media/jni/Android.bp b/media/jni/Android.bp
index de9a24b078cb..339a7eef637e 100644
--- a/media/jni/Android.bp
+++ b/media/jni/Android.bp
@@ -133,8 +133,10 @@ cc_library_shared {
"libmediaextractor",
"libmediametrics",
"libmediaplayer2",
+ "libmediaplayer2-protos",
"libmediautils",
"libnetd_client",
+ "libprotobuf-cpp-lite",
"libstagefright_esds",
"libstagefright_foundation",
"libstagefright_httplive",
@@ -143,7 +145,7 @@ cc_library_shared {
"libstagefright_nuplayer2",
"libstagefright_player2",
"libstagefright_rtsp",
- "libstagefright_timedtext",
+ "libstagefright_timedtext2",
"libunwindstack",
"libutilscallstack",
"libziparchive",
diff --git a/media/jni/android_media_MediaPlayer2.cpp b/media/jni/android_media_MediaPlayer2.cpp
index 426598727c89..801dade63268 100644
--- a/media/jni/android_media_MediaPlayer2.cpp
+++ b/media/jni/android_media_MediaPlayer2.cpp
@@ -56,6 +56,10 @@
#include "android_util_Binder.h"
#include <binder/Parcel.h>
+#include "mediaplayer2.pb.h"
+
+using android::media::MediaPlayer2Proto::PlayerMessage;
+
// Modular DRM begin
#define FIND_CLASS(var, className) \
var = env->FindClass(className); \
@@ -157,7 +161,7 @@ public:
JNIMediaPlayer2Listener(JNIEnv* env, jobject thiz, jobject weak_thiz);
~JNIMediaPlayer2Listener();
virtual void notify(int64_t srcId, int msg, int ext1, int ext2,
- const Parcel *obj = NULL) override;
+ const PlayerMessage *obj = NULL) override;
private:
JNIMediaPlayer2Listener();
jclass mClass; // Reference to MediaPlayer2 class
@@ -190,18 +194,21 @@ JNIMediaPlayer2Listener::~JNIMediaPlayer2Listener()
env->DeleteGlobalRef(mClass);
}
-void JNIMediaPlayer2Listener::notify(int64_t srcId, int msg, int ext1, int ext2, const Parcel *obj)
+void JNIMediaPlayer2Listener::notify(int64_t srcId, int msg, int ext1, int ext2,
+ const PlayerMessage* obj)
{
JNIEnv *env = JavaVMHelper::getJNIEnv();
- if (obj && obj->dataSize() > 0) {
- jobject jParcel = createJavaParcelObject(env);
- if (jParcel != NULL) {
- Parcel* nativeParcel = parcelForJavaObject(env, jParcel);
- nativeParcel->setData(obj->data(), obj->dataSize());
- env->CallStaticVoidMethod(mClass, fields.post_event, mObject,
- srcId, msg, ext1, ext2, jParcel);
- env->DeleteLocalRef(jParcel);
- }
+ if (obj != NULL) {
+ int size = obj->ByteSize();
+ jbyte* temp = new jbyte[size];
+ obj->SerializeToArray(temp, size);
+
+ // return the response as a byte array.
+ jbyteArray out = env->NewByteArray(size);
+ env->SetByteArrayRegion(out, 0, size, temp);
+ env->CallStaticVoidMethod(mClass, fields.post_event, mObject,
+ srcId, msg, ext1, ext2, out);
+ delete[] temp;
} else {
env->CallStaticVoidMethod(mClass, fields.post_event, mObject,
srcId, msg, ext1, ext2, NULL);
@@ -911,6 +918,9 @@ android_media_MediaPlayer2_setParameter(JNIEnv *env, jobject thiz, jint key, job
return false;
}
+ // TODO: parcelForJavaObject() shouldn't be used since it's dependent on
+ // framework's Parcel implementation. This setParameter() is used
+ // only with AudioAttribute. Can this be used as jobject with JAudioTrack?
Parcel *request = parcelForJavaObject(env, java_request);
status_t err = mp->setParameter(key, *request);
if (err == OK) {
@@ -978,26 +988,35 @@ android_media_MediaPlayer2_setVolume(JNIEnv *env, jobject thiz, jfloat leftVolum
process_media_player_call( env, thiz, mp->setVolume((float) leftVolume, (float) rightVolume), NULL, NULL );
}
-// Sends the request and reply parcels to the media player via the
-// binder interface.
-static jint
-android_media_MediaPlayer2_invoke(JNIEnv *env, jobject thiz,
- jobject java_request, jobject java_reply)
-{
+static jbyteArray
+android_media_MediaPlayer2_invoke(JNIEnv *env, jobject thiz, jbyteArray requestData) {
sp<MediaPlayer2> media_player = getMediaPlayer(env, thiz);
- if (media_player == NULL ) {
+ if (media_player == NULL) {
jniThrowException(env, "java/lang/IllegalStateException", NULL);
- return UNKNOWN_ERROR;
+ return NULL;
}
- Parcel *request = parcelForJavaObject(env, java_request);
- Parcel *reply = parcelForJavaObject(env, java_reply);
+ // Get the byte[] pointer and data length.
+ jbyte* pData = env->GetByteArrayElements(requestData, NULL);
+ jsize pDataLen = env->GetArrayLength(requestData);
+
+ // Deserialize from the byte stream.
+ PlayerMessage request;
+ PlayerMessage response;
+ request.ParseFromArray(pData, pDataLen);
+
+ media_player->invoke(request, &response);
+
+ int size = response.ByteSize();
+ jbyte* temp = new jbyte[size];
+ response.SerializeToArray(temp, size);
- request->setDataPosition(0);
+ // return the response as a byte array.
+ jbyteArray out = env->NewByteArray(size);
+ env->SetByteArrayRegion(out, 0, size, temp);
+ delete[] temp;
- // Don't use process_media_player_call which use the async loop to
- // report errors, instead returns the status.
- return (jint) media_player->invoke(*request, reply);
+ return out;
}
// Sends the new filter to the client.
@@ -1068,7 +1087,7 @@ android_media_MediaPlayer2_native_init(JNIEnv *env)
}
fields.post_event = env->GetStaticMethodID(clazz, "postEventFromNative",
- "(Ljava/lang/Object;JIIILjava/lang/Object;)V");
+ "(Ljava/lang/Object;JIII[B)V");
if (fields.post_event == NULL) {
return;
}
@@ -1512,7 +1531,7 @@ static const JNINativeMethod gMethods[] = {
{"setLooping", "(Z)V", (void *)android_media_MediaPlayer2_setLooping},
{"isLooping", "()Z", (void *)android_media_MediaPlayer2_isLooping},
{"_setVolume", "(FF)V", (void *)android_media_MediaPlayer2_setVolume},
- {"native_invoke", "(Landroid/os/Parcel;Landroid/os/Parcel;)I",(void *)android_media_MediaPlayer2_invoke},
+ {"_invoke", "([B)[B", (void *)android_media_MediaPlayer2_invoke},
{"native_setMetadataFilter", "(Landroid/os/Parcel;)I", (void *)android_media_MediaPlayer2_setMetadataFilter},
{"native_getMetadata", "(ZZLandroid/os/Parcel;)Z", (void *)android_media_MediaPlayer2_getMetadata},
{"native_init", "()V", (void *)android_media_MediaPlayer2_native_init},
diff --git a/media/proto/Android.bp b/media/proto/Android.bp
new file mode 100644
index 000000000000..50d44c3e6145
--- /dev/null
+++ b/media/proto/Android.bp
@@ -0,0 +1,20 @@
+java_library_static {
+ name: "mediaplayer2-protos",
+ host_supported: true,
+ proto: {
+ type: "lite",
+ },
+ srcs: ["mediaplayer2.proto"],
+ no_framework_libs: true,
+ jarjar_rules: "jarjar-rules.txt",
+}
+
+cc_library_static {
+ name: "libmediaplayer2-protos",
+ host_supported: true,
+ proto: {
+ export_proto_headers: true,
+ type: "lite",
+ },
+ srcs: ["mediaplayer2.proto"],
+}
diff --git a/media/proto/jarjar-rules.txt b/media/proto/jarjar-rules.txt
new file mode 100644
index 000000000000..7be6e732d3fd
--- /dev/null
+++ b/media/proto/jarjar-rules.txt
@@ -0,0 +1,2 @@
+rule com.google.protobuf.** com.android.framework.protobuf.@1
+
diff --git a/media/proto/mediaplayer2.proto b/media/proto/mediaplayer2.proto
new file mode 100644
index 000000000000..6287d6cd326d
--- /dev/null
+++ b/media/proto/mediaplayer2.proto
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+syntax = "proto2";
+
+option optimize_for = LITE_RUNTIME;
+
+// C++ namespace: android::media:MediaPlayer2Proto:
+package android.media.MediaPlayer2Proto;
+
+option java_package = "android.media";
+option java_outer_classname = "MediaPlayer2Proto";
+
+message Value {
+ // The kind of value.
+ oneof kind {
+ // Represents a boolean value.
+ bool bool_value = 1;
+ // Represents an int32 value.
+ int32 int32_value = 2;
+ // Represents an uint32 value.
+ uint32 uint32_value = 3;
+ // Represents an int64 value.
+ int64 int64_value = 4;
+ // Represents an uint64 value.
+ uint64 uint64_value = 5;
+ // Represents a float value.
+ double float_value = 6;
+ // Represents a double value.
+ double double_value = 7;
+ // Represents a string value.
+ string string_value = 8;
+ // Represents a bytes value.
+ bytes bytes_value = 9;
+ }
+}
+
+message PlayerMessage {
+ repeated Value values = 1;
+}
diff --git a/packages/DefaultContainerService/res/values-fr-rCA/strings.xml b/packages/DefaultContainerService/res/values-fr-rCA/strings.xml
index 69c4e9944dff..353d0b47841f 100644
--- a/packages/DefaultContainerService/res/values-fr-rCA/strings.xml
+++ b/packages/DefaultContainerService/res/values-fr-rCA/strings.xml
@@ -20,5 +20,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="service_name" msgid="4841491635055379553">"Aide accès au paquet"</string>
+ <string name="service_name" msgid="4841491635055379553">"Aide Accès au paquet"</string>
</resources>
diff --git a/packages/DefaultContainerService/res/values-pt-rPT/strings.xml b/packages/DefaultContainerService/res/values-pt-rPT/strings.xml
index 8ea6a3af4e1b..647334b1196b 100644
--- a/packages/DefaultContainerService/res/values-pt-rPT/strings.xml
+++ b/packages/DefaultContainerService/res/values-pt-rPT/strings.xml
@@ -20,5 +20,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="service_name" msgid="4841491635055379553">"Ajuda p/ aceder a pacotes"</string>
+ <string name="service_name" msgid="4841491635055379553">"Ajuda acesso a pacotes"</string>
</resources>
diff --git a/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java b/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java
index 0a720a5b234e..62207c5517ec 100644
--- a/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java
+++ b/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java
@@ -145,6 +145,7 @@ public class ExternalStorageProvider extends FileSystemProvider {
}
}
+ @GuardedBy("mRootsLock")
private void updateVolumesLocked() {
mRoots.clear();
diff --git a/packages/SettingsLib/HelpUtils/res/values-af/strings.xml b/packages/SettingsLib/HelpUtils/res/values-af/strings.xml
new file mode 100644
index 000000000000..8bf8545be85a
--- /dev/null
+++ b/packages/SettingsLib/HelpUtils/res/values-af/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright (C) 2018 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="help_feedback_label" msgid="4550436169116444686">"Hulp en terugvoer"</string>
+</resources>
diff --git a/packages/SettingsLib/HelpUtils/res/values-am/strings.xml b/packages/SettingsLib/HelpUtils/res/values-am/strings.xml
new file mode 100644
index 000000000000..10a276cd5594
--- /dev/null
+++ b/packages/SettingsLib/HelpUtils/res/values-am/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright (C) 2018 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="help_feedback_label" msgid="4550436169116444686">"እገዛ እና ግብረመልስ"</string>
+</resources>
diff --git a/packages/SettingsLib/HelpUtils/res/values-ar/strings.xml b/packages/SettingsLib/HelpUtils/res/values-ar/strings.xml
new file mode 100644
index 000000000000..cfbe26aeda57
--- /dev/null
+++ b/packages/SettingsLib/HelpUtils/res/values-ar/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright (C) 2018 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="help_feedback_label" msgid="4550436169116444686">"المساعدة والتعليقات"</string>
+</resources>
diff --git a/packages/SettingsLib/HelpUtils/res/values-as/strings.xml b/packages/SettingsLib/HelpUtils/res/values-as/strings.xml
new file mode 100644
index 000000000000..0a3cb6d58edc
--- /dev/null
+++ b/packages/SettingsLib/HelpUtils/res/values-as/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright (C) 2018 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="help_feedback_label" msgid="4550436169116444686">"সহায় আৰু প্ৰতিক্ৰিয়া"</string>
+</resources>
diff --git a/packages/SettingsLib/HelpUtils/res/values-az/strings.xml b/packages/SettingsLib/HelpUtils/res/values-az/strings.xml
new file mode 100644
index 000000000000..a7353d9b12cd
--- /dev/null
+++ b/packages/SettingsLib/HelpUtils/res/values-az/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright (C) 2018 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="help_feedback_label" msgid="4550436169116444686">"Yardım və rəy"</string>
+</resources>
diff --git a/packages/SettingsLib/HelpUtils/res/values-b+sr+Latn/strings.xml b/packages/SettingsLib/HelpUtils/res/values-b+sr+Latn/strings.xml
new file mode 100644
index 000000000000..af5aee764e6f
--- /dev/null
+++ b/packages/SettingsLib/HelpUtils/res/values-b+sr+Latn/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright (C) 2018 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="help_feedback_label" msgid="4550436169116444686">"Pomoć i povratne informacije"</string>
+</resources>
diff --git a/packages/SettingsLib/HelpUtils/res/values-be/strings.xml b/packages/SettingsLib/HelpUtils/res/values-be/strings.xml
new file mode 100644
index 000000000000..87f8e7406610
--- /dev/null
+++ b/packages/SettingsLib/HelpUtils/res/values-be/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright (C) 2018 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="help_feedback_label" msgid="4550436169116444686">"Даведка і водгукі"</string>
+</resources>
diff --git a/packages/SettingsLib/HelpUtils/res/values-bg/strings.xml b/packages/SettingsLib/HelpUtils/res/values-bg/strings.xml
new file mode 100644
index 000000000000..d51626bc5a36
--- /dev/null
+++ b/packages/SettingsLib/HelpUtils/res/values-bg/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright (C) 2018 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="help_feedback_label" msgid="4550436169116444686">"Помощ и отзиви"</string>
+</resources>
diff --git a/packages/SettingsLib/HelpUtils/res/values-bn/strings.xml b/packages/SettingsLib/HelpUtils/res/values-bn/strings.xml
new file mode 100644
index 000000000000..57b721869f96
--- /dev/null
+++ b/packages/SettingsLib/HelpUtils/res/values-bn/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright (C) 2018 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="help_feedback_label" msgid="4550436169116444686">"সহায়তা ও মতামত"</string>
+</resources>
diff --git a/packages/SettingsLib/HelpUtils/res/values-bs/strings.xml b/packages/SettingsLib/HelpUtils/res/values-bs/strings.xml
new file mode 100644
index 000000000000..af5aee764e6f
--- /dev/null
+++ b/packages/SettingsLib/HelpUtils/res/values-bs/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright (C) 2018 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="help_feedback_label" msgid="4550436169116444686">"Pomoć i povratne informacije"</string>
+</resources>
diff --git a/packages/SettingsLib/HelpUtils/res/values-ca/strings.xml b/packages/SettingsLib/HelpUtils/res/values-ca/strings.xml
new file mode 100644
index 000000000000..b62c6cda0b35
--- /dev/null
+++ b/packages/SettingsLib/HelpUtils/res/values-ca/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright (C) 2018 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="help_feedback_label" msgid="4550436169116444686">"Ajuda i suggeriments"</string>
+</resources>
diff --git a/packages/SettingsLib/HelpUtils/res/values-cs/strings.xml b/packages/SettingsLib/HelpUtils/res/values-cs/strings.xml
new file mode 100644
index 000000000000..2da1b9c63818
--- /dev/null
+++ b/packages/SettingsLib/HelpUtils/res/values-cs/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright (C) 2018 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="help_feedback_label" msgid="4550436169116444686">"Nápověda a zpětná vazba"</string>
+</resources>
diff --git a/packages/SettingsLib/HelpUtils/res/values-da/strings.xml b/packages/SettingsLib/HelpUtils/res/values-da/strings.xml
new file mode 100644
index 000000000000..4f3647437124
--- /dev/null
+++ b/packages/SettingsLib/HelpUtils/res/values-da/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright (C) 2018 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="help_feedback_label" msgid="4550436169116444686">"Hjælp og feedback"</string>
+</resources>
diff --git a/packages/SettingsLib/HelpUtils/res/values-de/strings.xml b/packages/SettingsLib/HelpUtils/res/values-de/strings.xml
new file mode 100644
index 000000000000..e82e92bbb647
--- /dev/null
+++ b/packages/SettingsLib/HelpUtils/res/values-de/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright (C) 2018 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="help_feedback_label" msgid="4550436169116444686">"Hilfe &amp; Feedback"</string>
+</resources>
diff --git a/packages/SettingsLib/HelpUtils/res/values-el/strings.xml b/packages/SettingsLib/HelpUtils/res/values-el/strings.xml
new file mode 100644
index 000000000000..bd41d3e61b35
--- /dev/null
+++ b/packages/SettingsLib/HelpUtils/res/values-el/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright (C) 2018 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="help_feedback_label" msgid="4550436169116444686">"Βοήθεια και σχόλια"</string>
+</resources>
diff --git a/packages/SettingsLib/HelpUtils/res/values-en-rAU/strings.xml b/packages/SettingsLib/HelpUtils/res/values-en-rAU/strings.xml
new file mode 100644
index 000000000000..dce3496ac80e
--- /dev/null
+++ b/packages/SettingsLib/HelpUtils/res/values-en-rAU/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright (C) 2018 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="help_feedback_label" msgid="4550436169116444686">"Help &amp; feedback"</string>
+</resources>
diff --git a/packages/SettingsLib/HelpUtils/res/values-en-rCA/strings.xml b/packages/SettingsLib/HelpUtils/res/values-en-rCA/strings.xml
new file mode 100644
index 000000000000..dce3496ac80e
--- /dev/null
+++ b/packages/SettingsLib/HelpUtils/res/values-en-rCA/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright (C) 2018 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="help_feedback_label" msgid="4550436169116444686">"Help &amp; feedback"</string>
+</resources>
diff --git a/packages/SettingsLib/HelpUtils/res/values-en-rGB/strings.xml b/packages/SettingsLib/HelpUtils/res/values-en-rGB/strings.xml
new file mode 100644
index 000000000000..dce3496ac80e
--- /dev/null
+++ b/packages/SettingsLib/HelpUtils/res/values-en-rGB/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright (C) 2018 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="help_feedback_label" msgid="4550436169116444686">"Help &amp; feedback"</string>
+</resources>
diff --git a/packages/SettingsLib/HelpUtils/res/values-en-rIN/strings.xml b/packages/SettingsLib/HelpUtils/res/values-en-rIN/strings.xml
new file mode 100644
index 000000000000..dce3496ac80e
--- /dev/null
+++ b/packages/SettingsLib/HelpUtils/res/values-en-rIN/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright (C) 2018 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="help_feedback_label" msgid="4550436169116444686">"Help &amp; feedback"</string>
+</resources>
diff --git a/packages/SettingsLib/HelpUtils/res/values-en-rXC/strings.xml b/packages/SettingsLib/HelpUtils/res/values-en-rXC/strings.xml
new file mode 100644
index 000000000000..21084fbc0cea
--- /dev/null
+++ b/packages/SettingsLib/HelpUtils/res/values-en-rXC/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright (C) 2018 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="help_feedback_label" msgid="4550436169116444686">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‎‏‏‏‏‏‏‎‎‏‎‎‏‏‎‎‏‏‎‎‏‎‏‏‎‎‏‎‏‏‎‎‎‏‎‏‎‎‏‎‏‎‎‎‏‏‎‎‏‏‎‏‎‎‎‎‎‎‎‏‏‏‎‎Help &amp; feedback‎‏‎‎‏‎"</string>
+</resources>
diff --git a/packages/SettingsLib/HelpUtils/res/values-es-rUS/strings.xml b/packages/SettingsLib/HelpUtils/res/values-es-rUS/strings.xml
new file mode 100644
index 000000000000..3bc97c6a5dab
--- /dev/null
+++ b/packages/SettingsLib/HelpUtils/res/values-es-rUS/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright (C) 2018 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="help_feedback_label" msgid="4550436169116444686">"Ayuda y comentarios"</string>
+</resources>
diff --git a/packages/SettingsLib/HelpUtils/res/values-es/strings.xml b/packages/SettingsLib/HelpUtils/res/values-es/strings.xml
new file mode 100644
index 000000000000..85670188c67d
--- /dev/null
+++ b/packages/SettingsLib/HelpUtils/res/values-es/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright (C) 2018 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="help_feedback_label" msgid="4550436169116444686">"Ayuda y sugerencias"</string>
+</resources>
diff --git a/packages/SettingsLib/HelpUtils/res/values-et/strings.xml b/packages/SettingsLib/HelpUtils/res/values-et/strings.xml
new file mode 100644
index 000000000000..177c3e0b5153
--- /dev/null
+++ b/packages/SettingsLib/HelpUtils/res/values-et/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright (C) 2018 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="help_feedback_label" msgid="4550436169116444686">"Abi ja tagasiside"</string>
+</resources>
diff --git a/packages/SettingsLib/HelpUtils/res/values-eu/strings.xml b/packages/SettingsLib/HelpUtils/res/values-eu/strings.xml
new file mode 100644
index 000000000000..ff22ba5e3b9f
--- /dev/null
+++ b/packages/SettingsLib/HelpUtils/res/values-eu/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright (C) 2018 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="help_feedback_label" msgid="4550436169116444686">"Laguntza eta iritziak"</string>
+</resources>
diff --git a/packages/SettingsLib/HelpUtils/res/values-fa/strings.xml b/packages/SettingsLib/HelpUtils/res/values-fa/strings.xml
new file mode 100644
index 000000000000..d07d8f6bad7a
--- /dev/null
+++ b/packages/SettingsLib/HelpUtils/res/values-fa/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright (C) 2018 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="help_feedback_label" msgid="4550436169116444686">"راهنما و بازخورد"</string>
+</resources>
diff --git a/packages/SettingsLib/HelpUtils/res/values-fi/strings.xml b/packages/SettingsLib/HelpUtils/res/values-fi/strings.xml
new file mode 100644
index 000000000000..e94ebc5b86e8
--- /dev/null
+++ b/packages/SettingsLib/HelpUtils/res/values-fi/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright (C) 2018 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="help_feedback_label" msgid="4550436169116444686">"Ohje ja palaute"</string>
+</resources>
diff --git a/packages/SettingsLib/HelpUtils/res/values-fr-rCA/strings.xml b/packages/SettingsLib/HelpUtils/res/values-fr-rCA/strings.xml
new file mode 100644
index 000000000000..fd59425b978b
--- /dev/null
+++ b/packages/SettingsLib/HelpUtils/res/values-fr-rCA/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright (C) 2018 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="help_feedback_label" msgid="4550436169116444686">"Aide et rétroaction"</string>
+</resources>
diff --git a/packages/SettingsLib/HelpUtils/res/values-fr/strings.xml b/packages/SettingsLib/HelpUtils/res/values-fr/strings.xml
new file mode 100644
index 000000000000..23f0b3b801c0
--- /dev/null
+++ b/packages/SettingsLib/HelpUtils/res/values-fr/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright (C) 2018 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="help_feedback_label" msgid="4550436169116444686">"Aide et commentaires"</string>
+</resources>
diff --git a/packages/SettingsLib/HelpUtils/res/values-gl/strings.xml b/packages/SettingsLib/HelpUtils/res/values-gl/strings.xml
new file mode 100644
index 000000000000..c8cc6b63fc6d
--- /dev/null
+++ b/packages/SettingsLib/HelpUtils/res/values-gl/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright (C) 2018 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="help_feedback_label" msgid="4550436169116444686">"Axuda e comentarios"</string>
+</resources>
diff --git a/packages/SettingsLib/HelpUtils/res/values-gu/strings.xml b/packages/SettingsLib/HelpUtils/res/values-gu/strings.xml
new file mode 100644
index 000000000000..a53c6d2f0430
--- /dev/null
+++ b/packages/SettingsLib/HelpUtils/res/values-gu/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright (C) 2018 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="help_feedback_label" msgid="4550436169116444686">"સહાય અને પ્રતિસાદ"</string>
+</resources>
diff --git a/packages/SettingsLib/HelpUtils/res/values-hr/strings.xml b/packages/SettingsLib/HelpUtils/res/values-hr/strings.xml
new file mode 100644
index 000000000000..af5aee764e6f
--- /dev/null
+++ b/packages/SettingsLib/HelpUtils/res/values-hr/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright (C) 2018 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="help_feedback_label" msgid="4550436169116444686">"Pomoć i povratne informacije"</string>
+</resources>
diff --git a/packages/SettingsLib/HelpUtils/res/values-hu/strings.xml b/packages/SettingsLib/HelpUtils/res/values-hu/strings.xml
new file mode 100644
index 000000000000..bcf2734f6932
--- /dev/null
+++ b/packages/SettingsLib/HelpUtils/res/values-hu/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright (C) 2018 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="help_feedback_label" msgid="4550436169116444686">"Súgó és visszajelzés"</string>
+</resources>
diff --git a/packages/SettingsLib/HelpUtils/res/values-hy/strings.xml b/packages/SettingsLib/HelpUtils/res/values-hy/strings.xml
new file mode 100644
index 000000000000..ea14fa565f80
--- /dev/null
+++ b/packages/SettingsLib/HelpUtils/res/values-hy/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright (C) 2018 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="help_feedback_label" msgid="4550436169116444686">"Օգնություն և հետադարձ կապ"</string>
+</resources>
diff --git a/packages/SettingsLib/HelpUtils/res/values-in/strings.xml b/packages/SettingsLib/HelpUtils/res/values-in/strings.xml
new file mode 100644
index 000000000000..3055c7f93640
--- /dev/null
+++ b/packages/SettingsLib/HelpUtils/res/values-in/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright (C) 2018 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="help_feedback_label" msgid="4550436169116444686">"Bantuan &amp; masukan"</string>
+</resources>
diff --git a/packages/SettingsLib/HelpUtils/res/values-is/strings.xml b/packages/SettingsLib/HelpUtils/res/values-is/strings.xml
new file mode 100644
index 000000000000..1feaf4a35549
--- /dev/null
+++ b/packages/SettingsLib/HelpUtils/res/values-is/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright (C) 2018 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="help_feedback_label" msgid="4550436169116444686">"Hjálp og ábendingar"</string>
+</resources>
diff --git a/packages/SettingsLib/HelpUtils/res/values-it/strings.xml b/packages/SettingsLib/HelpUtils/res/values-it/strings.xml
new file mode 100644
index 000000000000..8e4d78d8285c
--- /dev/null
+++ b/packages/SettingsLib/HelpUtils/res/values-it/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright (C) 2018 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="help_feedback_label" msgid="4550436169116444686">"Guida e feedback"</string>
+</resources>
diff --git a/packages/SettingsLib/HelpUtils/res/values-iw/strings.xml b/packages/SettingsLib/HelpUtils/res/values-iw/strings.xml
new file mode 100644
index 000000000000..ab52996d8d97
--- /dev/null
+++ b/packages/SettingsLib/HelpUtils/res/values-iw/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright (C) 2018 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="help_feedback_label" msgid="4550436169116444686">"עזרה ומשוב"</string>
+</resources>
diff --git a/packages/SettingsLib/HelpUtils/res/values-ja/strings.xml b/packages/SettingsLib/HelpUtils/res/values-ja/strings.xml
new file mode 100644
index 000000000000..8c75d3238e06
--- /dev/null
+++ b/packages/SettingsLib/HelpUtils/res/values-ja/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright (C) 2018 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="help_feedback_label" msgid="4550436169116444686">"ヘルプとフィードバック"</string>
+</resources>
diff --git a/packages/SettingsLib/HelpUtils/res/values-ka/strings.xml b/packages/SettingsLib/HelpUtils/res/values-ka/strings.xml
new file mode 100644
index 000000000000..53b956ffd006
--- /dev/null
+++ b/packages/SettingsLib/HelpUtils/res/values-ka/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright (C) 2018 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="help_feedback_label" msgid="4550436169116444686">"დახმარება და გამოხმაურება"</string>
+</resources>
diff --git a/packages/SettingsLib/HelpUtils/res/values-kk/strings.xml b/packages/SettingsLib/HelpUtils/res/values-kk/strings.xml
new file mode 100644
index 000000000000..ef351ac0ad3e
--- /dev/null
+++ b/packages/SettingsLib/HelpUtils/res/values-kk/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright (C) 2018 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="help_feedback_label" msgid="4550436169116444686">"Анықтама және пікір"</string>
+</resources>
diff --git a/packages/SettingsLib/HelpUtils/res/values-km/strings.xml b/packages/SettingsLib/HelpUtils/res/values-km/strings.xml
new file mode 100644
index 000000000000..b2b0615cd679
--- /dev/null
+++ b/packages/SettingsLib/HelpUtils/res/values-km/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright (C) 2018 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="help_feedback_label" msgid="4550436169116444686">"ជំនួយ និងមតិកែលម្អ"</string>
+</resources>
diff --git a/packages/SettingsLib/HelpUtils/res/values-kn/strings.xml b/packages/SettingsLib/HelpUtils/res/values-kn/strings.xml
new file mode 100644
index 000000000000..8a86559aa6a7
--- /dev/null
+++ b/packages/SettingsLib/HelpUtils/res/values-kn/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright (C) 2018 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="help_feedback_label" msgid="4550436169116444686">"ಸಹಾಯ ಮತ್ತು ಪ್ರತಿಕ್ರಿಯೆ"</string>
+</resources>
diff --git a/packages/SettingsLib/HelpUtils/res/values-ko/strings.xml b/packages/SettingsLib/HelpUtils/res/values-ko/strings.xml
new file mode 100644
index 000000000000..f974a510628d
--- /dev/null
+++ b/packages/SettingsLib/HelpUtils/res/values-ko/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright (C) 2018 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="help_feedback_label" msgid="4550436169116444686">"도움말 및 의견"</string>
+</resources>
diff --git a/packages/SettingsLib/HelpUtils/res/values-ky/strings.xml b/packages/SettingsLib/HelpUtils/res/values-ky/strings.xml
new file mode 100644
index 000000000000..3c0cf8749bf3
--- /dev/null
+++ b/packages/SettingsLib/HelpUtils/res/values-ky/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright (C) 2018 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="help_feedback_label" msgid="4550436169116444686">"Жардам/Пикир билдирүү"</string>
+</resources>
diff --git a/packages/SettingsLib/HelpUtils/res/values-lo/strings.xml b/packages/SettingsLib/HelpUtils/res/values-lo/strings.xml
new file mode 100644
index 000000000000..3765d6e4bff4
--- /dev/null
+++ b/packages/SettingsLib/HelpUtils/res/values-lo/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright (C) 2018 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="help_feedback_label" msgid="4550436169116444686">"ຊ່ວຍເຫຼືອ ແລະ ຕິຊົມ"</string>
+</resources>
diff --git a/packages/SettingsLib/HelpUtils/res/values-lt/strings.xml b/packages/SettingsLib/HelpUtils/res/values-lt/strings.xml
new file mode 100644
index 000000000000..d7bce29e7320
--- /dev/null
+++ b/packages/SettingsLib/HelpUtils/res/values-lt/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright (C) 2018 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="help_feedback_label" msgid="4550436169116444686">"Pagalba ir atsiliepimai"</string>
+</resources>
diff --git a/packages/SettingsLib/HelpUtils/res/values-lv/strings.xml b/packages/SettingsLib/HelpUtils/res/values-lv/strings.xml
new file mode 100644
index 000000000000..77496a99c2b4
--- /dev/null
+++ b/packages/SettingsLib/HelpUtils/res/values-lv/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright (C) 2018 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="help_feedback_label" msgid="4550436169116444686">"Palīdzība un atsauksmes"</string>
+</resources>
diff --git a/packages/SettingsLib/HelpUtils/res/values-mk/strings.xml b/packages/SettingsLib/HelpUtils/res/values-mk/strings.xml
new file mode 100644
index 000000000000..516c18645cb9
--- /dev/null
+++ b/packages/SettingsLib/HelpUtils/res/values-mk/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright (C) 2018 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="help_feedback_label" msgid="4550436169116444686">"Помош и повратни информации"</string>
+</resources>
diff --git a/packages/SettingsLib/HelpUtils/res/values-ml/strings.xml b/packages/SettingsLib/HelpUtils/res/values-ml/strings.xml
new file mode 100644
index 000000000000..d2a7452ecb5c
--- /dev/null
+++ b/packages/SettingsLib/HelpUtils/res/values-ml/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright (C) 2018 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="help_feedback_label" msgid="4550436169116444686">"സഹായം &amp; ഫീഡ്‌ബാക്ക്"</string>
+</resources>
diff --git a/packages/SettingsLib/HelpUtils/res/values-mn/strings.xml b/packages/SettingsLib/HelpUtils/res/values-mn/strings.xml
new file mode 100644
index 000000000000..c3ebe8b07744
--- /dev/null
+++ b/packages/SettingsLib/HelpUtils/res/values-mn/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright (C) 2018 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="help_feedback_label" msgid="4550436169116444686">"Тусламж &amp; санал хүсэлт"</string>
+</resources>
diff --git a/packages/SettingsLib/HelpUtils/res/values-mr/strings.xml b/packages/SettingsLib/HelpUtils/res/values-mr/strings.xml
new file mode 100644
index 000000000000..7f3a881afbbe
--- /dev/null
+++ b/packages/SettingsLib/HelpUtils/res/values-mr/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright (C) 2018 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="help_feedback_label" msgid="4550436169116444686">"मदत आणि फीडबॅक"</string>
+</resources>
diff --git a/packages/SettingsLib/HelpUtils/res/values-ms/strings.xml b/packages/SettingsLib/HelpUtils/res/values-ms/strings.xml
new file mode 100644
index 000000000000..7c7c97168e70
--- /dev/null
+++ b/packages/SettingsLib/HelpUtils/res/values-ms/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright (C) 2018 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="help_feedback_label" msgid="4550436169116444686">"Bantuan &amp; maklum balas"</string>
+</resources>
diff --git a/packages/SettingsLib/HelpUtils/res/values-my/strings.xml b/packages/SettingsLib/HelpUtils/res/values-my/strings.xml
new file mode 100644
index 000000000000..f051860adff9
--- /dev/null
+++ b/packages/SettingsLib/HelpUtils/res/values-my/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright (C) 2018 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="help_feedback_label" msgid="4550436169116444686">"အကူအညီနှင့် အကြံပြုချက်"</string>
+</resources>
diff --git a/packages/SettingsLib/HelpUtils/res/values-nb/strings.xml b/packages/SettingsLib/HelpUtils/res/values-nb/strings.xml
new file mode 100644
index 000000000000..96886f6118e0
--- /dev/null
+++ b/packages/SettingsLib/HelpUtils/res/values-nb/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright (C) 2018 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="help_feedback_label" msgid="4550436169116444686">"Hjelp og tilbakemelding"</string>
+</resources>
diff --git a/packages/SettingsLib/HelpUtils/res/values-ne/strings.xml b/packages/SettingsLib/HelpUtils/res/values-ne/strings.xml
new file mode 100644
index 000000000000..40508ad25b3a
--- /dev/null
+++ b/packages/SettingsLib/HelpUtils/res/values-ne/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright (C) 2018 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="help_feedback_label" msgid="4550436169116444686">"मद्दत र प्रतिक्रिया"</string>
+</resources>
diff --git a/packages/SettingsLib/HelpUtils/res/values-nl/strings.xml b/packages/SettingsLib/HelpUtils/res/values-nl/strings.xml
new file mode 100644
index 000000000000..a034d297bac8
--- /dev/null
+++ b/packages/SettingsLib/HelpUtils/res/values-nl/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright (C) 2018 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="help_feedback_label" msgid="4550436169116444686">"Help en feedback"</string>
+</resources>
diff --git a/packages/SettingsLib/HelpUtils/res/values-or/strings.xml b/packages/SettingsLib/HelpUtils/res/values-or/strings.xml
new file mode 100644
index 000000000000..e91cb61c8ca3
--- /dev/null
+++ b/packages/SettingsLib/HelpUtils/res/values-or/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright (C) 2018 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="help_feedback_label" msgid="4550436169116444686">"ସହାୟତା ଓ ମତାମତ"</string>
+</resources>
diff --git a/packages/SettingsLib/HelpUtils/res/values-pa/strings.xml b/packages/SettingsLib/HelpUtils/res/values-pa/strings.xml
new file mode 100644
index 000000000000..d847a5954bf0
--- /dev/null
+++ b/packages/SettingsLib/HelpUtils/res/values-pa/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright (C) 2018 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="help_feedback_label" msgid="4550436169116444686">"ਮਦਦ ਅਤੇ ਵਿਚਾਰ"</string>
+</resources>
diff --git a/packages/SettingsLib/HelpUtils/res/values-pl/strings.xml b/packages/SettingsLib/HelpUtils/res/values-pl/strings.xml
new file mode 100644
index 000000000000..e137a6bb8ebc
--- /dev/null
+++ b/packages/SettingsLib/HelpUtils/res/values-pl/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright (C) 2018 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="help_feedback_label" msgid="4550436169116444686">"Pomoc i opinie"</string>
+</resources>
diff --git a/packages/SettingsLib/HelpUtils/res/values-pt-rBR/strings.xml b/packages/SettingsLib/HelpUtils/res/values-pt-rBR/strings.xml
new file mode 100644
index 000000000000..73dfc49d7937
--- /dev/null
+++ b/packages/SettingsLib/HelpUtils/res/values-pt-rBR/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright (C) 2018 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="help_feedback_label" msgid="4550436169116444686">"Ajuda e feedback"</string>
+</resources>
diff --git a/packages/SettingsLib/HelpUtils/res/values-pt-rPT/strings.xml b/packages/SettingsLib/HelpUtils/res/values-pt-rPT/strings.xml
new file mode 100644
index 000000000000..baac2e872b20
--- /dev/null
+++ b/packages/SettingsLib/HelpUtils/res/values-pt-rPT/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright (C) 2018 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="help_feedback_label" msgid="4550436169116444686">"Ajuda e comentários"</string>
+</resources>
diff --git a/packages/SettingsLib/HelpUtils/res/values-pt/strings.xml b/packages/SettingsLib/HelpUtils/res/values-pt/strings.xml
new file mode 100644
index 000000000000..73dfc49d7937
--- /dev/null
+++ b/packages/SettingsLib/HelpUtils/res/values-pt/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright (C) 2018 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="help_feedback_label" msgid="4550436169116444686">"Ajuda e feedback"</string>
+</resources>
diff --git a/packages/SettingsLib/HelpUtils/res/values-ro/strings.xml b/packages/SettingsLib/HelpUtils/res/values-ro/strings.xml
new file mode 100644
index 000000000000..142291259174
--- /dev/null
+++ b/packages/SettingsLib/HelpUtils/res/values-ro/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright (C) 2018 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="help_feedback_label" msgid="4550436169116444686">"Ajutor și feedback"</string>
+</resources>
diff --git a/packages/SettingsLib/HelpUtils/res/values-ru/strings.xml b/packages/SettingsLib/HelpUtils/res/values-ru/strings.xml
new file mode 100644
index 000000000000..d7d1108814bb
--- /dev/null
+++ b/packages/SettingsLib/HelpUtils/res/values-ru/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright (C) 2018 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="help_feedback_label" msgid="4550436169116444686">"Справка и отзывы"</string>
+</resources>
diff --git a/packages/SettingsLib/HelpUtils/res/values-si/strings.xml b/packages/SettingsLib/HelpUtils/res/values-si/strings.xml
new file mode 100644
index 000000000000..719d7dc5476d
--- /dev/null
+++ b/packages/SettingsLib/HelpUtils/res/values-si/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright (C) 2018 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="help_feedback_label" msgid="4550436169116444686">"උදවු සහ ප්‍රතිපෝෂණ"</string>
+</resources>
diff --git a/packages/SettingsLib/HelpUtils/res/values-sk/strings.xml b/packages/SettingsLib/HelpUtils/res/values-sk/strings.xml
new file mode 100644
index 000000000000..a9eede3d6b53
--- /dev/null
+++ b/packages/SettingsLib/HelpUtils/res/values-sk/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright (C) 2018 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="help_feedback_label" msgid="4550436169116444686">"Pomocník a spätná väzba"</string>
+</resources>
diff --git a/packages/SettingsLib/HelpUtils/res/values-sl/strings.xml b/packages/SettingsLib/HelpUtils/res/values-sl/strings.xml
new file mode 100644
index 000000000000..81db7448731d
--- /dev/null
+++ b/packages/SettingsLib/HelpUtils/res/values-sl/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright (C) 2018 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="help_feedback_label" msgid="4550436169116444686">"Pomoč in povratne informacije"</string>
+</resources>
diff --git a/packages/SettingsLib/HelpUtils/res/values-sq/strings.xml b/packages/SettingsLib/HelpUtils/res/values-sq/strings.xml
new file mode 100644
index 000000000000..fddeff6acd49
--- /dev/null
+++ b/packages/SettingsLib/HelpUtils/res/values-sq/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright (C) 2018 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="help_feedback_label" msgid="4550436169116444686">"Ndihma dhe komentet"</string>
+</resources>
diff --git a/packages/SettingsLib/HelpUtils/res/values-sr/strings.xml b/packages/SettingsLib/HelpUtils/res/values-sr/strings.xml
new file mode 100644
index 000000000000..5d258060c5dc
--- /dev/null
+++ b/packages/SettingsLib/HelpUtils/res/values-sr/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright (C) 2018 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="help_feedback_label" msgid="4550436169116444686">"Помоћ и повратне информације"</string>
+</resources>
diff --git a/packages/SettingsLib/HelpUtils/res/values-sv/strings.xml b/packages/SettingsLib/HelpUtils/res/values-sv/strings.xml
new file mode 100644
index 000000000000..df1c89105a3f
--- /dev/null
+++ b/packages/SettingsLib/HelpUtils/res/values-sv/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright (C) 2018 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="help_feedback_label" msgid="4550436169116444686">"Hjälp och feedback"</string>
+</resources>
diff --git a/packages/SettingsLib/HelpUtils/res/values-sw/strings.xml b/packages/SettingsLib/HelpUtils/res/values-sw/strings.xml
new file mode 100644
index 000000000000..a4bb7266b2c6
--- /dev/null
+++ b/packages/SettingsLib/HelpUtils/res/values-sw/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright (C) 2018 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="help_feedback_label" msgid="4550436169116444686">"Usaidizi na maoni"</string>
+</resources>
diff --git a/packages/SettingsLib/HelpUtils/res/values-ta/strings.xml b/packages/SettingsLib/HelpUtils/res/values-ta/strings.xml
new file mode 100644
index 000000000000..91e8e46e63ea
--- /dev/null
+++ b/packages/SettingsLib/HelpUtils/res/values-ta/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright (C) 2018 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="help_feedback_label" msgid="4550436169116444686">"உதவி &amp; கருத்து"</string>
+</resources>
diff --git a/packages/SettingsLib/HelpUtils/res/values-te/strings.xml b/packages/SettingsLib/HelpUtils/res/values-te/strings.xml
new file mode 100644
index 000000000000..753b3207864b
--- /dev/null
+++ b/packages/SettingsLib/HelpUtils/res/values-te/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright (C) 2018 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="help_feedback_label" msgid="4550436169116444686">"సహాయం &amp; అభిప్రాయం"</string>
+</resources>
diff --git a/packages/SettingsLib/HelpUtils/res/values-th/strings.xml b/packages/SettingsLib/HelpUtils/res/values-th/strings.xml
new file mode 100644
index 000000000000..53d16a67f4cd
--- /dev/null
+++ b/packages/SettingsLib/HelpUtils/res/values-th/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright (C) 2018 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="help_feedback_label" msgid="4550436169116444686">"ความช่วยเหลือและความคิดเห็น"</string>
+</resources>
diff --git a/packages/SettingsLib/HelpUtils/res/values-tl/strings.xml b/packages/SettingsLib/HelpUtils/res/values-tl/strings.xml
new file mode 100644
index 000000000000..7edcd18cb8eb
--- /dev/null
+++ b/packages/SettingsLib/HelpUtils/res/values-tl/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright (C) 2018 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="help_feedback_label" msgid="4550436169116444686">"Tulong at feedback"</string>
+</resources>
diff --git a/packages/SettingsLib/HelpUtils/res/values-tr/strings.xml b/packages/SettingsLib/HelpUtils/res/values-tr/strings.xml
new file mode 100644
index 000000000000..263226fada7a
--- /dev/null
+++ b/packages/SettingsLib/HelpUtils/res/values-tr/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright (C) 2018 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="help_feedback_label" msgid="4550436169116444686">"Yardım ve geri bildirim"</string>
+</resources>
diff --git a/packages/SettingsLib/HelpUtils/res/values-uk/strings.xml b/packages/SettingsLib/HelpUtils/res/values-uk/strings.xml
new file mode 100644
index 000000000000..ebef521c5cae
--- /dev/null
+++ b/packages/SettingsLib/HelpUtils/res/values-uk/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright (C) 2018 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="help_feedback_label" msgid="4550436169116444686">"Довідка й відгуки"</string>
+</resources>
diff --git a/packages/SettingsLib/HelpUtils/res/values-ur/strings.xml b/packages/SettingsLib/HelpUtils/res/values-ur/strings.xml
new file mode 100644
index 000000000000..084bf29a182c
--- /dev/null
+++ b/packages/SettingsLib/HelpUtils/res/values-ur/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright (C) 2018 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="help_feedback_label" msgid="4550436169116444686">"مدد اور تاثرات"</string>
+</resources>
diff --git a/packages/SettingsLib/HelpUtils/res/values-uz/strings.xml b/packages/SettingsLib/HelpUtils/res/values-uz/strings.xml
new file mode 100644
index 000000000000..2106bed282f9
--- /dev/null
+++ b/packages/SettingsLib/HelpUtils/res/values-uz/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright (C) 2018 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="help_feedback_label" msgid="4550436169116444686">"Yordam va fikr-mulohaza"</string>
+</resources>
diff --git a/packages/SettingsLib/HelpUtils/res/values-vi/strings.xml b/packages/SettingsLib/HelpUtils/res/values-vi/strings.xml
new file mode 100644
index 000000000000..68ce6d1dcd06
--- /dev/null
+++ b/packages/SettingsLib/HelpUtils/res/values-vi/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright (C) 2018 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="help_feedback_label" msgid="4550436169116444686">"Trợ giúp &amp; phản hồi"</string>
+</resources>
diff --git a/packages/SettingsLib/HelpUtils/res/values-zh-rCN/strings.xml b/packages/SettingsLib/HelpUtils/res/values-zh-rCN/strings.xml
new file mode 100644
index 000000000000..a6d9f497aaab
--- /dev/null
+++ b/packages/SettingsLib/HelpUtils/res/values-zh-rCN/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright (C) 2018 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="help_feedback_label" msgid="4550436169116444686">"帮助和反馈"</string>
+</resources>
diff --git a/packages/SettingsLib/HelpUtils/res/values-zh-rHK/strings.xml b/packages/SettingsLib/HelpUtils/res/values-zh-rHK/strings.xml
new file mode 100644
index 000000000000..a6eae048ca52
--- /dev/null
+++ b/packages/SettingsLib/HelpUtils/res/values-zh-rHK/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright (C) 2018 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="help_feedback_label" msgid="4550436169116444686">"說明與意見反映"</string>
+</resources>
diff --git a/packages/SettingsLib/HelpUtils/res/values-zh-rTW/strings.xml b/packages/SettingsLib/HelpUtils/res/values-zh-rTW/strings.xml
new file mode 100644
index 000000000000..d66802cf580b
--- /dev/null
+++ b/packages/SettingsLib/HelpUtils/res/values-zh-rTW/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright (C) 2018 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="help_feedback_label" msgid="4550436169116444686">"說明與意見回饋"</string>
+</resources>
diff --git a/packages/SettingsLib/HelpUtils/res/values-zu/strings.xml b/packages/SettingsLib/HelpUtils/res/values-zu/strings.xml
new file mode 100644
index 000000000000..32993ce8e1a1
--- /dev/null
+++ b/packages/SettingsLib/HelpUtils/res/values-zu/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright (C) 2018 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="help_feedback_label" msgid="4550436169116444686">"Usizo nempendulo"</string>
+</resources>
diff --git a/packages/SettingsLib/res/values-af/strings.xml b/packages/SettingsLib/res/values-af/strings.xml
index 296a135a9d8a..aa96444cac48 100644
--- a/packages/SettingsLib/res/values-af/strings.xml
+++ b/packages/SettingsLib/res/values-af/strings.xml
@@ -415,7 +415,6 @@
<string name="screen_zoom_summary_very_large" msgid="7108563375663670067">"Groter"</string>
<string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"Grootste"</string>
<string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Gepasmaak (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
- <string name="help_feedback_label" msgid="6815040660801785649">"Hulp en terugvoer"</string>
<string name="content_description_menu_button" msgid="8182594799812351266">"Kieslys"</string>
<string name="retail_demo_reset_message" msgid="118771671364131297">"Voer wagwoord in om fabriekterugstelling in demonstrasiemodus uit te voer"</string>
<string name="retail_demo_reset_next" msgid="8356731459226304963">"Volgende"</string>
diff --git a/packages/SettingsLib/res/values-am/strings.xml b/packages/SettingsLib/res/values-am/strings.xml
index ab52bcb0cf76..452206c61c14 100644
--- a/packages/SettingsLib/res/values-am/strings.xml
+++ b/packages/SettingsLib/res/values-am/strings.xml
@@ -415,7 +415,6 @@
<string name="screen_zoom_summary_very_large" msgid="7108563375663670067">"ተለቅ ያለ"</string>
<string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"በጣም ተለቅ ያለ"</string>
<string name="screen_zoom_summary_custom" msgid="5611979864124160447">"ብጁ (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
- <string name="help_feedback_label" msgid="6815040660801785649">"እገዛ እና ግብረመልስ"</string>
<string name="content_description_menu_button" msgid="8182594799812351266">"ምናሌ"</string>
<string name="retail_demo_reset_message" msgid="118771671364131297">"የፋብሪካ ዳግም ማስጀመር በማሳያ ሁነታ ውስጥ ለማከናወን የይለፍ ቃል ያስገቡ"</string>
<string name="retail_demo_reset_next" msgid="8356731459226304963">"ቀጣይ"</string>
diff --git a/packages/SettingsLib/res/values-ar/strings.xml b/packages/SettingsLib/res/values-ar/strings.xml
index e8811eb6c724..e67e1ecf0c13 100644
--- a/packages/SettingsLib/res/values-ar/strings.xml
+++ b/packages/SettingsLib/res/values-ar/strings.xml
@@ -415,7 +415,6 @@
<string name="screen_zoom_summary_very_large" msgid="7108563375663670067">"أكبر"</string>
<string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"أكبر مستوى"</string>
<string name="screen_zoom_summary_custom" msgid="5611979864124160447">"مخصص (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
- <string name="help_feedback_label" msgid="6815040660801785649">"المساعدة والتعليقات"</string>
<string name="content_description_menu_button" msgid="8182594799812351266">"القائمة"</string>
<string name="retail_demo_reset_message" msgid="118771671364131297">"إدخال كلمة المرور لإعادة الضبط بحسب بيانات المصنع في الوضع التجريبي"</string>
<string name="retail_demo_reset_next" msgid="8356731459226304963">"التالي"</string>
diff --git a/packages/SettingsLib/res/values-as/strings.xml b/packages/SettingsLib/res/values-as/strings.xml
index 0adac28fc7b8..7311661ff9e3 100644
--- a/packages/SettingsLib/res/values-as/strings.xml
+++ b/packages/SettingsLib/res/values-as/strings.xml
@@ -415,7 +415,6 @@
<string name="screen_zoom_summary_very_large" msgid="7108563375663670067">"বৃহত্তৰ"</string>
<string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"সকলোতকৈ ডাঙৰ"</string>
<string name="screen_zoom_summary_custom" msgid="5611979864124160447">"নিজৰ উপযোগিতা অনুযায়ী (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
- <string name="help_feedback_label" msgid="6815040660801785649">"সহায় আৰু ফীডবেক"</string>
<string name="content_description_menu_button" msgid="8182594799812351266">"মেনু"</string>
<string name="retail_demo_reset_message" msgid="118771671364131297">"ডেম’ ম\'ডত ফেক্টৰী ৰিছেট কৰিবলৈ পাছৱৰ্ড দিয়ক"</string>
<string name="retail_demo_reset_next" msgid="8356731459226304963">"পৰৱৰ্তী"</string>
diff --git a/packages/SettingsLib/res/values-az/strings.xml b/packages/SettingsLib/res/values-az/strings.xml
index 8f974fef7edd..750bf5d95320 100644
--- a/packages/SettingsLib/res/values-az/strings.xml
+++ b/packages/SettingsLib/res/values-az/strings.xml
@@ -415,7 +415,6 @@
<string name="screen_zoom_summary_very_large" msgid="7108563375663670067">"Daha böyük"</string>
<string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"Ən böyük"</string>
<string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Fərdi (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
- <string name="help_feedback_label" msgid="6815040660801785649">"Yardım və rəy"</string>
<string name="content_description_menu_button" msgid="8182594799812351266">"Menyu"</string>
<string name="retail_demo_reset_message" msgid="118771671364131297">"Demo rejimində sıfırlamaq üçün parol daxil edin"</string>
<string name="retail_demo_reset_next" msgid="8356731459226304963">"Növbəti"</string>
diff --git a/packages/SettingsLib/res/values-b+sr+Latn/strings.xml b/packages/SettingsLib/res/values-b+sr+Latn/strings.xml
index 1e3eba631a19..cd8096c5f682 100644
--- a/packages/SettingsLib/res/values-b+sr+Latn/strings.xml
+++ b/packages/SettingsLib/res/values-b+sr+Latn/strings.xml
@@ -415,7 +415,6 @@
<string name="screen_zoom_summary_very_large" msgid="7108563375663670067">"Veći"</string>
<string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"Najveći"</string>
<string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Prilagođeni (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
- <string name="help_feedback_label" msgid="6815040660801785649">"Pomoć i povratne informacije"</string>
<string name="content_description_menu_button" msgid="8182594799812351266">"Meni"</string>
<string name="retail_demo_reset_message" msgid="118771671364131297">"Unesite lozinku da biste obavili resetovanje na fabrička podešavanja u režimu demonstracije"</string>
<string name="retail_demo_reset_next" msgid="8356731459226304963">"Dalje"</string>
diff --git a/packages/SettingsLib/res/values-be/strings.xml b/packages/SettingsLib/res/values-be/strings.xml
index 42fda63e9b4d..072913a0bc60 100644
--- a/packages/SettingsLib/res/values-be/strings.xml
+++ b/packages/SettingsLib/res/values-be/strings.xml
@@ -415,7 +415,6 @@
<string name="screen_zoom_summary_very_large" msgid="7108563375663670067">"Большы"</string>
<string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"Самы вялікі"</string>
<string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Карыстальніцкі (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
- <string name="help_feedback_label" msgid="6815040660801785649">"Даведка і водгукі"</string>
<string name="content_description_menu_button" msgid="8182594799812351266">"Меню"</string>
<string name="retail_demo_reset_message" msgid="118771671364131297">"Каб выканаць скід да заводскіх налад у дэманстрацыйным рэжыме, увядзіце пароль"</string>
<string name="retail_demo_reset_next" msgid="8356731459226304963">"Далей"</string>
diff --git a/packages/SettingsLib/res/values-bg/strings.xml b/packages/SettingsLib/res/values-bg/strings.xml
index a309449dd744..a5ce523970f0 100644
--- a/packages/SettingsLib/res/values-bg/strings.xml
+++ b/packages/SettingsLib/res/values-bg/strings.xml
@@ -415,7 +415,6 @@
<string name="screen_zoom_summary_very_large" msgid="7108563375663670067">"По-голямо"</string>
<string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"Най-голямо"</string>
<string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Персонализирано (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
- <string name="help_feedback_label" msgid="6815040660801785649">"Помощ и отзиви"</string>
<string name="content_description_menu_button" msgid="8182594799812351266">"Меню"</string>
<string name="retail_demo_reset_message" msgid="118771671364131297">"Въведете парола за възст. на фабр. настройки в демонстр. режим"</string>
<string name="retail_demo_reset_next" msgid="8356731459226304963">"Напред"</string>
diff --git a/packages/SettingsLib/res/values-bn/strings.xml b/packages/SettingsLib/res/values-bn/strings.xml
index ad4ef2f94e09..c0537717420f 100644
--- a/packages/SettingsLib/res/values-bn/strings.xml
+++ b/packages/SettingsLib/res/values-bn/strings.xml
@@ -415,7 +415,6 @@
<string name="screen_zoom_summary_very_large" msgid="7108563375663670067">"খুব বড়"</string>
<string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"বৃহত্তম"</string>
<string name="screen_zoom_summary_custom" msgid="5611979864124160447">"কাস্টম (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
- <string name="help_feedback_label" msgid="6815040660801785649">"সহায়তা ও মতামত"</string>
<string name="content_description_menu_button" msgid="8182594799812351266">"মেনু"</string>
<string name="retail_demo_reset_message" msgid="118771671364131297">"ডেমো মোডে ফ্যাক্টরি রিসেট করতে পাসওয়ার্ড দিন"</string>
<string name="retail_demo_reset_next" msgid="8356731459226304963">"পরবর্তী"</string>
diff --git a/packages/SettingsLib/res/values-bs/strings.xml b/packages/SettingsLib/res/values-bs/strings.xml
index 43326823ee68..764bc1958b68 100644
--- a/packages/SettingsLib/res/values-bs/strings.xml
+++ b/packages/SettingsLib/res/values-bs/strings.xml
@@ -415,7 +415,6 @@
<string name="screen_zoom_summary_very_large" msgid="7108563375663670067">"Vrlo veliko"</string>
<string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"Najveći"</string>
<string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Prilagodi (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
- <string name="help_feedback_label" msgid="6815040660801785649">"Pomoć i povratne informacije"</string>
<string name="content_description_menu_button" msgid="8182594799812351266">"Meni"</string>
<string name="retail_demo_reset_message" msgid="118771671364131297">"Unesite lozinku da izvršite vraćanje na fabričke postavke u načinu demonstracije"</string>
<string name="retail_demo_reset_next" msgid="8356731459226304963">"Naprijed"</string>
diff --git a/packages/SettingsLib/res/values-ca/strings.xml b/packages/SettingsLib/res/values-ca/strings.xml
index 7750ef290de9..8309c41a3ea0 100644
--- a/packages/SettingsLib/res/values-ca/strings.xml
+++ b/packages/SettingsLib/res/values-ca/strings.xml
@@ -415,7 +415,6 @@
<string name="screen_zoom_summary_very_large" msgid="7108563375663670067">"Més gran"</string>
<string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"Més grans possible"</string>
<string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Personalitzat (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
- <string name="help_feedback_label" msgid="6815040660801785649">"Ajuda i suggeriments"</string>
<string name="content_description_menu_button" msgid="8182594799812351266">"Menú"</string>
<string name="retail_demo_reset_message" msgid="118771671364131297">"Introdueix la contrasenya per restablir les dades de fàbrica en mode de demostració"</string>
<string name="retail_demo_reset_next" msgid="8356731459226304963">"Següent"</string>
diff --git a/packages/SettingsLib/res/values-cs/strings.xml b/packages/SettingsLib/res/values-cs/strings.xml
index 72b3389dd64c..bd8bc2b8b406 100644
--- a/packages/SettingsLib/res/values-cs/strings.xml
+++ b/packages/SettingsLib/res/values-cs/strings.xml
@@ -415,7 +415,6 @@
<string name="screen_zoom_summary_very_large" msgid="7108563375663670067">"Větší"</string>
<string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"Největší"</string>
<string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Vlastní (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
- <string name="help_feedback_label" msgid="6815040660801785649">"Nápověda a zpětná vazba"</string>
<string name="content_description_menu_button" msgid="8182594799812351266">"Nabídka"</string>
<string name="retail_demo_reset_message" msgid="118771671364131297">"Chcete-li v ukázkovém režimu obnovit zařízení do továrního nastavení, zadejte heslo"</string>
<string name="retail_demo_reset_next" msgid="8356731459226304963">"Další"</string>
diff --git a/packages/SettingsLib/res/values-da/strings.xml b/packages/SettingsLib/res/values-da/strings.xml
index ca960709a7c0..ab813469df52 100644
--- a/packages/SettingsLib/res/values-da/strings.xml
+++ b/packages/SettingsLib/res/values-da/strings.xml
@@ -196,7 +196,7 @@
<string name="bugreport_in_power_summary" msgid="1778455732762984579">"Vis en knap til oprettelse af fejlrapporter i menu for slukknap"</string>
<string name="keep_screen_on" msgid="1146389631208760344">"Lås ikke"</string>
<string name="keep_screen_on_summary" msgid="2173114350754293009">"Skærmen går ikke i dvale under opladning"</string>
- <string name="bt_hci_snoop_log" msgid="3340699311158865670">"Aktivér Bluetooth HCI snoop log"</string>
+ <string name="bt_hci_snoop_log" msgid="3340699311158865670">"Aktivér Bluetooth HCI spionlog"</string>
<string name="bt_hci_snoop_log_summary" msgid="366083475849911315">"Gem alle Bluetooth HCI-pakker i en fil (slå Bluetooth fra og til igen, når du har ændret denne indstilling)"</string>
<string name="oem_unlock_enable" msgid="6040763321967327691">"OEM-oplåsning"</string>
<string name="oem_unlock_enable_summary" msgid="4720281828891618376">"Tillad, at startindlæseren låses op"</string>
@@ -415,7 +415,6 @@
<string name="screen_zoom_summary_very_large" msgid="7108563375663670067">"Større"</string>
<string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"Størst"</string>
<string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Tilpasset (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
- <string name="help_feedback_label" msgid="6815040660801785649">"Hjælp og feedback"</string>
<string name="content_description_menu_button" msgid="8182594799812351266">"Menu"</string>
<string name="retail_demo_reset_message" msgid="118771671364131297">"Angiv adgangskode for at gendanne fabriksdata i demotilstand"</string>
<string name="retail_demo_reset_next" msgid="8356731459226304963">"Næste"</string>
diff --git a/packages/SettingsLib/res/values-de/strings.xml b/packages/SettingsLib/res/values-de/strings.xml
index 9db490b6f5c1..2432a10a6476 100644
--- a/packages/SettingsLib/res/values-de/strings.xml
+++ b/packages/SettingsLib/res/values-de/strings.xml
@@ -415,7 +415,6 @@
<string name="screen_zoom_summary_very_large" msgid="7108563375663670067">"Größer"</string>
<string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"Am größten"</string>
<string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Benutzerdefiniert (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
- <string name="help_feedback_label" msgid="6815040660801785649">"Hilfe &amp; Feedback"</string>
<string name="content_description_menu_button" msgid="8182594799812351266">"Menü"</string>
<string name="retail_demo_reset_message" msgid="118771671364131297">"Passwort eingeben, um Gerät im Demomodus auf Werkseinstellungen zurückzusetzen"</string>
<string name="retail_demo_reset_next" msgid="8356731459226304963">"Weiter"</string>
diff --git a/packages/SettingsLib/res/values-el/strings.xml b/packages/SettingsLib/res/values-el/strings.xml
index 2ba543e45955..6f2889c985ab 100644
--- a/packages/SettingsLib/res/values-el/strings.xml
+++ b/packages/SettingsLib/res/values-el/strings.xml
@@ -415,7 +415,6 @@
<string name="screen_zoom_summary_very_large" msgid="7108563375663670067">"Πιο μεγάλα"</string>
<string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"Μεγαλύτερα"</string>
<string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Προσαρμοσμένη (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
- <string name="help_feedback_label" msgid="6815040660801785649">"Βοήθεια και σχόλια"</string>
<string name="content_description_menu_button" msgid="8182594799812351266">"Μενού"</string>
<string name="retail_demo_reset_message" msgid="118771671364131297">"Εισαγάγετε κωδικό πρόσβασης για επαναφορά εργοστασιακών ρυθμίσεων στη λειτουργία επίδειξης"</string>
<string name="retail_demo_reset_next" msgid="8356731459226304963">"Επόμενο"</string>
diff --git a/packages/SettingsLib/res/values-en-rAU/strings.xml b/packages/SettingsLib/res/values-en-rAU/strings.xml
index 747fdc77cab8..154aa7d9076a 100644
--- a/packages/SettingsLib/res/values-en-rAU/strings.xml
+++ b/packages/SettingsLib/res/values-en-rAU/strings.xml
@@ -415,7 +415,6 @@
<string name="screen_zoom_summary_very_large" msgid="7108563375663670067">"Larger"</string>
<string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"Largest"</string>
<string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Custom (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
- <string name="help_feedback_label" msgid="6815040660801785649">"Help &amp; feedback"</string>
<string name="content_description_menu_button" msgid="8182594799812351266">"Menu"</string>
<string name="retail_demo_reset_message" msgid="118771671364131297">"Enter password to perform factory reset in demo mode"</string>
<string name="retail_demo_reset_next" msgid="8356731459226304963">"Next"</string>
diff --git a/packages/SettingsLib/res/values-en-rCA/strings.xml b/packages/SettingsLib/res/values-en-rCA/strings.xml
index 747fdc77cab8..154aa7d9076a 100644
--- a/packages/SettingsLib/res/values-en-rCA/strings.xml
+++ b/packages/SettingsLib/res/values-en-rCA/strings.xml
@@ -415,7 +415,6 @@
<string name="screen_zoom_summary_very_large" msgid="7108563375663670067">"Larger"</string>
<string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"Largest"</string>
<string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Custom (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
- <string name="help_feedback_label" msgid="6815040660801785649">"Help &amp; feedback"</string>
<string name="content_description_menu_button" msgid="8182594799812351266">"Menu"</string>
<string name="retail_demo_reset_message" msgid="118771671364131297">"Enter password to perform factory reset in demo mode"</string>
<string name="retail_demo_reset_next" msgid="8356731459226304963">"Next"</string>
diff --git a/packages/SettingsLib/res/values-en-rGB/strings.xml b/packages/SettingsLib/res/values-en-rGB/strings.xml
index 747fdc77cab8..154aa7d9076a 100644
--- a/packages/SettingsLib/res/values-en-rGB/strings.xml
+++ b/packages/SettingsLib/res/values-en-rGB/strings.xml
@@ -415,7 +415,6 @@
<string name="screen_zoom_summary_very_large" msgid="7108563375663670067">"Larger"</string>
<string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"Largest"</string>
<string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Custom (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
- <string name="help_feedback_label" msgid="6815040660801785649">"Help &amp; feedback"</string>
<string name="content_description_menu_button" msgid="8182594799812351266">"Menu"</string>
<string name="retail_demo_reset_message" msgid="118771671364131297">"Enter password to perform factory reset in demo mode"</string>
<string name="retail_demo_reset_next" msgid="8356731459226304963">"Next"</string>
diff --git a/packages/SettingsLib/res/values-en-rIN/strings.xml b/packages/SettingsLib/res/values-en-rIN/strings.xml
index 747fdc77cab8..154aa7d9076a 100644
--- a/packages/SettingsLib/res/values-en-rIN/strings.xml
+++ b/packages/SettingsLib/res/values-en-rIN/strings.xml
@@ -415,7 +415,6 @@
<string name="screen_zoom_summary_very_large" msgid="7108563375663670067">"Larger"</string>
<string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"Largest"</string>
<string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Custom (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
- <string name="help_feedback_label" msgid="6815040660801785649">"Help &amp; feedback"</string>
<string name="content_description_menu_button" msgid="8182594799812351266">"Menu"</string>
<string name="retail_demo_reset_message" msgid="118771671364131297">"Enter password to perform factory reset in demo mode"</string>
<string name="retail_demo_reset_next" msgid="8356731459226304963">"Next"</string>
diff --git a/packages/SettingsLib/res/values-en-rXC/strings.xml b/packages/SettingsLib/res/values-en-rXC/strings.xml
index 33b9f1db3d59..e9746c0b38df 100644
--- a/packages/SettingsLib/res/values-en-rXC/strings.xml
+++ b/packages/SettingsLib/res/values-en-rXC/strings.xml
@@ -415,7 +415,6 @@
<string name="screen_zoom_summary_very_large" msgid="7108563375663670067">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‏‏‏‎‎‎‏‎‏‎‏‎‎‏‏‎‏‎‏‏‎‎‎‎‏‎‏‏‏‎‏‎‎‎‏‏‎‏‎‏‏‏‎‎‏‎‎‎‏‏‏‎‎‎‏‏‎‎‏‏‎‎‏‏‎Larger‎‏‎‎‏‎"</string>
<string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‏‏‏‎‎‏‏‏‎‎‎‏‎‎‏‏‎‎‏‎‎‏‎‎‎‏‎‏‎‏‏‏‎‏‏‎‎‏‏‎‎‏‏‎‏‏‎‏‎‏‎‏‎‏‏‎‏‏‎‎‎‎‏‏‎Largest‎‏‎‎‏‎"</string>
<string name="screen_zoom_summary_custom" msgid="5611979864124160447">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‏‏‎‎‏‏‎‏‏‏‏‎‎‎‎‏‏‏‎‎‎‎‎‏‏‏‏‏‎‎‏‏‏‏‏‎‏‏‏‏‏‏‎‎‎‎‏‏‏‏‏‏‏‎‎‏‏‎‏‏‏‏‏‏‎Custom (‎‏‎‎‏‏‎<xliff:g id="DENSITYDPI">%d</xliff:g>‎‏‎‎‏‏‏‎)‎‏‎‎‏‎"</string>
- <string name="help_feedback_label" msgid="6815040660801785649">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‏‏‎‏‏‏‏‎‏‎‎‏‎‎‏‏‏‏‏‎‎‎‏‏‎‏‎‏‏‏‏‏‏‎‎‏‎‏‎‎‏‏‏‎‏‏‏‏‎‎‎‎‏‏‏‏‎‎‏‏‎‎‎‏‎Help &amp; feedback‎‏‎‎‏‎"</string>
<string name="content_description_menu_button" msgid="8182594799812351266">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‏‏‏‏‎‎‎‏‏‎‎‎‏‏‏‎‎‏‏‎‏‎‏‎‏‎‎‏‏‏‎‏‏‏‏‏‏‏‏‏‏‏‎‎‎‏‏‎‎‎‎‏‎‏‎‏‎‎‏‎‎‎‏‎‎Menu‎‏‎‎‏‎"</string>
<string name="retail_demo_reset_message" msgid="118771671364131297">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‎‎‏‏‏‎‏‎‎‏‎‏‏‏‏‏‎‏‏‎‎‎‏‏‎‏‎‎‏‎‏‏‎‎‎‏‎‎‎‎‏‎‎‏‏‏‎‏‏‎‎‏‏‏‏‎‎‎‎‏‎Enter password to perform factory reset in demo mode‎‏‎‎‏‎"</string>
<string name="retail_demo_reset_next" msgid="8356731459226304963">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‏‏‏‏‎‎‏‏‏‏‏‏‏‎‎‏‎‎‎‏‎‎‏‎‏‏‏‏‏‏‎‎‎‏‏‏‏‏‏‎‏‎‎‎‎‏‎‎‎‎‎‎‎‎‎‏‏‏‎‎‎‎‏‏‎Next‎‏‎‎‏‎"</string>
diff --git a/packages/SettingsLib/res/values-es-rUS/strings.xml b/packages/SettingsLib/res/values-es-rUS/strings.xml
index f665b77b836c..706e1d3f4299 100644
--- a/packages/SettingsLib/res/values-es-rUS/strings.xml
+++ b/packages/SettingsLib/res/values-es-rUS/strings.xml
@@ -415,7 +415,6 @@
<string name="screen_zoom_summary_very_large" msgid="7108563375663670067">"Más grande"</string>
<string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"Máximo"</string>
<string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Personalizado (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
- <string name="help_feedback_label" msgid="6815040660801785649">"Ayuda y comentarios"</string>
<string name="content_description_menu_button" msgid="8182594799812351266">"Menú"</string>
<string name="retail_demo_reset_message" msgid="118771671364131297">"Ingresa contraseña y restablece en demo"</string>
<string name="retail_demo_reset_next" msgid="8356731459226304963">"Siguiente"</string>
diff --git a/packages/SettingsLib/res/values-es/strings.xml b/packages/SettingsLib/res/values-es/strings.xml
index 9cdde92ee564..f9eddd9a43ff 100644
--- a/packages/SettingsLib/res/values-es/strings.xml
+++ b/packages/SettingsLib/res/values-es/strings.xml
@@ -242,7 +242,7 @@
<string name="select_logd_size_dialog_title" msgid="1206769310236476760">"Elige el tamaño del Logger por búfer"</string>
<string name="dev_logpersist_clear_warning_title" msgid="684806692440237967">"¿Borrar almacenamiento continuo del registrador?"</string>
<string name="dev_logpersist_clear_warning_message" msgid="2256582531342994562">"Cuando ya no supervisamos la actividad con el registrador de forma continua, estamos obligados a borrar los datos del registrador almacenados en el dispositivo."</string>
- <string name="select_logpersist_title" msgid="7530031344550073166">"Guardar datos de forma continua"</string>
+ <string name="select_logpersist_title" msgid="7530031344550073166">"Guardar datos de registro de forma continua"</string>
<string name="select_logpersist_dialog_title" msgid="4003400579973269060">"Seleccionar búferes de registro para guardarlos de forma continua en dispositivo"</string>
<string name="select_usb_configuration_title" msgid="2649938511506971843">"Seleccionar configuración de USB"</string>
<string name="select_usb_configuration_dialog_title" msgid="6385564442851599963">"Seleccionar configuración de USB"</string>
@@ -396,7 +396,7 @@
<string name="battery_info_status_full" msgid="2824614753861462808">"Completa"</string>
<string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"Controlada por el administrador"</string>
<string name="enabled_by_admin" msgid="5302986023578399263">"Habilitada por el administrador"</string>
- <string name="disabled_by_admin" msgid="8505398946020816620">"Inhabilitada por el administrador"</string>
+ <string name="disabled_by_admin" msgid="8505398946020816620">"Inhabilitado por el administrador"</string>
<string name="disabled" msgid="9206776641295849915">"Inhabilitada"</string>
<string name="external_source_trusted" msgid="2707996266575928037">"Autorizadas"</string>
<string name="external_source_untrusted" msgid="2677442511837596726">"No autorizadas"</string>
@@ -415,7 +415,6 @@
<string name="screen_zoom_summary_very_large" msgid="7108563375663670067">"Más grande"</string>
<string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"Lo más grande posible"</string>
<string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Personalizado (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
- <string name="help_feedback_label" msgid="6815040660801785649">"Ayuda y sugerencias"</string>
<string name="content_description_menu_button" msgid="8182594799812351266">"Menú"</string>
<string name="retail_demo_reset_message" msgid="118771671364131297">"Escribe una contraseña para restablecer estado de fábrica en modo demostración"</string>
<string name="retail_demo_reset_next" msgid="8356731459226304963">"Siguiente"</string>
diff --git a/packages/SettingsLib/res/values-et/strings.xml b/packages/SettingsLib/res/values-et/strings.xml
index 2b4432120ee5..ac318808351d 100644
--- a/packages/SettingsLib/res/values-et/strings.xml
+++ b/packages/SettingsLib/res/values-et/strings.xml
@@ -415,7 +415,6 @@
<string name="screen_zoom_summary_very_large" msgid="7108563375663670067">"Suurem"</string>
<string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"Suurim"</string>
<string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Kohandatud (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
- <string name="help_feedback_label" msgid="6815040660801785649">"Abi ja tagasiside"</string>
<string name="content_description_menu_button" msgid="8182594799812351266">"Menüü"</string>
<string name="retail_demo_reset_message" msgid="118771671364131297">"Sisestage parool, et demorežiimis tehaseseadetele lähtestada"</string>
<string name="retail_demo_reset_next" msgid="8356731459226304963">"Järgmine"</string>
diff --git a/packages/SettingsLib/res/values-eu/strings.xml b/packages/SettingsLib/res/values-eu/strings.xml
index 4ad60b320e65..2eee948f62d3 100644
--- a/packages/SettingsLib/res/values-eu/strings.xml
+++ b/packages/SettingsLib/res/values-eu/strings.xml
@@ -415,7 +415,6 @@
<string name="screen_zoom_summary_very_large" msgid="7108563375663670067">"Oso handia"</string>
<string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"Handiena"</string>
<string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Pertsonalizatua (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
- <string name="help_feedback_label" msgid="6815040660801785649">"Laguntza eta iritziak"</string>
<string name="content_description_menu_button" msgid="8182594799812351266">"Menua"</string>
<string name="retail_demo_reset_message" msgid="118771671364131297">"Idatzi pasahitza jatorrizko ezarpenak demo moduan berrezartzeko"</string>
<string name="retail_demo_reset_next" msgid="8356731459226304963">"Hurrengoa"</string>
diff --git a/packages/SettingsLib/res/values-fa/strings.xml b/packages/SettingsLib/res/values-fa/strings.xml
index 1d0882145c83..6efd4fe80600 100644
--- a/packages/SettingsLib/res/values-fa/strings.xml
+++ b/packages/SettingsLib/res/values-fa/strings.xml
@@ -415,7 +415,6 @@
<string name="screen_zoom_summary_very_large" msgid="7108563375663670067">"بزرگ‌تر"</string>
<string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"بزرگ‌ترین"</string>
<string name="screen_zoom_summary_custom" msgid="5611979864124160447">"سفارشی (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
- <string name="help_feedback_label" msgid="6815040660801785649">"راهنما و بازخورد"</string>
<string name="content_description_menu_button" msgid="8182594799812351266">"منو"</string>
<string name="retail_demo_reset_message" msgid="118771671364131297">"برای انجام بازنشانی کارخانه‌ای در حالت نمایشی، گذرواژه را وارد کنید"</string>
<string name="retail_demo_reset_next" msgid="8356731459226304963">"بعدی"</string>
diff --git a/packages/SettingsLib/res/values-fi/strings.xml b/packages/SettingsLib/res/values-fi/strings.xml
index 7c253fc2a886..4d64e81bfe3b 100644
--- a/packages/SettingsLib/res/values-fi/strings.xml
+++ b/packages/SettingsLib/res/values-fi/strings.xml
@@ -415,7 +415,6 @@
<string name="screen_zoom_summary_very_large" msgid="7108563375663670067">"Suurempi"</string>
<string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"Suurin"</string>
<string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Muokattu (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
- <string name="help_feedback_label" msgid="6815040660801785649">"Ohje ja palaute"</string>
<string name="content_description_menu_button" msgid="8182594799812351266">"Valikko"</string>
<string name="retail_demo_reset_message" msgid="118771671364131297">"Palauta tehdasasetukset antamalla salasana"</string>
<string name="retail_demo_reset_next" msgid="8356731459226304963">"Seuraava"</string>
diff --git a/packages/SettingsLib/res/values-fr-rCA/strings.xml b/packages/SettingsLib/res/values-fr-rCA/strings.xml
index 99906ca3c1ad..8e813ea40b2c 100644
--- a/packages/SettingsLib/res/values-fr-rCA/strings.xml
+++ b/packages/SettingsLib/res/values-fr-rCA/strings.xml
@@ -415,7 +415,6 @@
<string name="screen_zoom_summary_very_large" msgid="7108563375663670067">"Plus grande"</string>
<string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"La plus grande"</string>
<string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Personnalisée (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
- <string name="help_feedback_label" msgid="6815040660801785649">"Aide et commentaires"</string>
<string name="content_description_menu_button" msgid="8182594799812351266">"Menu"</string>
<string name="retail_demo_reset_message" msgid="118771671364131297">"Entrez m. passe pour réinit. en mode démo"</string>
<string name="retail_demo_reset_next" msgid="8356731459226304963">"Suivant"</string>
diff --git a/packages/SettingsLib/res/values-fr/strings.xml b/packages/SettingsLib/res/values-fr/strings.xml
index 7a51faa87236..baf8ed095f05 100644
--- a/packages/SettingsLib/res/values-fr/strings.xml
+++ b/packages/SettingsLib/res/values-fr/strings.xml
@@ -246,7 +246,7 @@
<string name="select_logpersist_dialog_title" msgid="4003400579973269060">"Sélectionner les mémoires tampon journal à stocker en permanence sur l\'appareil"</string>
<string name="select_usb_configuration_title" msgid="2649938511506971843">"Sélectionner une configuration USB"</string>
<string name="select_usb_configuration_dialog_title" msgid="6385564442851599963">"Sélectionner une configuration USB"</string>
- <string name="allow_mock_location" msgid="2787962564578664888">"Positions fictives"</string>
+ <string name="allow_mock_location" msgid="2787962564578664888">"Autoriser les positions fictives"</string>
<string name="allow_mock_location_summary" msgid="317615105156345626">"Autoriser les positions fictives"</string>
<string name="debug_view_attributes" msgid="6485448367803310384">"Activer inspect. attribut affich."</string>
<string name="mobile_data_always_on_summary" msgid="8149773901431697910">"Maintenir les données mobiles à l\'état actif, même lorsque le Wi‑Fi est actif (pour changer rapidement de réseau)"</string>
@@ -415,7 +415,6 @@
<string name="screen_zoom_summary_very_large" msgid="7108563375663670067">"Très grand"</string>
<string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"Extrêmement grand"</string>
<string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Personnalisé (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
- <string name="help_feedback_label" msgid="6815040660801785649">"Aide et commentaires"</string>
<string name="content_description_menu_button" msgid="8182594799812351266">"Menu"</string>
<string name="retail_demo_reset_message" msgid="118771671364131297">"Saisir mot de passe pour rétablir conf. d\'usine en mode démo."</string>
<string name="retail_demo_reset_next" msgid="8356731459226304963">"Suivant"</string>
diff --git a/packages/SettingsLib/res/values-gl/strings.xml b/packages/SettingsLib/res/values-gl/strings.xml
index 5bc61631abb1..dc22b25a2d26 100644
--- a/packages/SettingsLib/res/values-gl/strings.xml
+++ b/packages/SettingsLib/res/values-gl/strings.xml
@@ -415,7 +415,6 @@
<string name="screen_zoom_summary_very_large" msgid="7108563375663670067">"Máis grande"</string>
<string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"O máis grande"</string>
<string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Personalizado (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
- <string name="help_feedback_label" msgid="6815040660801785649">"Axuda e comentarios"</string>
<string name="content_description_menu_button" msgid="8182594799812351266">"Menú"</string>
<string name="retail_demo_reset_message" msgid="118771671364131297">"Insire contrasinal para restablec. en demostración"</string>
<string name="retail_demo_reset_next" msgid="8356731459226304963">"Seguinte"</string>
diff --git a/packages/SettingsLib/res/values-gu/strings.xml b/packages/SettingsLib/res/values-gu/strings.xml
index b523ae274380..7943d51cf83c 100644
--- a/packages/SettingsLib/res/values-gu/strings.xml
+++ b/packages/SettingsLib/res/values-gu/strings.xml
@@ -415,7 +415,6 @@
<string name="screen_zoom_summary_very_large" msgid="7108563375663670067">"વધુ મોટું"</string>
<string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"સૌથી મોટું"</string>
<string name="screen_zoom_summary_custom" msgid="5611979864124160447">"કસ્ટમ (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
- <string name="help_feedback_label" msgid="6815040660801785649">"સહાય અને પ્રતિસાદ"</string>
<string name="content_description_menu_button" msgid="8182594799812351266">"મેનુ"</string>
<string name="retail_demo_reset_message" msgid="118771671364131297">"ડેમો મોડમાં ફેક્ટરી રીસેટ પાસવર્ડ દાખલ કરો"</string>
<string name="retail_demo_reset_next" msgid="8356731459226304963">"આગલું"</string>
diff --git a/packages/SettingsLib/res/values-hi/strings.xml b/packages/SettingsLib/res/values-hi/strings.xml
index cd12f21cc1cc..3ec7e58e76fe 100644
--- a/packages/SettingsLib/res/values-hi/strings.xml
+++ b/packages/SettingsLib/res/values-hi/strings.xml
@@ -415,7 +415,6 @@
<string name="screen_zoom_summary_very_large" msgid="7108563375663670067">"अधिक बड़ा"</string>
<string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"सबसे बड़ा"</string>
<string name="screen_zoom_summary_custom" msgid="5611979864124160447">"कस्टम (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
- <string name="help_feedback_label" msgid="6815040660801785649">"सहायता और फ़ीडबैक"</string>
<string name="content_description_menu_button" msgid="8182594799812351266">"मेन्यू"</string>
<string name="retail_demo_reset_message" msgid="118771671364131297">"डेमो मोड में फ़ैक्टरी रीसेट के लिए पासवर्ड डालें"</string>
<string name="retail_demo_reset_next" msgid="8356731459226304963">"आगे"</string>
diff --git a/packages/SettingsLib/res/values-hr/strings.xml b/packages/SettingsLib/res/values-hr/strings.xml
index 9c83640b2fd4..ce8e6ec49da7 100644
--- a/packages/SettingsLib/res/values-hr/strings.xml
+++ b/packages/SettingsLib/res/values-hr/strings.xml
@@ -415,7 +415,6 @@
<string name="screen_zoom_summary_very_large" msgid="7108563375663670067">"Veće"</string>
<string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"Najveće"</string>
<string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Prilagođeno (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
- <string name="help_feedback_label" msgid="6815040660801785649">"Pomoć i povratne informacije"</string>
<string name="content_description_menu_button" msgid="8182594799812351266">"Izbornik"</string>
<string name="retail_demo_reset_message" msgid="118771671364131297">"Unesite zaporku za resetiranje u demo načinu"</string>
<string name="retail_demo_reset_next" msgid="8356731459226304963">"Dalje"</string>
diff --git a/packages/SettingsLib/res/values-hu/strings.xml b/packages/SettingsLib/res/values-hu/strings.xml
index 25d11aa97b5e..1c7919984c9d 100644
--- a/packages/SettingsLib/res/values-hu/strings.xml
+++ b/packages/SettingsLib/res/values-hu/strings.xml
@@ -415,7 +415,6 @@
<string name="screen_zoom_summary_very_large" msgid="7108563375663670067">"Nagyobb"</string>
<string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"Legnagyobb"</string>
<string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Egyéni (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
- <string name="help_feedback_label" msgid="6815040660801785649">"Súgó és visszajelzés"</string>
<string name="content_description_menu_button" msgid="8182594799812351266">"Menü"</string>
<string name="retail_demo_reset_message" msgid="118771671364131297">"Írja be a jelszót a visszaállításhoz"</string>
<string name="retail_demo_reset_next" msgid="8356731459226304963">"Következő"</string>
diff --git a/packages/SettingsLib/res/values-hy/strings.xml b/packages/SettingsLib/res/values-hy/strings.xml
index f811312c22f6..84ee03932ad8 100644
--- a/packages/SettingsLib/res/values-hy/strings.xml
+++ b/packages/SettingsLib/res/values-hy/strings.xml
@@ -415,7 +415,6 @@
<string name="screen_zoom_summary_very_large" msgid="7108563375663670067">"Ավելի մեծ"</string>
<string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"Ամենամեծ"</string>
<string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Հատուկ (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
- <string name="help_feedback_label" msgid="6815040660801785649">"Օգնություն և հետադարձ կապ"</string>
<string name="content_description_menu_button" msgid="8182594799812351266">"Ընտրացանկ"</string>
<string name="retail_demo_reset_message" msgid="118771671364131297">"Մուտքագրեք գաղտնաբառը՝ ցուցադրական ռեժիմում գործարանային վերակայում կատարելու համար"</string>
<string name="retail_demo_reset_next" msgid="8356731459226304963">"Հաջորդը"</string>
diff --git a/packages/SettingsLib/res/values-in/strings.xml b/packages/SettingsLib/res/values-in/strings.xml
index 39a88e5e5b71..9356c85614d4 100644
--- a/packages/SettingsLib/res/values-in/strings.xml
+++ b/packages/SettingsLib/res/values-in/strings.xml
@@ -281,7 +281,7 @@
<string name="strict_mode_summary" msgid="142834318897332338">"Kedipkan layar saat apl beroperasi lama pada utas utama"</string>
<string name="pointer_location" msgid="6084434787496938001">"Lokasi penunjuk"</string>
<string name="pointer_location_summary" msgid="840819275172753713">"Hamparan layar menampilkan data sentuhan saat ini"</string>
- <string name="show_touches" msgid="2642976305235070316">"Tampilkan ketukan"</string>
+ <string name="show_touches" msgid="2642976305235070316">"Tampilkan tap"</string>
<string name="show_touches_summary" msgid="6101183132903926324">"Tampilkan masukan visual untuk ketukan"</string>
<string name="show_screen_updates" msgid="5470814345876056420">"Lihat pembaruan permukaan"</string>
<string name="show_screen_updates_summary" msgid="2569622766672785529">"Sorot seluruh permukaan jendela saat diperbarui"</string>
@@ -415,7 +415,6 @@
<string name="screen_zoom_summary_very_large" msgid="7108563375663670067">"Lebih besar"</string>
<string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"Terbesar"</string>
<string name="screen_zoom_summary_custom" msgid="5611979864124160447">"(<xliff:g id="DENSITYDPI">%d</xliff:g>) khusus"</string>
- <string name="help_feedback_label" msgid="6815040660801785649">"Bantuan &amp; masukan"</string>
<string name="content_description_menu_button" msgid="8182594799812351266">"Menu"</string>
<string name="retail_demo_reset_message" msgid="118771671364131297">"Masukkan sandi untuk mengembalikan ke setelan pabrik dalam mode demo"</string>
<string name="retail_demo_reset_next" msgid="8356731459226304963">"Berikutnya"</string>
diff --git a/packages/SettingsLib/res/values-is/strings.xml b/packages/SettingsLib/res/values-is/strings.xml
index afb10a9b16ba..ca5e1f51b2f4 100644
--- a/packages/SettingsLib/res/values-is/strings.xml
+++ b/packages/SettingsLib/res/values-is/strings.xml
@@ -415,7 +415,6 @@
<string name="screen_zoom_summary_very_large" msgid="7108563375663670067">"Stærra"</string>
<string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"Stærst"</string>
<string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Sérsniðið (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
- <string name="help_feedback_label" msgid="6815040660801785649">"Hjálp og ábendingar"</string>
<string name="content_description_menu_button" msgid="8182594799812351266">"Valmynd"</string>
<string name="retail_demo_reset_message" msgid="118771671364131297">"Sláðu inn aðgangsorð til að framkvæma núllstillingu í sýnisútgáfu"</string>
<string name="retail_demo_reset_next" msgid="8356731459226304963">"Áfram"</string>
diff --git a/packages/SettingsLib/res/values-it/strings.xml b/packages/SettingsLib/res/values-it/strings.xml
index 24eef7af6b13..88a5bb8cf5c7 100644
--- a/packages/SettingsLib/res/values-it/strings.xml
+++ b/packages/SettingsLib/res/values-it/strings.xml
@@ -415,7 +415,6 @@
<string name="screen_zoom_summary_very_large" msgid="7108563375663670067">"Più grande"</string>
<string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"Massimo"</string>
<string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Personalizzato (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
- <string name="help_feedback_label" msgid="6815040660801785649">"Guida e feedback"</string>
<string name="content_description_menu_button" msgid="8182594799812351266">"Menu"</string>
<string name="retail_demo_reset_message" msgid="118771671364131297">"Inserisci la password per eseguire il ripristino dei dati di fabbrica in modalità demo"</string>
<string name="retail_demo_reset_next" msgid="8356731459226304963">"Avanti"</string>
diff --git a/packages/SettingsLib/res/values-iw/strings.xml b/packages/SettingsLib/res/values-iw/strings.xml
index e9c44c957f7f..cec35cf309c9 100644
--- a/packages/SettingsLib/res/values-iw/strings.xml
+++ b/packages/SettingsLib/res/values-iw/strings.xml
@@ -415,7 +415,6 @@
<string name="screen_zoom_summary_very_large" msgid="7108563375663670067">"יותר גדול"</string>
<string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"הכי גדול"</string>
<string name="screen_zoom_summary_custom" msgid="5611979864124160447">"מותאם אישית (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
- <string name="help_feedback_label" msgid="6815040660801785649">"עזרה ומשוב"</string>
<string name="content_description_menu_button" msgid="8182594799812351266">"תפריט"</string>
<string name="retail_demo_reset_message" msgid="118771671364131297">"הזן סיסמה כדי לבצע איפוס להגדרות היצרן במצב הדגמה"</string>
<string name="retail_demo_reset_next" msgid="8356731459226304963">"הבא"</string>
diff --git a/packages/SettingsLib/res/values-ja/strings.xml b/packages/SettingsLib/res/values-ja/strings.xml
index 0cc2d17d4c22..9cfdadcfaeb8 100644
--- a/packages/SettingsLib/res/values-ja/strings.xml
+++ b/packages/SettingsLib/res/values-ja/strings.xml
@@ -415,7 +415,6 @@
<string name="screen_zoom_summary_very_large" msgid="7108563375663670067">"特大"</string>
<string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"最大"</string>
<string name="screen_zoom_summary_custom" msgid="5611979864124160447">"カスタム(<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
- <string name="help_feedback_label" msgid="6815040660801785649">"ヘルプとフィードバック"</string>
<string name="content_description_menu_button" msgid="8182594799812351266">"メニュー"</string>
<string name="retail_demo_reset_message" msgid="118771671364131297">"デモモードで初期状態にリセットするには、パスワードを入力してください"</string>
<string name="retail_demo_reset_next" msgid="8356731459226304963">"次へ"</string>
diff --git a/packages/SettingsLib/res/values-ka/strings.xml b/packages/SettingsLib/res/values-ka/strings.xml
index daca5b9c8322..1083025d71da 100644
--- a/packages/SettingsLib/res/values-ka/strings.xml
+++ b/packages/SettingsLib/res/values-ka/strings.xml
@@ -415,7 +415,6 @@
<string name="screen_zoom_summary_very_large" msgid="7108563375663670067">"უფრო დიდი"</string>
<string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"უდიდესი"</string>
<string name="screen_zoom_summary_custom" msgid="5611979864124160447">"მორგებული (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
- <string name="help_feedback_label" msgid="6815040660801785649">"დახმარება და გამოხმაურება"</string>
<string name="content_description_menu_button" msgid="8182594799812351266">"მენიუ"</string>
<string name="retail_demo_reset_message" msgid="118771671364131297">"შეიყვანეთ პაროლი დემო-რეჟიმში ქარხნულ მდგომარეობაზე დასაბრუნებლად"</string>
<string name="retail_demo_reset_next" msgid="8356731459226304963">"შემდეგი"</string>
diff --git a/packages/SettingsLib/res/values-kk/strings.xml b/packages/SettingsLib/res/values-kk/strings.xml
index b95d6e9e19d1..a122d911d9ba 100644
--- a/packages/SettingsLib/res/values-kk/strings.xml
+++ b/packages/SettingsLib/res/values-kk/strings.xml
@@ -415,7 +415,6 @@
<string name="screen_zoom_summary_very_large" msgid="7108563375663670067">"Үлкенірек"</string>
<string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"Ең үлкен"</string>
<string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Арнаулы (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
- <string name="help_feedback_label" msgid="6815040660801785649">"Анықтама және пікір"</string>
<string name="content_description_menu_button" msgid="8182594799812351266">"Mәзір"</string>
<string name="retail_demo_reset_message" msgid="118771671364131297">"Демо режимде зауыттық мәндерге қайтару үшін құпия сөзді енгізу"</string>
<string name="retail_demo_reset_next" msgid="8356731459226304963">"Келесі"</string>
diff --git a/packages/SettingsLib/res/values-km/strings.xml b/packages/SettingsLib/res/values-km/strings.xml
index 5bf38c0e64ea..7ffd766b6648 100644
--- a/packages/SettingsLib/res/values-km/strings.xml
+++ b/packages/SettingsLib/res/values-km/strings.xml
@@ -415,7 +415,6 @@
<string name="screen_zoom_summary_very_large" msgid="7108563375663670067">"ធំជាង"</string>
<string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"ធំបំផុត"</string>
<string name="screen_zoom_summary_custom" msgid="5611979864124160447">"ផ្ទាល់ខ្លួន (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
- <string name="help_feedback_label" msgid="6815040660801785649">"ជំនួយ និងមតិស្ថាបនា"</string>
<string name="content_description_menu_button" msgid="8182594799812351266">"ម៉ឺនុយ"</string>
<string name="retail_demo_reset_message" msgid="118771671364131297">"បញ្ចូល​ពាក្យ​សម្ងាត់ ដើម្បី​កំណត់ឧបករណ៍​​ឡើង​វិញ​ដូចពេលចេញ​ពី​រោងចក្រ នៅក្នុង​មុខងារ​សាកល្បង"</string>
<string name="retail_demo_reset_next" msgid="8356731459226304963">"បន្ទាប់"</string>
diff --git a/packages/SettingsLib/res/values-kn/strings.xml b/packages/SettingsLib/res/values-kn/strings.xml
index 923547f821bc..e12cbd20699c 100644
--- a/packages/SettingsLib/res/values-kn/strings.xml
+++ b/packages/SettingsLib/res/values-kn/strings.xml
@@ -415,7 +415,6 @@
<string name="screen_zoom_summary_very_large" msgid="7108563375663670067">"ಸ್ವಲ್ಪ ದೊಡ್ಡ"</string>
<string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"ದೊಡ್ಡ"</string>
<string name="screen_zoom_summary_custom" msgid="5611979864124160447">"ಕಸ್ಟಮ್ (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
- <string name="help_feedback_label" msgid="6815040660801785649">"ಸಹಾಯ ಮತ್ತು ಪ್ರತಿಕ್ರಿಯೆ"</string>
<string name="content_description_menu_button" msgid="8182594799812351266">"ಮೆನು"</string>
<string name="retail_demo_reset_message" msgid="118771671364131297">"ಫ್ಯಾಕ್ಟರಿ ರಿಸೆಟ್‌ಗೆ ಪಾಸ್‌ವರ್ಡ್ ನಮೂದಿಸಿ"</string>
<string name="retail_demo_reset_next" msgid="8356731459226304963">"ಮುಂದೆ"</string>
diff --git a/packages/SettingsLib/res/values-ko/strings.xml b/packages/SettingsLib/res/values-ko/strings.xml
index 9bac29d97844..ab2892f125d6 100644
--- a/packages/SettingsLib/res/values-ko/strings.xml
+++ b/packages/SettingsLib/res/values-ko/strings.xml
@@ -415,7 +415,6 @@
<string name="screen_zoom_summary_very_large" msgid="7108563375663670067">"더 크게"</string>
<string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"가장 크게"</string>
<string name="screen_zoom_summary_custom" msgid="5611979864124160447">"맞춤(<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
- <string name="help_feedback_label" msgid="6815040660801785649">"고객센터"</string>
<string name="content_description_menu_button" msgid="8182594799812351266">"메뉴"</string>
<string name="retail_demo_reset_message" msgid="118771671364131297">"데모 모드에서 초기화하려면 비밀번호 입력"</string>
<string name="retail_demo_reset_next" msgid="8356731459226304963">"다음"</string>
diff --git a/packages/SettingsLib/res/values-ky/strings.xml b/packages/SettingsLib/res/values-ky/strings.xml
index 523fabea585d..56b5da1feceb 100644
--- a/packages/SettingsLib/res/values-ky/strings.xml
+++ b/packages/SettingsLib/res/values-ky/strings.xml
@@ -415,7 +415,6 @@
<string name="screen_zoom_summary_very_large" msgid="7108563375663670067">"Чоңураак"</string>
<string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"Эң чоң"</string>
<string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Ыңгайлаштырылган (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
- <string name="help_feedback_label" msgid="6815040660801785649">"Жардам жана пикир билдирүү"</string>
<string name="content_description_menu_button" msgid="8182594799812351266">"Меню"</string>
<string name="retail_demo_reset_message" msgid="118771671364131297">"Демо режиминде демейки жөндөөлөргө кайтаруу үчүн сырсөздү киргизиңиз"</string>
<string name="retail_demo_reset_next" msgid="8356731459226304963">"Кийинки"</string>
diff --git a/packages/SettingsLib/res/values-lo/strings.xml b/packages/SettingsLib/res/values-lo/strings.xml
index f85a69150a58..eb27f02b069a 100644
--- a/packages/SettingsLib/res/values-lo/strings.xml
+++ b/packages/SettingsLib/res/values-lo/strings.xml
@@ -415,7 +415,6 @@
<string name="screen_zoom_summary_very_large" msgid="7108563375663670067">"ໃຫຍ່ກວ່າ"</string>
<string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"ໃຫຍ່ທີ່ສຸດ"</string>
<string name="screen_zoom_summary_custom" msgid="5611979864124160447">"ປັບແຕ່ງເອງ (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
- <string name="help_feedback_label" msgid="6815040660801785649">"ຊ່ວຍເຫຼືອ &amp; ຄຳຕິຊົມ"</string>
<string name="content_description_menu_button" msgid="8182594799812351266">"ເມນູ"</string>
<string name="retail_demo_reset_message" msgid="118771671364131297">"Enter password to perform factory reset in demo mode"</string>
<string name="retail_demo_reset_next" msgid="8356731459226304963">"ຕໍ່ໄປ"</string>
diff --git a/packages/SettingsLib/res/values-lt/strings.xml b/packages/SettingsLib/res/values-lt/strings.xml
index fc2924f66812..44b532b8045c 100644
--- a/packages/SettingsLib/res/values-lt/strings.xml
+++ b/packages/SettingsLib/res/values-lt/strings.xml
@@ -415,7 +415,6 @@
<string name="screen_zoom_summary_very_large" msgid="7108563375663670067">"Didesnis"</string>
<string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"Didžiausias"</string>
<string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Tinkintas (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
- <string name="help_feedback_label" msgid="6815040660801785649">"Pagalba ir atsiliepimai"</string>
<string name="content_description_menu_button" msgid="8182594799812351266">"Meniu"</string>
<string name="retail_demo_reset_message" msgid="118771671364131297">"Įv. slapt. ir atk. gam. nust. dem. rež."</string>
<string name="retail_demo_reset_next" msgid="8356731459226304963">"Kitas"</string>
diff --git a/packages/SettingsLib/res/values-lv/strings.xml b/packages/SettingsLib/res/values-lv/strings.xml
index 6ce5e8e86310..ba87d074cd31 100644
--- a/packages/SettingsLib/res/values-lv/strings.xml
+++ b/packages/SettingsLib/res/values-lv/strings.xml
@@ -415,7 +415,6 @@
<string name="screen_zoom_summary_very_large" msgid="7108563375663670067">"Lielāks"</string>
<string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"Vislielākais"</string>
<string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Pielāgots (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
- <string name="help_feedback_label" msgid="6815040660801785649">"Palīdzība un atsauksmes"</string>
<string name="content_description_menu_button" msgid="8182594799812351266">"Izvēlne"</string>
<string name="retail_demo_reset_message" msgid="118771671364131297">"Iev. paroli, lai atiest. rūpnīcas iest. dem. režīmā"</string>
<string name="retail_demo_reset_next" msgid="8356731459226304963">"Tālāk"</string>
diff --git a/packages/SettingsLib/res/values-mk/strings.xml b/packages/SettingsLib/res/values-mk/strings.xml
index c6c508e2c12c..0c5c94acef05 100644
--- a/packages/SettingsLib/res/values-mk/strings.xml
+++ b/packages/SettingsLib/res/values-mk/strings.xml
@@ -415,7 +415,6 @@
<string name="screen_zoom_summary_very_large" msgid="7108563375663670067">"Поголем"</string>
<string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"Најголем"</string>
<string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Приспособен (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
- <string name="help_feedback_label" msgid="6815040660801785649">"Помош и повратни информации"</string>
<string name="content_description_menu_button" msgid="8182594799812351266">"Мени"</string>
<string name="retail_demo_reset_message" msgid="118771671364131297">"Внесете лозинка за фаб. ресет. во демо"</string>
<string name="retail_demo_reset_next" msgid="8356731459226304963">"Следно"</string>
diff --git a/packages/SettingsLib/res/values-ml/strings.xml b/packages/SettingsLib/res/values-ml/strings.xml
index 6b6462c083b3..1a208e6260c1 100644
--- a/packages/SettingsLib/res/values-ml/strings.xml
+++ b/packages/SettingsLib/res/values-ml/strings.xml
@@ -415,7 +415,6 @@
<string name="screen_zoom_summary_very_large" msgid="7108563375663670067">"കൂടുതൽ വലുത്"</string>
<string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"ഏറ്റവും വലുത്"</string>
<string name="screen_zoom_summary_custom" msgid="5611979864124160447">"ഇഷ്ടാനുസൃതം ( <xliff:g id="DENSITYDPI">%d</xliff:g> )"</string>
- <string name="help_feedback_label" msgid="6815040660801785649">"സഹായവും പ്രതികരണവും"</string>
<string name="content_description_menu_button" msgid="8182594799812351266">"മെനു"</string>
<string name="retail_demo_reset_message" msgid="118771671364131297">"ഡെമോ ‌മോഡിൽ ഫാക്ടറി റീസെറ്റിന് പാസ്‌വേഡ് നൽകുക"</string>
<string name="retail_demo_reset_next" msgid="8356731459226304963">"അടുത്തത്"</string>
diff --git a/packages/SettingsLib/res/values-mn/strings.xml b/packages/SettingsLib/res/values-mn/strings.xml
index 56f1cc0bc569..809e82ef122c 100644
--- a/packages/SettingsLib/res/values-mn/strings.xml
+++ b/packages/SettingsLib/res/values-mn/strings.xml
@@ -415,7 +415,6 @@
<string name="screen_zoom_summary_very_large" msgid="7108563375663670067">"Илүү том"</string>
<string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"Хамгийн том"</string>
<string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Тогтмол утга (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
- <string name="help_feedback_label" msgid="6815040660801785649">"Тусламж, санал хүсэлт"</string>
<string name="content_description_menu_button" msgid="8182594799812351266">"Цэс"</string>
<string name="retail_demo_reset_message" msgid="118771671364131297">"Үйлдвэрийн тохиргоог демо горимд ажиллуулахын тулд нууц үг оруулна уу"</string>
<string name="retail_demo_reset_next" msgid="8356731459226304963">"Дараагийн"</string>
diff --git a/packages/SettingsLib/res/values-mr/strings.xml b/packages/SettingsLib/res/values-mr/strings.xml
index 7485886673bf..dfa6d2fe8964 100644
--- a/packages/SettingsLib/res/values-mr/strings.xml
+++ b/packages/SettingsLib/res/values-mr/strings.xml
@@ -415,7 +415,6 @@
<string name="screen_zoom_summary_very_large" msgid="7108563375663670067">"आणखी मोठा"</string>
<string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"सर्वात मोठा"</string>
<string name="screen_zoom_summary_custom" msgid="5611979864124160447">"कस्टम करा (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
- <string name="help_feedback_label" msgid="6815040660801785649">"मदत आणि अभिप्राय"</string>
<string name="content_description_menu_button" msgid="8182594799812351266">"मेनू"</string>
<string name="retail_demo_reset_message" msgid="118771671364131297">"डेमो मोडमध्ये फॅक्टरी रीसेट करण्यासाठी पासवर्ड एंटर करा"</string>
<string name="retail_demo_reset_next" msgid="8356731459226304963">"पुढील"</string>
diff --git a/packages/SettingsLib/res/values-ms/strings.xml b/packages/SettingsLib/res/values-ms/strings.xml
index fdb8702a91e5..b4ed016460e3 100644
--- a/packages/SettingsLib/res/values-ms/strings.xml
+++ b/packages/SettingsLib/res/values-ms/strings.xml
@@ -415,7 +415,6 @@
<string name="screen_zoom_summary_very_large" msgid="7108563375663670067">"Lebih besar"</string>
<string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"Terbesar"</string>
<string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Tersuai (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
- <string name="help_feedback_label" msgid="6815040660801785649">"Bantuan &amp; maklum balas"</string>
<string name="content_description_menu_button" msgid="8182594799812351266">"Menu"</string>
<string name="retail_demo_reset_message" msgid="118771671364131297">"Mskkn kta laluan utk ttpn sml kilang dlm mod demo"</string>
<string name="retail_demo_reset_next" msgid="8356731459226304963">"Seterusnya"</string>
diff --git a/packages/SettingsLib/res/values-my/strings.xml b/packages/SettingsLib/res/values-my/strings.xml
index dc5d924a13c4..c1ffd28248ba 100644
--- a/packages/SettingsLib/res/values-my/strings.xml
+++ b/packages/SettingsLib/res/values-my/strings.xml
@@ -415,7 +415,6 @@
<string name="screen_zoom_summary_very_large" msgid="7108563375663670067">"ပိုကြီး"</string>
<string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"အကြီးဆုံး"</string>
<string name="screen_zoom_summary_custom" msgid="5611979864124160447">"စိတ်ကြိုက် (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
- <string name="help_feedback_label" msgid="6815040660801785649">"အကူအညီနှင့် အကြံပြုချက်"</string>
<string name="content_description_menu_button" msgid="8182594799812351266">"မီနူး"</string>
<string name="retail_demo_reset_message" msgid="118771671364131297">"ဒီမိုမုဒ်၌မူလဆက်တင်ထားရန် စကားဝှက်ထည့်ပါ"</string>
<string name="retail_demo_reset_next" msgid="8356731459226304963">"ရှေ့သို့"</string>
diff --git a/packages/SettingsLib/res/values-nb/strings.xml b/packages/SettingsLib/res/values-nb/strings.xml
index 460eb5781cb1..5a8e01e32119 100644
--- a/packages/SettingsLib/res/values-nb/strings.xml
+++ b/packages/SettingsLib/res/values-nb/strings.xml
@@ -415,7 +415,6 @@
<string name="screen_zoom_summary_very_large" msgid="7108563375663670067">"Større"</string>
<string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"Størst"</string>
<string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Egendefinert (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
- <string name="help_feedback_label" msgid="6815040660801785649">"Hjelp og tilbakemelding"</string>
<string name="content_description_menu_button" msgid="8182594799812351266">"Meny"</string>
<string name="retail_demo_reset_message" msgid="118771671364131297">"Skriv inn passordet for å tilbakestille til fabrikkstandard i demomodus"</string>
<string name="retail_demo_reset_next" msgid="8356731459226304963">"Neste"</string>
diff --git a/packages/SettingsLib/res/values-ne/strings.xml b/packages/SettingsLib/res/values-ne/strings.xml
index 763b60c539a9..72a9abb784af 100644
--- a/packages/SettingsLib/res/values-ne/strings.xml
+++ b/packages/SettingsLib/res/values-ne/strings.xml
@@ -415,7 +415,6 @@
<string name="screen_zoom_summary_very_large" msgid="7108563375663670067">"अझ ठूलो"</string>
<string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"सबैभन्दा ठूलो"</string>
<string name="screen_zoom_summary_custom" msgid="5611979864124160447">"आफू अनुकूल (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
- <string name="help_feedback_label" msgid="6815040660801785649">"मद्दत र प्रतिक्रिया"</string>
<string name="content_description_menu_button" msgid="8182594799812351266">"मेनु"</string>
<string name="retail_demo_reset_message" msgid="118771671364131297">"डेमो मोडमा फ्याक्ट्री रिसेट गर्न पासवर्ड प्रविष्ट गर्नुहोस्"</string>
<string name="retail_demo_reset_next" msgid="8356731459226304963">"अर्को"</string>
diff --git a/packages/SettingsLib/res/values-nl/strings.xml b/packages/SettingsLib/res/values-nl/strings.xml
index 264427ef6d7a..f34171742ec8 100644
--- a/packages/SettingsLib/res/values-nl/strings.xml
+++ b/packages/SettingsLib/res/values-nl/strings.xml
@@ -415,7 +415,6 @@
<string name="screen_zoom_summary_very_large" msgid="7108563375663670067">"Groter"</string>
<string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"Grootst"</string>
<string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Aangepast (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
- <string name="help_feedback_label" msgid="6815040660801785649">"Help en feedback"</string>
<string name="content_description_menu_button" msgid="8182594799812351266">"Menu"</string>
<string name="retail_demo_reset_message" msgid="118771671364131297">"Geef wachtwoord op om terug te zetten op fabrieksinstellingen in demomodus"</string>
<string name="retail_demo_reset_next" msgid="8356731459226304963">"Volgende"</string>
diff --git a/packages/SettingsLib/res/values-or/strings.xml b/packages/SettingsLib/res/values-or/strings.xml
index ecdc49e7d418..a7761e9ce75e 100644
--- a/packages/SettingsLib/res/values-or/strings.xml
+++ b/packages/SettingsLib/res/values-or/strings.xml
@@ -415,7 +415,6 @@
<string name="screen_zoom_summary_very_large" msgid="7108563375663670067">"ବୃହତ୍ତମ"</string>
<string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"ବୃହତ୍ତମ"</string>
<string name="screen_zoom_summary_custom" msgid="5611979864124160447">"କଷ୍ଟମ୍‌ (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
- <string name="help_feedback_label" msgid="6815040660801785649">"ସହାୟତା ଓ ମତାମତ"</string>
<string name="content_description_menu_button" msgid="8182594799812351266">"ମେନୁ"</string>
<string name="retail_demo_reset_message" msgid="118771671364131297">"ଡେମୋ ମୋଡ୍‌ରେ ଫ୍ୟାକ୍ଟୋରୀ ରିସେଟ୍‌ କରିବାକୁ ପାସ୍‌ୱାର୍ଡ ଲେଖନ୍ତୁ"</string>
<string name="retail_demo_reset_next" msgid="8356731459226304963">"ପରବର୍ତ୍ତୀ"</string>
diff --git a/packages/SettingsLib/res/values-pa/strings.xml b/packages/SettingsLib/res/values-pa/strings.xml
index 63c88cd23147..c7ab3793db16 100644
--- a/packages/SettingsLib/res/values-pa/strings.xml
+++ b/packages/SettingsLib/res/values-pa/strings.xml
@@ -415,7 +415,6 @@
<string name="screen_zoom_summary_very_large" msgid="7108563375663670067">"ਥੋੜ੍ਹਾ ਵੱਡੀ"</string>
<string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"ਸਭ ਤੋਂ ਵੱਡੀ"</string>
<string name="screen_zoom_summary_custom" msgid="5611979864124160447">"ਵਿਉਂਂਤੀ (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
- <string name="help_feedback_label" msgid="6815040660801785649">"ਮਦਦ &amp; ਫੀਡਬੈਕ"</string>
<string name="content_description_menu_button" msgid="8182594799812351266">"ਮੀਨੂ"</string>
<string name="retail_demo_reset_message" msgid="118771671364131297">"ਡੈਮੋ ਮੋਡ \'ਚ ਫੈਕਟਰੀ ਰੀਸੈੱਟ ਲਈ ਪਾਸਵਰਡ ਦਿਓ"</string>
<string name="retail_demo_reset_next" msgid="8356731459226304963">"ਅੱਗੇ"</string>
diff --git a/packages/SettingsLib/res/values-pl/strings.xml b/packages/SettingsLib/res/values-pl/strings.xml
index 7c3da214e7bb..effa59afaa8f 100644
--- a/packages/SettingsLib/res/values-pl/strings.xml
+++ b/packages/SettingsLib/res/values-pl/strings.xml
@@ -415,7 +415,6 @@
<string name="screen_zoom_summary_very_large" msgid="7108563375663670067">"Większy"</string>
<string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"Największy"</string>
<string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Niestandardowe (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
- <string name="help_feedback_label" msgid="6815040660801785649">"Pomoc i opinie"</string>
<string name="content_description_menu_button" msgid="8182594799812351266">"Menu"</string>
<string name="retail_demo_reset_message" msgid="118771671364131297">"Wpisz hasło, by przywrócić ustawienia fabryczne w trybie demonstracyjnym"</string>
<string name="retail_demo_reset_next" msgid="8356731459226304963">"Dalej"</string>
diff --git a/packages/SettingsLib/res/values-pt-rBR/strings.xml b/packages/SettingsLib/res/values-pt-rBR/strings.xml
index 192e532489bb..afefeda2ee53 100644
--- a/packages/SettingsLib/res/values-pt-rBR/strings.xml
+++ b/packages/SettingsLib/res/values-pt-rBR/strings.xml
@@ -77,7 +77,7 @@
<string name="bluetooth_profile_pbap_summary" msgid="6605229608108852198">"Usar para compartilhamento de contatos"</string>
<string name="bluetooth_profile_pan_nap" msgid="8429049285027482959">"Compartilhamento de conexão à Internet"</string>
<string name="bluetooth_profile_map" msgid="1019763341565580450">"Mensagens de texto"</string>
- <string name="bluetooth_profile_sap" msgid="5764222021851283125">"Acesso SIM"</string>
+ <string name="bluetooth_profile_sap" msgid="5764222021851283125">"Acesso ao chip"</string>
<string name="bluetooth_profile_a2dp_high_quality" msgid="5444517801472820055">"Áudio HD: <xliff:g id="CODEC_NAME">%1$s</xliff:g>"</string>
<string name="bluetooth_profile_a2dp_high_quality_unknown_codec" msgid="8510588052415438887">"Áudio HD"</string>
<string name="bluetooth_profile_hearing_aid" msgid="7999237886427812595">"Aparelho auditivo"</string>
@@ -93,7 +93,7 @@
<string name="bluetooth_pan_nap_profile_summary_connected" msgid="1322694224800769308">"Compartilhamento de conexão local de Internet c/ disposit."</string>
<string name="bluetooth_pan_profile_summary_use_for" msgid="5736111170225304239">"Usar para acesso à Internet"</string>
<string name="bluetooth_map_profile_summary_use_for" msgid="5154200119919927434">"Usar para mapa"</string>
- <string name="bluetooth_sap_profile_summary_use_for" msgid="7085362712786907993">"Use para acesso SIM"</string>
+ <string name="bluetooth_sap_profile_summary_use_for" msgid="7085362712786907993">"Use para acesso ao chip"</string>
<string name="bluetooth_a2dp_profile_summary_use_for" msgid="4630849022250168427">"Usar para áudio de mídia"</string>
<string name="bluetooth_headset_profile_summary_use_for" msgid="8705753622443862627">"Usar para áudio do smartphone"</string>
<string name="bluetooth_opp_profile_summary_use_for" msgid="1255674547144769756">"Usado para transferência de arquivo"</string>
@@ -415,7 +415,6 @@
<string name="screen_zoom_summary_very_large" msgid="7108563375663670067">"Muito grande"</string>
<string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"Maior"</string>
<string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Personalizada (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
- <string name="help_feedback_label" msgid="6815040660801785649">"Ajuda e feedback"</string>
<string name="content_description_menu_button" msgid="8182594799812351266">"Menu"</string>
<string name="retail_demo_reset_message" msgid="118771671364131297">"Digite a senha para redef. p/ configuração original em modo demo"</string>
<string name="retail_demo_reset_next" msgid="8356731459226304963">"Próxima"</string>
diff --git a/packages/SettingsLib/res/values-pt-rPT/strings.xml b/packages/SettingsLib/res/values-pt-rPT/strings.xml
index 01bc0fcf8443..4ee4521d7948 100644
--- a/packages/SettingsLib/res/values-pt-rPT/strings.xml
+++ b/packages/SettingsLib/res/values-pt-rPT/strings.xml
@@ -415,7 +415,6 @@
<string name="screen_zoom_summary_very_large" msgid="7108563375663670067">"Maior"</string>
<string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"O maior"</string>
<string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Personalizado (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
- <string name="help_feedback_label" msgid="6815040660801785649">"Ajuda e comentários"</string>
<string name="content_description_menu_button" msgid="8182594799812351266">"Menu"</string>
<string name="retail_demo_reset_message" msgid="118771671364131297">"Introduzir palavra-passe para efetuar a reposição de fábrica no modo demo"</string>
<string name="retail_demo_reset_next" msgid="8356731459226304963">"Próximo"</string>
diff --git a/packages/SettingsLib/res/values-pt/strings.xml b/packages/SettingsLib/res/values-pt/strings.xml
index 192e532489bb..afefeda2ee53 100644
--- a/packages/SettingsLib/res/values-pt/strings.xml
+++ b/packages/SettingsLib/res/values-pt/strings.xml
@@ -77,7 +77,7 @@
<string name="bluetooth_profile_pbap_summary" msgid="6605229608108852198">"Usar para compartilhamento de contatos"</string>
<string name="bluetooth_profile_pan_nap" msgid="8429049285027482959">"Compartilhamento de conexão à Internet"</string>
<string name="bluetooth_profile_map" msgid="1019763341565580450">"Mensagens de texto"</string>
- <string name="bluetooth_profile_sap" msgid="5764222021851283125">"Acesso SIM"</string>
+ <string name="bluetooth_profile_sap" msgid="5764222021851283125">"Acesso ao chip"</string>
<string name="bluetooth_profile_a2dp_high_quality" msgid="5444517801472820055">"Áudio HD: <xliff:g id="CODEC_NAME">%1$s</xliff:g>"</string>
<string name="bluetooth_profile_a2dp_high_quality_unknown_codec" msgid="8510588052415438887">"Áudio HD"</string>
<string name="bluetooth_profile_hearing_aid" msgid="7999237886427812595">"Aparelho auditivo"</string>
@@ -93,7 +93,7 @@
<string name="bluetooth_pan_nap_profile_summary_connected" msgid="1322694224800769308">"Compartilhamento de conexão local de Internet c/ disposit."</string>
<string name="bluetooth_pan_profile_summary_use_for" msgid="5736111170225304239">"Usar para acesso à Internet"</string>
<string name="bluetooth_map_profile_summary_use_for" msgid="5154200119919927434">"Usar para mapa"</string>
- <string name="bluetooth_sap_profile_summary_use_for" msgid="7085362712786907993">"Use para acesso SIM"</string>
+ <string name="bluetooth_sap_profile_summary_use_for" msgid="7085362712786907993">"Use para acesso ao chip"</string>
<string name="bluetooth_a2dp_profile_summary_use_for" msgid="4630849022250168427">"Usar para áudio de mídia"</string>
<string name="bluetooth_headset_profile_summary_use_for" msgid="8705753622443862627">"Usar para áudio do smartphone"</string>
<string name="bluetooth_opp_profile_summary_use_for" msgid="1255674547144769756">"Usado para transferência de arquivo"</string>
@@ -415,7 +415,6 @@
<string name="screen_zoom_summary_very_large" msgid="7108563375663670067">"Muito grande"</string>
<string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"Maior"</string>
<string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Personalizada (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
- <string name="help_feedback_label" msgid="6815040660801785649">"Ajuda e feedback"</string>
<string name="content_description_menu_button" msgid="8182594799812351266">"Menu"</string>
<string name="retail_demo_reset_message" msgid="118771671364131297">"Digite a senha para redef. p/ configuração original em modo demo"</string>
<string name="retail_demo_reset_next" msgid="8356731459226304963">"Próxima"</string>
diff --git a/packages/SettingsLib/res/values-ro/strings.xml b/packages/SettingsLib/res/values-ro/strings.xml
index cc74bd3d7ea6..f42363e46ca5 100644
--- a/packages/SettingsLib/res/values-ro/strings.xml
+++ b/packages/SettingsLib/res/values-ro/strings.xml
@@ -415,7 +415,6 @@
<string name="screen_zoom_summary_very_large" msgid="7108563375663670067">"Mai mare"</string>
<string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"Cel mai mare"</string>
<string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Personalizat (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
- <string name="help_feedback_label" msgid="6815040660801785649">"Ajutor și feedback"</string>
<string name="content_description_menu_button" msgid="8182594799812351266">"Meniu"</string>
<string name="retail_demo_reset_message" msgid="118771671364131297">"Introduceți parola pentru a reveni la setările din fabrică în modul demo"</string>
<string name="retail_demo_reset_next" msgid="8356731459226304963">"Înainte"</string>
diff --git a/packages/SettingsLib/res/values-ru/strings.xml b/packages/SettingsLib/res/values-ru/strings.xml
index 5e1869ff5a01..451c7102f2ca 100644
--- a/packages/SettingsLib/res/values-ru/strings.xml
+++ b/packages/SettingsLib/res/values-ru/strings.xml
@@ -415,7 +415,6 @@
<string name="screen_zoom_summary_very_large" msgid="7108563375663670067">"Очень крупный"</string>
<string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"Максимальный"</string>
<string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Другой (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
- <string name="help_feedback_label" msgid="6815040660801785649">"Справка/отзыв"</string>
<string name="content_description_menu_button" msgid="8182594799812351266">"Меню"</string>
<string name="retail_demo_reset_message" msgid="118771671364131297">"Чтобы сбросить настройки в деморежиме, введите пароль."</string>
<string name="retail_demo_reset_next" msgid="8356731459226304963">"Далее"</string>
diff --git a/packages/SettingsLib/res/values-si/strings.xml b/packages/SettingsLib/res/values-si/strings.xml
index 1be890b0da3e..d9e69ce8d338 100644
--- a/packages/SettingsLib/res/values-si/strings.xml
+++ b/packages/SettingsLib/res/values-si/strings.xml
@@ -415,7 +415,6 @@
<string name="screen_zoom_summary_very_large" msgid="7108563375663670067">"වඩා විශාල"</string>
<string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"විශාලතම"</string>
<string name="screen_zoom_summary_custom" msgid="5611979864124160447">"අභිරුචි (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
- <string name="help_feedback_label" msgid="6815040660801785649">"උදව් සහ ප්‍රතිපෝෂණ"</string>
<string name="content_description_menu_button" msgid="8182594799812351266">"මෙනුව"</string>
<string name="retail_demo_reset_message" msgid="118771671364131297">"ආදර්ශන ප්‍රකාර කර්මාන්තශාලා යළි සැකසීමට මුරපදය ඇ. ක."</string>
<string name="retail_demo_reset_next" msgid="8356731459226304963">"ඊළඟ"</string>
diff --git a/packages/SettingsLib/res/values-sk/strings.xml b/packages/SettingsLib/res/values-sk/strings.xml
index d1ec450118b2..a0c1062114b0 100644
--- a/packages/SettingsLib/res/values-sk/strings.xml
+++ b/packages/SettingsLib/res/values-sk/strings.xml
@@ -415,7 +415,6 @@
<string name="screen_zoom_summary_very_large" msgid="7108563375663670067">"Väčšie"</string>
<string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"Najväčšie"</string>
<string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Vlastné (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
- <string name="help_feedback_label" msgid="6815040660801785649">"Pomocník a spätná väzba"</string>
<string name="content_description_menu_button" msgid="8182594799812351266">"Ponuka"</string>
<string name="retail_demo_reset_message" msgid="118771671364131297">"Zadajte heslo na obnovenie továrenských nastavení v režime ukážky"</string>
<string name="retail_demo_reset_next" msgid="8356731459226304963">"Ďalej"</string>
diff --git a/packages/SettingsLib/res/values-sl/strings.xml b/packages/SettingsLib/res/values-sl/strings.xml
index 46325509f8db..3088d0fa4bb8 100644
--- a/packages/SettingsLib/res/values-sl/strings.xml
+++ b/packages/SettingsLib/res/values-sl/strings.xml
@@ -415,7 +415,6 @@
<string name="screen_zoom_summary_very_large" msgid="7108563375663670067">"Večje"</string>
<string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"Največje"</string>
<string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Po meri (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
- <string name="help_feedback_label" msgid="6815040660801785649">"Pomoč in povratne informacije"</string>
<string name="content_description_menu_button" msgid="8182594799812351266">"Meni"</string>
<string name="retail_demo_reset_message" msgid="118771671364131297">"Geslo za tovar. nast. v predstav. načinu"</string>
<string name="retail_demo_reset_next" msgid="8356731459226304963">"Naprej"</string>
diff --git a/packages/SettingsLib/res/values-sq/strings.xml b/packages/SettingsLib/res/values-sq/strings.xml
index 24cdcb1e54ab..8e31013af9d4 100644
--- a/packages/SettingsLib/res/values-sq/strings.xml
+++ b/packages/SettingsLib/res/values-sq/strings.xml
@@ -415,7 +415,6 @@
<string name="screen_zoom_summary_very_large" msgid="7108563375663670067">"Më i madh"</string>
<string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"Më i madhi"</string>
<string name="screen_zoom_summary_custom" msgid="5611979864124160447">"I personalizuar (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
- <string name="help_feedback_label" msgid="6815040660801785649">"Ndihma dhe komentet"</string>
<string name="content_description_menu_button" msgid="8182594799812351266">"Menyja"</string>
<string name="retail_demo_reset_message" msgid="118771671364131297">"Fut fjalëkalimin për të kryer rivendosje në gjendje fabrike në modalitetin e demonstrimit"</string>
<string name="retail_demo_reset_next" msgid="8356731459226304963">"Përpara"</string>
diff --git a/packages/SettingsLib/res/values-sr/strings.xml b/packages/SettingsLib/res/values-sr/strings.xml
index ebefc65483bf..fe9711937365 100644
--- a/packages/SettingsLib/res/values-sr/strings.xml
+++ b/packages/SettingsLib/res/values-sr/strings.xml
@@ -415,7 +415,6 @@
<string name="screen_zoom_summary_very_large" msgid="7108563375663670067">"Већи"</string>
<string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"Највећи"</string>
<string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Прилагођени (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
- <string name="help_feedback_label" msgid="6815040660801785649">"Помоћ и повратне информације"</string>
<string name="content_description_menu_button" msgid="8182594799812351266">"Мени"</string>
<string name="retail_demo_reset_message" msgid="118771671364131297">"Унесите лозинку да бисте обавили ресетовање на фабричка подешавања у режиму демонстрације"</string>
<string name="retail_demo_reset_next" msgid="8356731459226304963">"Даље"</string>
diff --git a/packages/SettingsLib/res/values-sv/strings.xml b/packages/SettingsLib/res/values-sv/strings.xml
index 040aea67031d..11f446c6e61c 100644
--- a/packages/SettingsLib/res/values-sv/strings.xml
+++ b/packages/SettingsLib/res/values-sv/strings.xml
@@ -415,7 +415,6 @@
<string name="screen_zoom_summary_very_large" msgid="7108563375663670067">"Större"</string>
<string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"Störst"</string>
<string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Anpassad (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
- <string name="help_feedback_label" msgid="6815040660801785649">"Hjälp och feedback"</string>
<string name="content_description_menu_button" msgid="8182594799812351266">"Meny"</string>
<string name="retail_demo_reset_message" msgid="118771671364131297">"Ange lösenord och utför fabriksåterställning i demoläge"</string>
<string name="retail_demo_reset_next" msgid="8356731459226304963">"Nästa"</string>
diff --git a/packages/SettingsLib/res/values-sw/strings.xml b/packages/SettingsLib/res/values-sw/strings.xml
index 8be74eacf53a..ba3aaba3401c 100644
--- a/packages/SettingsLib/res/values-sw/strings.xml
+++ b/packages/SettingsLib/res/values-sw/strings.xml
@@ -415,7 +415,6 @@
<string name="screen_zoom_summary_very_large" msgid="7108563375663670067">"Kubwa kiasi"</string>
<string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"Kubwa zaidi"</string>
<string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Kiwango maalum (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
- <string name="help_feedback_label" msgid="6815040660801785649">"Usaidizi na maoni"</string>
<string name="content_description_menu_button" msgid="8182594799812351266">"Menyu"</string>
<string name="retail_demo_reset_message" msgid="118771671364131297">"Weka nenosiri ili urejeshe mipangilio ya kiwandani ikiwa katika hali ya onyesho."</string>
<string name="retail_demo_reset_next" msgid="8356731459226304963">"Inayofuata"</string>
diff --git a/packages/SettingsLib/res/values-ta/strings.xml b/packages/SettingsLib/res/values-ta/strings.xml
index 225005dc2336..63d5e75170f3 100644
--- a/packages/SettingsLib/res/values-ta/strings.xml
+++ b/packages/SettingsLib/res/values-ta/strings.xml
@@ -415,7 +415,6 @@
<string name="screen_zoom_summary_very_large" msgid="7108563375663670067">"கொஞ்சம் பெரியது"</string>
<string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"மிகப் பெரியது"</string>
<string name="screen_zoom_summary_custom" msgid="5611979864124160447">"தனிப்பயன் (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
- <string name="help_feedback_label" msgid="6815040660801785649">"உதவி &amp; கருத்து"</string>
<string name="content_description_menu_button" msgid="8182594799812351266">"மெனு"</string>
<string name="retail_demo_reset_message" msgid="118771671364131297">"டெமோ பயன்முறையில் ஆரம்பநிலை மீட்டமைவைச் செயல்படுத்த, கடவுச்சொல்லை உள்ளிடவும்"</string>
<string name="retail_demo_reset_next" msgid="8356731459226304963">"அடுத்து"</string>
diff --git a/packages/SettingsLib/res/values-te/strings.xml b/packages/SettingsLib/res/values-te/strings.xml
index 531001ccc481..4af461d093b9 100644
--- a/packages/SettingsLib/res/values-te/strings.xml
+++ b/packages/SettingsLib/res/values-te/strings.xml
@@ -415,7 +415,6 @@
<string name="screen_zoom_summary_very_large" msgid="7108563375663670067">"చాలా పెద్దగా"</string>
<string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"అతి పెద్దగా"</string>
<string name="screen_zoom_summary_custom" msgid="5611979864124160447">"అనుకూలం (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
- <string name="help_feedback_label" msgid="6815040660801785649">"సహాయం &amp; అభిప్రాయం"</string>
<string name="content_description_menu_button" msgid="8182594799812351266">"మెను"</string>
<string name="retail_demo_reset_message" msgid="118771671364131297">"డెమో మోడ్‌లో ఫ్యాక్టరీ రీసెట్‌ను నిర్వహించడానికి పాస్‌వర్డ్‌ను నమోదు చేయండి"</string>
<string name="retail_demo_reset_next" msgid="8356731459226304963">"తర్వాత"</string>
diff --git a/packages/SettingsLib/res/values-th/strings.xml b/packages/SettingsLib/res/values-th/strings.xml
index cf214e1878d8..9cc5c730836c 100644
--- a/packages/SettingsLib/res/values-th/strings.xml
+++ b/packages/SettingsLib/res/values-th/strings.xml
@@ -415,7 +415,6 @@
<string name="screen_zoom_summary_very_large" msgid="7108563375663670067">"ใหญ่ขึ้น"</string>
<string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"ใหญ่ที่สุด"</string>
<string name="screen_zoom_summary_custom" msgid="5611979864124160447">"กำหนดเอง (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
- <string name="help_feedback_label" msgid="6815040660801785649">"ความช่วยเหลือและความคิดเห็น"</string>
<string name="content_description_menu_button" msgid="8182594799812351266">"เมนู"</string>
<string name="retail_demo_reset_message" msgid="118771671364131297">"ป้อนรหัสผ่านเพื่อรีเซ็ตค่าในโหมดสาธิต"</string>
<string name="retail_demo_reset_next" msgid="8356731459226304963">"ถัดไป"</string>
diff --git a/packages/SettingsLib/res/values-tl/strings.xml b/packages/SettingsLib/res/values-tl/strings.xml
index aee95eaa8505..49abe42bd8db 100644
--- a/packages/SettingsLib/res/values-tl/strings.xml
+++ b/packages/SettingsLib/res/values-tl/strings.xml
@@ -415,7 +415,6 @@
<string name="screen_zoom_summary_very_large" msgid="7108563375663670067">"Mas malaki"</string>
<string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"Pinakamalaki"</string>
<string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Custom (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
- <string name="help_feedback_label" msgid="6815040660801785649">"Tulong at feedback"</string>
<string name="content_description_menu_button" msgid="8182594799812351266">"Menu"</string>
<string name="retail_demo_reset_message" msgid="118771671364131297">"Ilagay ang password upang mag-factory reset sa demo mode"</string>
<string name="retail_demo_reset_next" msgid="8356731459226304963">"Susunod"</string>
diff --git a/packages/SettingsLib/res/values-tr/strings.xml b/packages/SettingsLib/res/values-tr/strings.xml
index e4b23f96e455..23a96d95f0e2 100644
--- a/packages/SettingsLib/res/values-tr/strings.xml
+++ b/packages/SettingsLib/res/values-tr/strings.xml
@@ -415,7 +415,6 @@
<string name="screen_zoom_summary_very_large" msgid="7108563375663670067">"Daha büyük"</string>
<string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"En büyük"</string>
<string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Özel (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
- <string name="help_feedback_label" msgid="6815040660801785649">"Yardım ve geri bildirim"</string>
<string name="content_description_menu_button" msgid="8182594799812351266">"Menü"</string>
<string name="retail_demo_reset_message" msgid="118771671364131297">"Demo modunda sıfırlamak için şifreyi girin"</string>
<string name="retail_demo_reset_next" msgid="8356731459226304963">"Sonraki"</string>
diff --git a/packages/SettingsLib/res/values-uk/strings.xml b/packages/SettingsLib/res/values-uk/strings.xml
index 958a3d28a8d2..cea870a49cd5 100644
--- a/packages/SettingsLib/res/values-uk/strings.xml
+++ b/packages/SettingsLib/res/values-uk/strings.xml
@@ -415,7 +415,6 @@
<string name="screen_zoom_summary_very_large" msgid="7108563375663670067">"Більші елементи"</string>
<string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"Найбільші елементи"</string>
<string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Спеціальний масштаб (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
- <string name="help_feedback_label" msgid="6815040660801785649">"Довідка й відгуки"</string>
<string name="content_description_menu_button" msgid="8182594799812351266">"Меню"</string>
<string name="retail_demo_reset_message" msgid="118771671364131297">"Введіть пароль, щоб скинути налаштування в демо-режимі"</string>
<string name="retail_demo_reset_next" msgid="8356731459226304963">"Далі"</string>
diff --git a/packages/SettingsLib/res/values-ur/strings.xml b/packages/SettingsLib/res/values-ur/strings.xml
index 31f0a33b3e64..0fb60d9b4b32 100644
--- a/packages/SettingsLib/res/values-ur/strings.xml
+++ b/packages/SettingsLib/res/values-ur/strings.xml
@@ -415,7 +415,6 @@
<string name="screen_zoom_summary_very_large" msgid="7108563375663670067">"قدرے بڑا"</string>
<string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"سب سے بڑا"</string>
<string name="screen_zoom_summary_custom" msgid="5611979864124160447">"حسب ضرورت (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
- <string name="help_feedback_label" msgid="6815040660801785649">"مدد اور تاثرات"</string>
<string name="content_description_menu_button" msgid="8182594799812351266">"مینو"</string>
<string name="retail_demo_reset_message" msgid="118771671364131297">"ڈیمو موڈ میں فیکٹری ری سیٹ کیلئے پاس ورڈ درج کریں"</string>
<string name="retail_demo_reset_next" msgid="8356731459226304963">"اگلا"</string>
diff --git a/packages/SettingsLib/res/values-uz/strings.xml b/packages/SettingsLib/res/values-uz/strings.xml
index 7ff458864b8c..4690db37ac84 100644
--- a/packages/SettingsLib/res/values-uz/strings.xml
+++ b/packages/SettingsLib/res/values-uz/strings.xml
@@ -415,7 +415,6 @@
<string name="screen_zoom_summary_very_large" msgid="7108563375663670067">"Kattaroq"</string>
<string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"Eng katta"</string>
<string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Moslashtirilgan (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
- <string name="help_feedback_label" msgid="6815040660801785649">"Yordam va fikr-mulohaza"</string>
<string name="content_description_menu_button" msgid="8182594799812351266">"Menyu"</string>
<string name="retail_demo_reset_message" msgid="118771671364131297">"Demo rejimda zavod holatiga qaytarish uchun parolni kiriting"</string>
<string name="retail_demo_reset_next" msgid="8356731459226304963">"Keyingisi"</string>
diff --git a/packages/SettingsLib/res/values-vi/strings.xml b/packages/SettingsLib/res/values-vi/strings.xml
index daa9335a3630..937b37d7ff69 100644
--- a/packages/SettingsLib/res/values-vi/strings.xml
+++ b/packages/SettingsLib/res/values-vi/strings.xml
@@ -415,7 +415,6 @@
<string name="screen_zoom_summary_very_large" msgid="7108563375663670067">"Lớn hơn"</string>
<string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"Lớn nhất"</string>
<string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Tùy chỉnh (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
- <string name="help_feedback_label" msgid="6815040660801785649">"Trợ giúp và phản hồi"</string>
<string name="content_description_menu_button" msgid="8182594799812351266">"Menu"</string>
<string name="retail_demo_reset_message" msgid="118771671364131297">"Nhập mật khẩu để tiến hành khôi phục cài đặt gốc ở chế độ trình diễn"</string>
<string name="retail_demo_reset_next" msgid="8356731459226304963">"Tiếp theo"</string>
diff --git a/packages/SettingsLib/res/values-zh-rCN/strings.xml b/packages/SettingsLib/res/values-zh-rCN/strings.xml
index 6cb27e990a3b..47753fd2c01c 100644
--- a/packages/SettingsLib/res/values-zh-rCN/strings.xml
+++ b/packages/SettingsLib/res/values-zh-rCN/strings.xml
@@ -415,7 +415,6 @@
<string name="screen_zoom_summary_very_large" msgid="7108563375663670067">"较大"</string>
<string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"最大"</string>
<string name="screen_zoom_summary_custom" msgid="5611979864124160447">"自定义 (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
- <string name="help_feedback_label" msgid="6815040660801785649">"帮助和反馈"</string>
<string name="content_description_menu_button" msgid="8182594799812351266">"菜单"</string>
<string name="retail_demo_reset_message" msgid="118771671364131297">"输入密码即可在演示模式下恢复出厂设置"</string>
<string name="retail_demo_reset_next" msgid="8356731459226304963">"下一步"</string>
diff --git a/packages/SettingsLib/res/values-zh-rHK/strings.xml b/packages/SettingsLib/res/values-zh-rHK/strings.xml
index 16039c1c1a58..4cbf5a695a4f 100644
--- a/packages/SettingsLib/res/values-zh-rHK/strings.xml
+++ b/packages/SettingsLib/res/values-zh-rHK/strings.xml
@@ -415,7 +415,6 @@
<string name="screen_zoom_summary_very_large" msgid="7108563375663670067">"較大"</string>
<string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"最大"</string>
<string name="screen_zoom_summary_custom" msgid="5611979864124160447">"自訂 (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
- <string name="help_feedback_label" msgid="6815040660801785649">"說明和意見反映"</string>
<string name="content_description_menu_button" msgid="8182594799812351266">"選單"</string>
<string name="retail_demo_reset_message" msgid="118771671364131297">"輸入密碼即可在示範模式下重設原廠設定"</string>
<string name="retail_demo_reset_next" msgid="8356731459226304963">"下一步"</string>
diff --git a/packages/SettingsLib/res/values-zh-rTW/strings.xml b/packages/SettingsLib/res/values-zh-rTW/strings.xml
index ed6863889dd7..cecc6ac29d89 100644
--- a/packages/SettingsLib/res/values-zh-rTW/strings.xml
+++ b/packages/SettingsLib/res/values-zh-rTW/strings.xml
@@ -415,7 +415,6 @@
<string name="screen_zoom_summary_very_large" msgid="7108563375663670067">"較大"</string>
<string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"最大"</string>
<string name="screen_zoom_summary_custom" msgid="5611979864124160447">"自訂 (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
- <string name="help_feedback_label" msgid="6815040660801785649">"說明與意見回饋"</string>
<string name="content_description_menu_button" msgid="8182594799812351266">"選單"</string>
<string name="retail_demo_reset_message" msgid="118771671364131297">"如要在示範模式中恢復原廠設定,請輸入密碼"</string>
<string name="retail_demo_reset_next" msgid="8356731459226304963">"下一步"</string>
diff --git a/packages/SettingsLib/res/values-zu/strings.xml b/packages/SettingsLib/res/values-zu/strings.xml
index 957584adb73c..94c3abfdba6c 100644
--- a/packages/SettingsLib/res/values-zu/strings.xml
+++ b/packages/SettingsLib/res/values-zu/strings.xml
@@ -415,7 +415,6 @@
<string name="screen_zoom_summary_very_large" msgid="7108563375663670067">"Okukhulu kakhulu"</string>
<string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"Okukhulu kakhulu"</string>
<string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Ngokwezifiso (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
- <string name="help_feedback_label" msgid="6815040660801785649">"Usizo nempendulo"</string>
<string name="content_description_menu_button" msgid="8182594799812351266">"Imenyu"</string>
<string name="retail_demo_reset_message" msgid="118771671364131297">"Faka iphasiwedi ukuze wenze ukusetha kwefekthri kumodi yedemo"</string>
<string name="retail_demo_reset_next" msgid="8356731459226304963">"Okulandelayo"</string>
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/MapProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/MapProfile.java
index 689669faf60d..caea04f87a50 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/MapProfile.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/MapProfile.java
@@ -32,11 +32,10 @@ import java.util.ArrayList;
import java.util.List;
/**
- * MapProfile handles Bluetooth MAP profile.
+ * MapProfile handles the Bluetooth MAP MSE role
*/
public class MapProfile implements LocalBluetoothProfile {
private static final String TAG = "MapProfile";
- private static boolean V = true;
private BluetoothMap mService;
private boolean mIsProfileReady;
@@ -59,7 +58,7 @@ public class MapProfile implements LocalBluetoothProfile {
implements BluetoothProfile.ServiceListener {
public void onServiceConnected(int profile, BluetoothProfile proxy) {
- if (V) Log.d(TAG,"Bluetooth service connected");
+ Log.d(TAG, "Bluetooth service connected");
mService = (BluetoothMap) proxy;
// We just bound to the service, so refresh the UI for any connected MAP devices.
List<BluetoothDevice> deviceList = mService.getConnectedDevices();
@@ -81,14 +80,14 @@ public class MapProfile implements LocalBluetoothProfile {
}
public void onServiceDisconnected(int profile) {
- if (V) Log.d(TAG,"Bluetooth service disconnected");
+ Log.d(TAG, "Bluetooth service disconnected");
mProfileManager.callServiceDisconnectedListeners();
mIsProfileReady=false;
}
}
public boolean isProfileReady() {
- if(V) Log.d(TAG,"isProfileReady(): "+ mIsProfileReady);
+ Log.d(TAG, "isProfileReady(): " + mIsProfileReady);
return mIsProfileReady;
}
@@ -114,45 +113,45 @@ public class MapProfile implements LocalBluetoothProfile {
}
public boolean connect(BluetoothDevice device) {
- if(V)Log.d(TAG,"connect() - should not get called");
+ Log.d(TAG, "connect() - should not get called");
return false; // MAP never connects out
}
public boolean disconnect(BluetoothDevice device) {
- if (mService == null) return false;
- List<BluetoothDevice> deviceList = mService.getConnectedDevices();
- if (!deviceList.isEmpty() && deviceList.get(0).equals(device)) {
- if (mService.getPriority(device) > BluetoothProfile.PRIORITY_ON) {
- mService.setPriority(device, BluetoothProfile.PRIORITY_ON);
- }
- return mService.disconnect(device);
- } else {
+ if (mService == null) {
return false;
}
+ if (mService.getPriority(device) > BluetoothProfile.PRIORITY_ON) {
+ mService.setPriority(device, BluetoothProfile.PRIORITY_ON);
+ }
+ return mService.disconnect(device);
}
public int getConnectionStatus(BluetoothDevice device) {
- if (mService == null) return BluetoothProfile.STATE_DISCONNECTED;
- List<BluetoothDevice> deviceList = mService.getConnectedDevices();
- if(V) Log.d(TAG,"getConnectionStatus: status is: "+ mService.getConnectionState(device));
-
- return !deviceList.isEmpty() && deviceList.get(0).equals(device)
- ? mService.getConnectionState(device)
- : BluetoothProfile.STATE_DISCONNECTED;
+ if (mService == null) {
+ return BluetoothProfile.STATE_DISCONNECTED;
+ }
+ return mService.getConnectionState(device);
}
public boolean isPreferred(BluetoothDevice device) {
- if (mService == null) return false;
+ if (mService == null) {
+ return false;
+ }
return mService.getPriority(device) > BluetoothProfile.PRIORITY_OFF;
}
public int getPreferred(BluetoothDevice device) {
- if (mService == null) return BluetoothProfile.PRIORITY_OFF;
+ if (mService == null) {
+ return BluetoothProfile.PRIORITY_OFF;
+ }
return mService.getPriority(device);
}
public void setPreferred(BluetoothDevice device, boolean preferred) {
- if (mService == null) return;
+ if (mService == null) {
+ return;
+ }
if (preferred) {
if (mService.getPriority(device) < BluetoothProfile.PRIORITY_ON) {
mService.setPriority(device, BluetoothProfile.PRIORITY_ON);
@@ -163,7 +162,9 @@ public class MapProfile implements LocalBluetoothProfile {
}
public List<BluetoothDevice> getConnectedDevices() {
- if (mService == null) return new ArrayList<BluetoothDevice>(0);
+ if (mService == null) {
+ return new ArrayList<BluetoothDevice>(0);
+ }
return mService.getDevicesMatchingConnectionStates(
new int[] {BluetoothProfile.STATE_CONNECTED,
BluetoothProfile.STATE_CONNECTING,
@@ -201,7 +202,7 @@ public class MapProfile implements LocalBluetoothProfile {
}
protected void finalize() {
- if (V) Log.d(TAG, "finalize()");
+ Log.d(TAG, "finalize()");
if (mService != null) {
try {
BluetoothAdapter.getDefaultAdapter().closeProfileProxy(BluetoothProfile.MAP,
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/GenerationRegistry.java b/packages/SettingsProvider/src/com/android/providers/settings/GenerationRegistry.java
index 3e6c3f2e5b85..044ec867aef4 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/GenerationRegistry.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/GenerationRegistry.java
@@ -111,6 +111,7 @@ final class GenerationRegistry {
}
}
+ @GuardedBy("mLock")
private MemoryIntArray getBackingStoreLocked() {
if (mBackingStore == null) {
// One for the global table, two for system and secure tables for a
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
index 500199f7a521..290a4f83a40a 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
@@ -722,6 +722,7 @@ public class SettingsProvider extends ContentProvider {
}
}
+ @GuardedBy("mLock")
private void dumpForUserLocked(int userId, PrintWriter pw) {
if (userId == UserHandle.USER_SYSTEM) {
pw.println("GLOBAL SETTINGS (user " + userId + ")");
@@ -1179,6 +1180,7 @@ public class SettingsProvider extends ContentProvider {
&& UserHandle.getAppId(Binder.getCallingUid()) >= Process.FIRST_APPLICATION_UID;
}
+ @GuardedBy("mLock")
private Setting getSsaidSettingLocked(PackageInfo callingPkg, int owningUserId) {
// Get uid of caller (key) used to store ssaid value
String name = Integer.toString(
@@ -1709,6 +1711,7 @@ public class SettingsProvider extends ContentProvider {
}
}
+ @GuardedBy("mLock")
private List<String> getSettingsNamesLocked(int settingsType, int userId) {
// Don't enforce the instant app whitelist for now -- its too prone to unintended breakage
// in the current form.
@@ -1801,6 +1804,7 @@ public class SettingsProvider extends ContentProvider {
*
* @returns whether the enabled location providers changed.
*/
+ @GuardedBy("mLock")
private boolean updateLocationProvidersAllowedLocked(String value, String tag,
int owningUserId, boolean makeDefault, boolean forceNotify) {
if (TextUtils.isEmpty(value)) {
@@ -2718,6 +2722,7 @@ public class SettingsProvider extends ContentProvider {
}
}
+ @GuardedBy("secureSettings.mLock")
private void ensureSecureSettingAndroidIdSetLocked(SettingsState secureSettings) {
Setting value = secureSettings.getSettingLocked(Settings.Secure.ANDROID_ID);
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsState.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsState.java
index e57483a8c734..389d627a9bd6 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsState.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsState.java
@@ -274,6 +274,7 @@ final class SettingsState {
}
// The settings provider must hold its lock when calling here.
+ @GuardedBy("mLock")
public int getVersionLocked() {
return mVersion;
}
@@ -283,6 +284,7 @@ final class SettingsState {
}
// The settings provider must hold its lock when calling here.
+ @GuardedBy("mLock")
public void setVersionLocked(int version) {
if (version == mVersion) {
return;
@@ -293,6 +295,7 @@ final class SettingsState {
}
// The settings provider must hold its lock when calling here.
+ @GuardedBy("mLock")
public void removeSettingsForPackageLocked(String packageName) {
boolean removedSomething = false;
@@ -317,6 +320,7 @@ final class SettingsState {
}
// The settings provider must hold its lock when calling here.
+ @GuardedBy("mLock")
public List<String> getSettingNamesLocked() {
ArrayList<String> names = new ArrayList<>();
final int settingsCount = mSettings.size();
@@ -328,6 +332,7 @@ final class SettingsState {
}
// The settings provider must hold its lock when calling here.
+ @GuardedBy("mLock")
public Setting getSettingLocked(String name) {
if (TextUtils.isEmpty(name)) {
return mNullSetting;
@@ -350,6 +355,7 @@ final class SettingsState {
}
// The settings provider must hold its lock when calling here.
+ @GuardedBy("mLock")
public void resetSettingDefaultValueLocked(String name) {
Setting oldSetting = getSettingLocked(name);
if (oldSetting != null && !oldSetting.isNull() && oldSetting.getDefaultValue() != null) {
@@ -366,6 +372,7 @@ final class SettingsState {
}
// The settings provider must hold its lock when calling here.
+ @GuardedBy("mLock")
public boolean insertSettingLocked(String name, String value, String tag,
boolean makeDefault, String packageName) {
if (TextUtils.isEmpty(name)) {
@@ -407,6 +414,7 @@ final class SettingsState {
}
// The settings provider must hold its lock when calling here.
+ @GuardedBy("mLock")
public boolean deleteSettingLocked(String name) {
if (TextUtils.isEmpty(name) || !hasSettingLocked(name)) {
return false;
@@ -429,6 +437,7 @@ final class SettingsState {
}
// The settings provider must hold its lock when calling here.
+ @GuardedBy("mLock")
public boolean resetSettingLocked(String name) {
if (TextUtils.isEmpty(name) || !hasSettingLocked(name)) {
return false;
@@ -458,6 +467,7 @@ final class SettingsState {
}
// The settings provider must hold its lock when calling here.
+ @GuardedBy("mLock")
public void destroyLocked(Runnable callback) {
mHandler.removeMessages(MyHandler.MSG_PERSIST_SETTINGS);
if (callback != null) {
@@ -471,6 +481,7 @@ final class SettingsState {
}
}
+ @GuardedBy("mLock")
private void addHistoricalOperationLocked(String type, Setting setting) {
if (mHistoricalOperations == null) {
return;
@@ -553,6 +564,7 @@ final class SettingsState {
}
}
+ @GuardedBy("mLock")
private void updateMemoryUsagePerPackageLocked(String packageName, String oldValue,
String newValue, String oldDefaultValue, String newDefaultValue) {
if (mMaxBytesPerAppPackage == MAX_BYTES_PER_APP_PACKAGE_UNLIMITED) {
@@ -588,10 +600,12 @@ final class SettingsState {
mPackageToMemoryUsage.put(packageName, newSize);
}
+ @GuardedBy("mLock")
private boolean hasSettingLocked(String name) {
return mSettings.indexOfKey(name) >= 0;
}
+ @GuardedBy("mLock")
private void scheduleWriteIfNeededLocked() {
// If dirty then we have a write already scheduled.
if (!mDirty) {
@@ -600,6 +614,7 @@ final class SettingsState {
}
}
+ @GuardedBy("mLock")
private void writeStateAsyncLocked() {
final long currentTimeMillis = SystemClock.uptimeMillis();
@@ -771,6 +786,7 @@ final class SettingsState {
}
}
+ @GuardedBy("mLock")
private void readStateSyncLocked() {
FileInputStream in;
try {
@@ -820,6 +836,7 @@ final class SettingsState {
}
}
+ @GuardedBy("mLock")
private void parseSettingsLocked(XmlPullParser parser)
throws IOException, XmlPullParserException {
diff --git a/packages/SystemUI/res-keyguard/values-pt-rBR/strings.xml b/packages/SystemUI/res-keyguard/values-pt-rBR/strings.xml
index 862b964a7671..90f46cefa304 100644
--- a/packages/SystemUI/res-keyguard/values-pt-rBR/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-pt-rBR/strings.xml
@@ -22,9 +22,9 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_name" msgid="3171996292755059205">"Bloqueio do teclado"</string>
<string name="keyguard_password_enter_pin_code" msgid="3420548423949593123">"Insira o código PIN"</string>
- <string name="keyguard_password_enter_puk_code" msgid="670683628782925409">"Digite o PUK do SIM e o novo código PIN."</string>
- <string name="keyguard_password_enter_puk_prompt" msgid="3747778500166059332">"Código PUK do SIM"</string>
- <string name="keyguard_password_enter_pin_prompt" msgid="8188243197504453830">"Novo código PIN do SIM"</string>
+ <string name="keyguard_password_enter_puk_code" msgid="670683628782925409">"Digite o PUK do chip e o novo código PIN."</string>
+ <string name="keyguard_password_enter_puk_prompt" msgid="3747778500166059332">"Código PUK do chip"</string>
+ <string name="keyguard_password_enter_pin_prompt" msgid="8188243197504453830">"Novo código PIN do chip"</string>
<string name="keyguard_password_entry_touch_hint" msgid="5790410752696806482"><font size="17">"Toque para inserir a senha"</font></string>
<string name="keyguard_password_enter_password_code" msgid="595980919238127672">"Digite a senha para desbloquear"</string>
<string name="keyguard_password_enter_pin_password_code" msgid="7504123374204446086">"Insira o PIN para desbloquear"</string>
@@ -40,20 +40,20 @@
<string name="keyguard_low_battery" msgid="9218432555787624490">"Conecte o seu carregador."</string>
<string name="keyguard_instructions_when_pattern_disabled" msgid="8566679946700751371">"Pressione Menu para desbloquear."</string>
<string name="keyguard_network_locked_message" msgid="6743537524631420759">"Rede bloqueada"</string>
- <string name="keyguard_missing_sim_message_short" msgid="6327533369959764518">"Sem cartão SIM"</string>
- <string name="keyguard_missing_sim_message" product="tablet" msgid="4550152848200783542">"Não há um cartão SIM no tablet."</string>
- <string name="keyguard_missing_sim_message" product="default" msgid="6585414237800161146">"Não há um cartão SIM no smartphone."</string>
- <string name="keyguard_missing_sim_instructions" msgid="7350295932015220392">"Insira um cartão SIM."</string>
- <string name="keyguard_missing_sim_instructions_long" msgid="589889372883904477">"O cartão SIM não foi inserido ou não é possível lê-lo. Insira um cartão SIM."</string>
- <string name="keyguard_permanent_disabled_sim_message_short" msgid="654102080186420706">"Cartão SIM inutilizável."</string>
- <string name="keyguard_permanent_disabled_sim_instructions" msgid="4683178224791318347">"O cartão SIM foi desativado permanentemente.\nEntre em contato com seu provedor de serviços sem fio para receber outro cartão SIM."</string>
- <string name="keyguard_sim_locked_message" msgid="953766009432168127">"O cartão SIM está bloqueado."</string>
- <string name="keyguard_sim_puk_locked_message" msgid="1772789643694942073">"O cartão SIM está bloqueado pelo PUK."</string>
- <string name="keyguard_sim_unlock_progress_dialog_message" msgid="3586601150825821675">"Desbloqueando o cartão SIM…"</string>
+ <string name="keyguard_missing_sim_message_short" msgid="6327533369959764518">"Sem chip"</string>
+ <string name="keyguard_missing_sim_message" product="tablet" msgid="4550152848200783542">"Não há um chip no tablet."</string>
+ <string name="keyguard_missing_sim_message" product="default" msgid="6585414237800161146">"Não há um chip no smartphone."</string>
+ <string name="keyguard_missing_sim_instructions" msgid="7350295932015220392">"Insira um chip."</string>
+ <string name="keyguard_missing_sim_instructions_long" msgid="589889372883904477">"O chip não foi inserido ou não é possível lê-lo. Insira um chip."</string>
+ <string name="keyguard_permanent_disabled_sim_message_short" msgid="654102080186420706">"Chip inutilizável."</string>
+ <string name="keyguard_permanent_disabled_sim_instructions" msgid="4683178224791318347">"O chip foi desativado permanentemente.\nEntre em contato com seu provedor de serviços sem fio para receber outro chip."</string>
+ <string name="keyguard_sim_locked_message" msgid="953766009432168127">"O chip está bloqueado."</string>
+ <string name="keyguard_sim_puk_locked_message" msgid="1772789643694942073">"O chip está bloqueado pelo PUK."</string>
+ <string name="keyguard_sim_unlock_progress_dialog_message" msgid="3586601150825821675">"Desbloqueando o chip…"</string>
<string name="keyguard_accessibility_pin_area" msgid="703175752097279029">"Área do PIN"</string>
<string name="keyguard_accessibility_password" msgid="7695303207740941101">"Senha do dispositivo"</string>
- <string name="keyguard_accessibility_sim_pin_area" msgid="912702510825058921">"Área do PIN SIM"</string>
- <string name="keyguard_accessibility_sim_puk_area" msgid="136979425761438705">"Área do PUK SIM"</string>
+ <string name="keyguard_accessibility_sim_pin_area" msgid="912702510825058921">"Área do PIN do chip"</string>
+ <string name="keyguard_accessibility_sim_puk_area" msgid="136979425761438705">"Área do PUK do chip"</string>
<string name="keyguard_accessibility_next_alarm" msgid="5835196989158584991">"Próximo alarme definido para <xliff:g id="ALARM">%1$s</xliff:g>"</string>
<string name="keyboardview_keycode_delete" msgid="6883116827512721630">"Excluir"</string>
<string name="disable_carrier_button_text" msgid="6914341927421916114">"Desativar eSIM"</string>
@@ -69,19 +69,19 @@
<item quantity="other">Tente novamente em <xliff:g id="NUMBER">%d</xliff:g> segundos.</item>
</plurals>
<string name="kg_pattern_instructions" msgid="5547646893001491340">"Desenhe seu padrão"</string>
- <string name="kg_sim_pin_instructions" msgid="6389000973113699187">"Informe o PIN do cartão SIM."</string>
- <string name="kg_sim_pin_instructions_multi" msgid="1643757228644271861">"Informe o PIN do cartão SIM para \"<xliff:g id="CARRIER">%1$s</xliff:g>\"."</string>
+ <string name="kg_sim_pin_instructions" msgid="6389000973113699187">"Informe o PIN do chip."</string>
+ <string name="kg_sim_pin_instructions_multi" msgid="1643757228644271861">"Informe o PIN do chip para \"<xliff:g id="CARRIER">%1$s</xliff:g>\"."</string>
<string name="kg_sim_lock_esim_instructions" msgid="4416732549172148542">"<xliff:g id="PREVIOUS_MSG">%1$s</xliff:g> Desative o eSIM para usar o dispositivo sem serviço móvel."</string>
<string name="kg_pin_instructions" msgid="4069609316644030034">"Digite o PIN"</string>
<string name="kg_password_instructions" msgid="136952397352976538">"Digite a senha"</string>
- <string name="kg_puk_enter_puk_hint" msgid="2288964170039899277">"O SIM foi desativado. Insira o código PUK para continuar. Entre em contato com a operadora para mais detalhes."</string>
- <string name="kg_puk_enter_puk_hint_multi" msgid="1373131883510840794">"O SIM \"<xliff:g id="CARRIER">%1$s</xliff:g>\" foi desativado. Informe o código PUK para continuar. Entre em contato com a operadora para saber mais detalhes."</string>
+ <string name="kg_puk_enter_puk_hint" msgid="2288964170039899277">"O chip foi desativado. Insira o código PUK para continuar. Entre em contato com a operadora para mais detalhes."</string>
+ <string name="kg_puk_enter_puk_hint_multi" msgid="1373131883510840794">"O chip \"<xliff:g id="CARRIER">%1$s</xliff:g>\" foi desativado. Informe o código PUK para continuar. Entre em contato com a operadora para saber mais detalhes."</string>
<string name="kg_puk_enter_pin_hint" msgid="3137789674920391087">"Digite o código PIN desejado"</string>
<string name="kg_enter_confirm_pin_hint" msgid="3089485999116759671">"Confirme o código PIN desejado"</string>
- <string name="kg_sim_unlock_progress_dialog_message" msgid="4471738151810900114">"Desbloqueando o cartão SIM…"</string>
+ <string name="kg_sim_unlock_progress_dialog_message" msgid="4471738151810900114">"Desbloqueando o chip…"</string>
<string name="kg_invalid_sim_pin_hint" msgid="3057533256729513335">"Digite um PIN com 4 a 8 números."</string>
<string name="kg_invalid_sim_puk_hint" msgid="6003602401368264144">"O código PUK deve ter oito números ou mais."</string>
- <string name="kg_invalid_puk" msgid="5399287873762592502">"Introduza novamente o código PUK correto. Muitas tentativas malsucedidas desativarão permanentemente o SIM."</string>
+ <string name="kg_invalid_puk" msgid="5399287873762592502">"Introduza novamente o código PUK correto. Muitas tentativas malsucedidas desativarão permanentemente o chip."</string>
<string name="kg_invalid_confirm_pin_hint" product="default" msgid="5672736555427444330">"Os códigos PIN não coincidem"</string>
<string name="kg_login_too_many_attempts" msgid="6604574268387867255">"Muitas tentativas de padrão"</string>
<string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8637788033282252027">"Você digitou seu PIN incorretamente <xliff:g id="NUMBER_0">%1$d</xliff:g> vezes. \n\nTente novamente em <xliff:g id="NUMBER_1">%2$d</xliff:g> segundos."</string>
@@ -101,18 +101,18 @@
<string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="8476407539834855">"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="956706236554092172">"Você desenhou sua sequência 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 o login do Google para desbloquear seu 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="8364140853305528449">"Você desenhou sua sequência 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 o login do Google para desbloquear.\n\n Tente novamente em <xliff:g id="NUMBER_2">%3$d</xliff:g> segundos."</string>
- <string name="kg_password_wrong_pin_code_pukked" msgid="3389829202093674267">"Código PIN do SIM incorreto. Entre em contato com a operadora para desbloquear o dispositivo."</string>
+ <string name="kg_password_wrong_pin_code_pukked" msgid="3389829202093674267">"Código PIN do chip incorreto. Entre em contato com a operadora para desbloquear o dispositivo."</string>
<plurals name="kg_password_wrong_pin_code" formatted="false" msgid="4314341367727055967">
- <item quantity="one">Código PIN do SIM incorreto. Tentativas restantes: <xliff:g id="NUMBER_1">%d</xliff:g>.</item>
- <item quantity="other">Código PIN do SIM incorreto. Tentativas restantes: <xliff:g id="NUMBER_1">%d</xliff:g>.</item>
+ <item quantity="one">Código PIN do chip incorreto. Tentativas restantes: <xliff:g id="NUMBER_1">%d</xliff:g>.</item>
+ <item quantity="other">Código PIN do chip incorreto. Tentativas restantes: <xliff:g id="NUMBER_1">%d</xliff:g>.</item>
</plurals>
- <string name="kg_password_wrong_puk_code_dead" msgid="3329017604125179374">"O SIM está inutilizável. Entre em contato com a operadora."</string>
+ <string name="kg_password_wrong_puk_code_dead" msgid="3329017604125179374">"O chip não pode ser utilizado. Entre em contato com a operadora."</string>
<plurals name="kg_password_wrong_puk_code" formatted="false" msgid="2287504898931957513">
- <item quantity="one">Código PUK do SIM incorreto. Tentativas restantes: <xliff:g id="NUMBER_1">%d</xliff:g>. Caso o código correto não seja digitado, o SIM se tornará permanentemente inutilizável.</item>
- <item quantity="other">Código PUK do SIM incorreto. Tentativas restantes: <xliff:g id="NUMBER_1">%d</xliff:g>. Caso o código correto não seja digitado, o SIM se tornará permanentemente inutilizável.</item>
+ <item quantity="one">Código PUK do chip incorreto. Tentativas restantes: <xliff:g id="NUMBER_1">%d</xliff:g>. Caso o código correto não seja digitado, o chip se tornará permanentemente inutilizável.</item>
+ <item quantity="other">Código PUK do chip incorreto. Tentativas restantes: <xliff:g id="NUMBER_1">%d</xliff:g>. Caso o código correto não seja digitado, o chip se tornará permanentemente inutilizável.</item>
</plurals>
- <string name="kg_password_pin_failed" msgid="8769990811451236223">"Falha na operação de PIN do SIM."</string>
- <string name="kg_password_puk_failed" msgid="1331621440873439974">"Falha na operação de PUK do SIM."</string>
+ <string name="kg_password_pin_failed" msgid="8769990811451236223">"Falha na operação de PIN do chip."</string>
+ <string name="kg_password_puk_failed" msgid="1331621440873439974">"Falha na operação de PUK do chip."</string>
<string name="kg_pin_accepted" msgid="7637293533973802143">"Código aceito."</string>
<string name="keyguard_carrier_default" msgid="4274828292998453695">"Sem serviço."</string>
<string name="accessibility_ime_switch_button" msgid="2695096475319405612">"Alterar o método de entrada"</string>
@@ -143,11 +143,11 @@
<string name="kg_fingerprint_not_recognized" msgid="7854413849848459418">"Não reconhecido"</string>
<string name="kg_face_not_recognized" msgid="6382535088345875294">"Não reconhecido"</string>
<plurals name="kg_password_default_pin_message" formatted="false" msgid="3739658416797652781">
- <item quantity="one">Informe o PIN do SIM. Você tem <xliff:g id="NUMBER_1">%d</xliff:g> tentativa restante.</item>
- <item quantity="other">Informe o PIN do SIM. Você tem <xliff:g id="NUMBER_1">%d</xliff:g> tentativas restantes.</item>
+ <item quantity="one">Informe o PIN do chip. Você tem <xliff:g id="NUMBER_1">%d</xliff:g> tentativa restante.</item>
+ <item quantity="other">Informe o PIN do chip. Você tem <xliff:g id="NUMBER_1">%d</xliff:g> tentativas restantes.</item>
</plurals>
<plurals name="kg_password_default_puk_message" formatted="false" msgid="8744416410184198352">
- <item quantity="one">O SIM agora está desativado. Informe o código PUK para continuar. Você tem <xliff:g id="_NUMBER_1">%d</xliff:g> tentativa restante antes de o SIM se tornar permanentemente inutilizável. Entre em contato com a operadora para saber mais detalhes.</item>
- <item quantity="other">O SIM agora está desativado. Informe o código PUK para continuar. Você tem <xliff:g id="_NUMBER_1">%d</xliff:g> tentativas restantes antes de o SIM se tornar permanentemente inutilizável. Entre em contato com a operadora para saber mais detalhes.</item>
+ <item quantity="one">O chip agora está desativado. Informe o código PUK para continuar. Você tem <xliff:g id="_NUMBER_1">%d</xliff:g> tentativa restante antes de o chip se tornar permanentemente inutilizável. Entre em contato com a operadora para saber mais detalhes.</item>
+ <item quantity="other">O chip agora está desativado. Informe o código PUK para continuar. Você tem <xliff:g id="_NUMBER_1">%d</xliff:g> tentativas restantes antes de o chip se tornar permanentemente inutilizável. Entre em contato com a operadora para saber mais detalhes.</item>
</plurals>
</resources>
diff --git a/packages/SystemUI/res-keyguard/values-pt/strings.xml b/packages/SystemUI/res-keyguard/values-pt/strings.xml
index 862b964a7671..90f46cefa304 100644
--- a/packages/SystemUI/res-keyguard/values-pt/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-pt/strings.xml
@@ -22,9 +22,9 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_name" msgid="3171996292755059205">"Bloqueio do teclado"</string>
<string name="keyguard_password_enter_pin_code" msgid="3420548423949593123">"Insira o código PIN"</string>
- <string name="keyguard_password_enter_puk_code" msgid="670683628782925409">"Digite o PUK do SIM e o novo código PIN."</string>
- <string name="keyguard_password_enter_puk_prompt" msgid="3747778500166059332">"Código PUK do SIM"</string>
- <string name="keyguard_password_enter_pin_prompt" msgid="8188243197504453830">"Novo código PIN do SIM"</string>
+ <string name="keyguard_password_enter_puk_code" msgid="670683628782925409">"Digite o PUK do chip e o novo código PIN."</string>
+ <string name="keyguard_password_enter_puk_prompt" msgid="3747778500166059332">"Código PUK do chip"</string>
+ <string name="keyguard_password_enter_pin_prompt" msgid="8188243197504453830">"Novo código PIN do chip"</string>
<string name="keyguard_password_entry_touch_hint" msgid="5790410752696806482"><font size="17">"Toque para inserir a senha"</font></string>
<string name="keyguard_password_enter_password_code" msgid="595980919238127672">"Digite a senha para desbloquear"</string>
<string name="keyguard_password_enter_pin_password_code" msgid="7504123374204446086">"Insira o PIN para desbloquear"</string>
@@ -40,20 +40,20 @@
<string name="keyguard_low_battery" msgid="9218432555787624490">"Conecte o seu carregador."</string>
<string name="keyguard_instructions_when_pattern_disabled" msgid="8566679946700751371">"Pressione Menu para desbloquear."</string>
<string name="keyguard_network_locked_message" msgid="6743537524631420759">"Rede bloqueada"</string>
- <string name="keyguard_missing_sim_message_short" msgid="6327533369959764518">"Sem cartão SIM"</string>
- <string name="keyguard_missing_sim_message" product="tablet" msgid="4550152848200783542">"Não há um cartão SIM no tablet."</string>
- <string name="keyguard_missing_sim_message" product="default" msgid="6585414237800161146">"Não há um cartão SIM no smartphone."</string>
- <string name="keyguard_missing_sim_instructions" msgid="7350295932015220392">"Insira um cartão SIM."</string>
- <string name="keyguard_missing_sim_instructions_long" msgid="589889372883904477">"O cartão SIM não foi inserido ou não é possível lê-lo. Insira um cartão SIM."</string>
- <string name="keyguard_permanent_disabled_sim_message_short" msgid="654102080186420706">"Cartão SIM inutilizável."</string>
- <string name="keyguard_permanent_disabled_sim_instructions" msgid="4683178224791318347">"O cartão SIM foi desativado permanentemente.\nEntre em contato com seu provedor de serviços sem fio para receber outro cartão SIM."</string>
- <string name="keyguard_sim_locked_message" msgid="953766009432168127">"O cartão SIM está bloqueado."</string>
- <string name="keyguard_sim_puk_locked_message" msgid="1772789643694942073">"O cartão SIM está bloqueado pelo PUK."</string>
- <string name="keyguard_sim_unlock_progress_dialog_message" msgid="3586601150825821675">"Desbloqueando o cartão SIM…"</string>
+ <string name="keyguard_missing_sim_message_short" msgid="6327533369959764518">"Sem chip"</string>
+ <string name="keyguard_missing_sim_message" product="tablet" msgid="4550152848200783542">"Não há um chip no tablet."</string>
+ <string name="keyguard_missing_sim_message" product="default" msgid="6585414237800161146">"Não há um chip no smartphone."</string>
+ <string name="keyguard_missing_sim_instructions" msgid="7350295932015220392">"Insira um chip."</string>
+ <string name="keyguard_missing_sim_instructions_long" msgid="589889372883904477">"O chip não foi inserido ou não é possível lê-lo. Insira um chip."</string>
+ <string name="keyguard_permanent_disabled_sim_message_short" msgid="654102080186420706">"Chip inutilizável."</string>
+ <string name="keyguard_permanent_disabled_sim_instructions" msgid="4683178224791318347">"O chip foi desativado permanentemente.\nEntre em contato com seu provedor de serviços sem fio para receber outro chip."</string>
+ <string name="keyguard_sim_locked_message" msgid="953766009432168127">"O chip está bloqueado."</string>
+ <string name="keyguard_sim_puk_locked_message" msgid="1772789643694942073">"O chip está bloqueado pelo PUK."</string>
+ <string name="keyguard_sim_unlock_progress_dialog_message" msgid="3586601150825821675">"Desbloqueando o chip…"</string>
<string name="keyguard_accessibility_pin_area" msgid="703175752097279029">"Área do PIN"</string>
<string name="keyguard_accessibility_password" msgid="7695303207740941101">"Senha do dispositivo"</string>
- <string name="keyguard_accessibility_sim_pin_area" msgid="912702510825058921">"Área do PIN SIM"</string>
- <string name="keyguard_accessibility_sim_puk_area" msgid="136979425761438705">"Área do PUK SIM"</string>
+ <string name="keyguard_accessibility_sim_pin_area" msgid="912702510825058921">"Área do PIN do chip"</string>
+ <string name="keyguard_accessibility_sim_puk_area" msgid="136979425761438705">"Área do PUK do chip"</string>
<string name="keyguard_accessibility_next_alarm" msgid="5835196989158584991">"Próximo alarme definido para <xliff:g id="ALARM">%1$s</xliff:g>"</string>
<string name="keyboardview_keycode_delete" msgid="6883116827512721630">"Excluir"</string>
<string name="disable_carrier_button_text" msgid="6914341927421916114">"Desativar eSIM"</string>
@@ -69,19 +69,19 @@
<item quantity="other">Tente novamente em <xliff:g id="NUMBER">%d</xliff:g> segundos.</item>
</plurals>
<string name="kg_pattern_instructions" msgid="5547646893001491340">"Desenhe seu padrão"</string>
- <string name="kg_sim_pin_instructions" msgid="6389000973113699187">"Informe o PIN do cartão SIM."</string>
- <string name="kg_sim_pin_instructions_multi" msgid="1643757228644271861">"Informe o PIN do cartão SIM para \"<xliff:g id="CARRIER">%1$s</xliff:g>\"."</string>
+ <string name="kg_sim_pin_instructions" msgid="6389000973113699187">"Informe o PIN do chip."</string>
+ <string name="kg_sim_pin_instructions_multi" msgid="1643757228644271861">"Informe o PIN do chip para \"<xliff:g id="CARRIER">%1$s</xliff:g>\"."</string>
<string name="kg_sim_lock_esim_instructions" msgid="4416732549172148542">"<xliff:g id="PREVIOUS_MSG">%1$s</xliff:g> Desative o eSIM para usar o dispositivo sem serviço móvel."</string>
<string name="kg_pin_instructions" msgid="4069609316644030034">"Digite o PIN"</string>
<string name="kg_password_instructions" msgid="136952397352976538">"Digite a senha"</string>
- <string name="kg_puk_enter_puk_hint" msgid="2288964170039899277">"O SIM foi desativado. Insira o código PUK para continuar. Entre em contato com a operadora para mais detalhes."</string>
- <string name="kg_puk_enter_puk_hint_multi" msgid="1373131883510840794">"O SIM \"<xliff:g id="CARRIER">%1$s</xliff:g>\" foi desativado. Informe o código PUK para continuar. Entre em contato com a operadora para saber mais detalhes."</string>
+ <string name="kg_puk_enter_puk_hint" msgid="2288964170039899277">"O chip foi desativado. Insira o código PUK para continuar. Entre em contato com a operadora para mais detalhes."</string>
+ <string name="kg_puk_enter_puk_hint_multi" msgid="1373131883510840794">"O chip \"<xliff:g id="CARRIER">%1$s</xliff:g>\" foi desativado. Informe o código PUK para continuar. Entre em contato com a operadora para saber mais detalhes."</string>
<string name="kg_puk_enter_pin_hint" msgid="3137789674920391087">"Digite o código PIN desejado"</string>
<string name="kg_enter_confirm_pin_hint" msgid="3089485999116759671">"Confirme o código PIN desejado"</string>
- <string name="kg_sim_unlock_progress_dialog_message" msgid="4471738151810900114">"Desbloqueando o cartão SIM…"</string>
+ <string name="kg_sim_unlock_progress_dialog_message" msgid="4471738151810900114">"Desbloqueando o chip…"</string>
<string name="kg_invalid_sim_pin_hint" msgid="3057533256729513335">"Digite um PIN com 4 a 8 números."</string>
<string name="kg_invalid_sim_puk_hint" msgid="6003602401368264144">"O código PUK deve ter oito números ou mais."</string>
- <string name="kg_invalid_puk" msgid="5399287873762592502">"Introduza novamente o código PUK correto. Muitas tentativas malsucedidas desativarão permanentemente o SIM."</string>
+ <string name="kg_invalid_puk" msgid="5399287873762592502">"Introduza novamente o código PUK correto. Muitas tentativas malsucedidas desativarão permanentemente o chip."</string>
<string name="kg_invalid_confirm_pin_hint" product="default" msgid="5672736555427444330">"Os códigos PIN não coincidem"</string>
<string name="kg_login_too_many_attempts" msgid="6604574268387867255">"Muitas tentativas de padrão"</string>
<string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8637788033282252027">"Você digitou seu PIN incorretamente <xliff:g id="NUMBER_0">%1$d</xliff:g> vezes. \n\nTente novamente em <xliff:g id="NUMBER_1">%2$d</xliff:g> segundos."</string>
@@ -101,18 +101,18 @@
<string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="8476407539834855">"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="956706236554092172">"Você desenhou sua sequência 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 o login do Google para desbloquear seu 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="8364140853305528449">"Você desenhou sua sequência 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 o login do Google para desbloquear.\n\n Tente novamente em <xliff:g id="NUMBER_2">%3$d</xliff:g> segundos."</string>
- <string name="kg_password_wrong_pin_code_pukked" msgid="3389829202093674267">"Código PIN do SIM incorreto. Entre em contato com a operadora para desbloquear o dispositivo."</string>
+ <string name="kg_password_wrong_pin_code_pukked" msgid="3389829202093674267">"Código PIN do chip incorreto. Entre em contato com a operadora para desbloquear o dispositivo."</string>
<plurals name="kg_password_wrong_pin_code" formatted="false" msgid="4314341367727055967">
- <item quantity="one">Código PIN do SIM incorreto. Tentativas restantes: <xliff:g id="NUMBER_1">%d</xliff:g>.</item>
- <item quantity="other">Código PIN do SIM incorreto. Tentativas restantes: <xliff:g id="NUMBER_1">%d</xliff:g>.</item>
+ <item quantity="one">Código PIN do chip incorreto. Tentativas restantes: <xliff:g id="NUMBER_1">%d</xliff:g>.</item>
+ <item quantity="other">Código PIN do chip incorreto. Tentativas restantes: <xliff:g id="NUMBER_1">%d</xliff:g>.</item>
</plurals>
- <string name="kg_password_wrong_puk_code_dead" msgid="3329017604125179374">"O SIM está inutilizável. Entre em contato com a operadora."</string>
+ <string name="kg_password_wrong_puk_code_dead" msgid="3329017604125179374">"O chip não pode ser utilizado. Entre em contato com a operadora."</string>
<plurals name="kg_password_wrong_puk_code" formatted="false" msgid="2287504898931957513">
- <item quantity="one">Código PUK do SIM incorreto. Tentativas restantes: <xliff:g id="NUMBER_1">%d</xliff:g>. Caso o código correto não seja digitado, o SIM se tornará permanentemente inutilizável.</item>
- <item quantity="other">Código PUK do SIM incorreto. Tentativas restantes: <xliff:g id="NUMBER_1">%d</xliff:g>. Caso o código correto não seja digitado, o SIM se tornará permanentemente inutilizável.</item>
+ <item quantity="one">Código PUK do chip incorreto. Tentativas restantes: <xliff:g id="NUMBER_1">%d</xliff:g>. Caso o código correto não seja digitado, o chip se tornará permanentemente inutilizável.</item>
+ <item quantity="other">Código PUK do chip incorreto. Tentativas restantes: <xliff:g id="NUMBER_1">%d</xliff:g>. Caso o código correto não seja digitado, o chip se tornará permanentemente inutilizável.</item>
</plurals>
- <string name="kg_password_pin_failed" msgid="8769990811451236223">"Falha na operação de PIN do SIM."</string>
- <string name="kg_password_puk_failed" msgid="1331621440873439974">"Falha na operação de PUK do SIM."</string>
+ <string name="kg_password_pin_failed" msgid="8769990811451236223">"Falha na operação de PIN do chip."</string>
+ <string name="kg_password_puk_failed" msgid="1331621440873439974">"Falha na operação de PUK do chip."</string>
<string name="kg_pin_accepted" msgid="7637293533973802143">"Código aceito."</string>
<string name="keyguard_carrier_default" msgid="4274828292998453695">"Sem serviço."</string>
<string name="accessibility_ime_switch_button" msgid="2695096475319405612">"Alterar o método de entrada"</string>
@@ -143,11 +143,11 @@
<string name="kg_fingerprint_not_recognized" msgid="7854413849848459418">"Não reconhecido"</string>
<string name="kg_face_not_recognized" msgid="6382535088345875294">"Não reconhecido"</string>
<plurals name="kg_password_default_pin_message" formatted="false" msgid="3739658416797652781">
- <item quantity="one">Informe o PIN do SIM. Você tem <xliff:g id="NUMBER_1">%d</xliff:g> tentativa restante.</item>
- <item quantity="other">Informe o PIN do SIM. Você tem <xliff:g id="NUMBER_1">%d</xliff:g> tentativas restantes.</item>
+ <item quantity="one">Informe o PIN do chip. Você tem <xliff:g id="NUMBER_1">%d</xliff:g> tentativa restante.</item>
+ <item quantity="other">Informe o PIN do chip. Você tem <xliff:g id="NUMBER_1">%d</xliff:g> tentativas restantes.</item>
</plurals>
<plurals name="kg_password_default_puk_message" formatted="false" msgid="8744416410184198352">
- <item quantity="one">O SIM agora está desativado. Informe o código PUK para continuar. Você tem <xliff:g id="_NUMBER_1">%d</xliff:g> tentativa restante antes de o SIM se tornar permanentemente inutilizável. Entre em contato com a operadora para saber mais detalhes.</item>
- <item quantity="other">O SIM agora está desativado. Informe o código PUK para continuar. Você tem <xliff:g id="_NUMBER_1">%d</xliff:g> tentativas restantes antes de o SIM se tornar permanentemente inutilizável. Entre em contato com a operadora para saber mais detalhes.</item>
+ <item quantity="one">O chip agora está desativado. Informe o código PUK para continuar. Você tem <xliff:g id="_NUMBER_1">%d</xliff:g> tentativa restante antes de o chip se tornar permanentemente inutilizável. Entre em contato com a operadora para saber mais detalhes.</item>
+ <item quantity="other">O chip agora está desativado. Informe o código PUK para continuar. Você tem <xliff:g id="_NUMBER_1">%d</xliff:g> tentativas restantes antes de o chip se tornar permanentemente inutilizável. Entre em contato com a operadora para saber mais detalhes.</item>
</plurals>
</resources>
diff --git a/packages/SystemUI/res/layout/notification_info.xml b/packages/SystemUI/res/layout/notification_info.xml
index e1e812bef258..7a38899f37f7 100644
--- a/packages/SystemUI/res/layout/notification_info.xml
+++ b/packages/SystemUI/res/layout/notification_info.xml
@@ -154,6 +154,7 @@
style="@style/TextAppearance.NotificationInfo.Button" />
<TextView
android:id="@+id/keep"
+ android:minWidth="48dp"
android:text="@string/inline_keep_button"
android:layout_width="wrap_content"
android:layout_height="match_parent"
diff --git a/packages/SystemUI/res/values-af/strings.xml b/packages/SystemUI/res/values-af/strings.xml
index 6bfd9b2f8470..44691c2b0730 100644
--- a/packages/SystemUI/res/values-af/strings.xml
+++ b/packages/SystemUI/res/values-af/strings.xml
@@ -426,9 +426,11 @@
<string name="user_logout_notification_action" msgid="1195428991423425062">"MELD GEBRUIKER AF"</string>
<string name="user_add_user_title" msgid="4553596395824132638">"Voeg nuwe gebruiker by?"</string>
<string name="user_add_user_message_short" msgid="2161624834066214559">"Wanneer jy \'n nuwe gebruiker byvoeg, moet daardie persoon hul spasie opstel.\n\nEnige gebruiker kan programme vir al die ander gebruikers opdateer."</string>
- <!-- no translation found for user_limit_reached_title (7374910700117359177) -->
- <skip />
- <!-- no translation found for user_limit_reached_message (1855040563671964242) -->
+ <string name="user_limit_reached_title" msgid="7374910700117359177">"Gebruikerlimiet is bereik"</string>
+ <plurals name="user_limit_reached_message" formatted="false" msgid="1855040563671964242">
+ <item quantity="other">Jy kan tot <xliff:g id="COUNT">%d</xliff:g> gebruikers byvoeg.</item>
+ <item quantity="one">Net een gebruiker kan geskep word.</item>
+ </plurals>
<string name="user_remove_user_title" msgid="4681256956076895559">"Verwyder gebruiker?"</string>
<string name="user_remove_user_message" msgid="1453218013959498039">"Alle programme en data van hierdie gebruiker sal uitgevee word."</string>
<string name="user_remove_user_remove" msgid="7479275741742178297">"Verwyder"</string>
@@ -732,8 +734,7 @@
<string name="left_icon" msgid="3096287125959387541">"Links-ikoon"</string>
<string name="right_icon" msgid="3952104823293824311">"Regs-ikoon"</string>
<string name="drag_to_add_tiles" msgid="230586591689084925">"Hou en sleep om teëls by te voeg"</string>
- <!-- no translation found for drag_to_rearrange_tiles (4566074720193667473) -->
- <skip />
+ <string name="drag_to_rearrange_tiles" msgid="4566074720193667473">"Hou en sleep om teëls te herrangskik"</string>
<string name="drag_to_remove_tiles" msgid="3361212377437088062">"Sleep hierheen om te verwyder"</string>
<string name="drag_to_remove_disabled" msgid="2390968976638993382">"Jy moet minstens 6 teëls hê"</string>
<string name="qs_edit" msgid="2232596095725105230">"Wysig"</string>
diff --git a/packages/SystemUI/res/values-am/strings.xml b/packages/SystemUI/res/values-am/strings.xml
index 43a27f0b2919..966e4d7f7536 100644
--- a/packages/SystemUI/res/values-am/strings.xml
+++ b/packages/SystemUI/res/values-am/strings.xml
@@ -426,9 +426,11 @@
<string name="user_logout_notification_action" msgid="1195428991423425062">"ተጠቃሚን አስወጣ"</string>
<string name="user_add_user_title" msgid="4553596395824132638">"አዲስ ተጠቃሚ ይታከል?"</string>
<string name="user_add_user_message_short" msgid="2161624834066214559">"እርስዎ አንድ አዲስ ተጠቃሚ ሲያክሉ ያ ሰው የራሱ ቦታ ማዘጋጀት አለበት።\n\nማንኛውም ተጠቃሚ መተግበሪያዎችን ለሌሎች ተጠቃሚዎች ሁሉ ሊያዘምን ይችላል።"</string>
- <!-- no translation found for user_limit_reached_title (7374910700117359177) -->
- <skip />
- <!-- no translation found for user_limit_reached_message (1855040563671964242) -->
+ <string name="user_limit_reached_title" msgid="7374910700117359177">"የተጠቃሚ ገደብ ላይ ተደርሷል"</string>
+ <plurals name="user_limit_reached_message" formatted="false" msgid="1855040563671964242">
+ <item quantity="one"><xliff:g id="COUNT">%d</xliff:g> ተጠቃሚዎች ብቻ ናቸው ሊፈጠሩ የሚችሉት።</item>
+ <item quantity="other"><xliff:g id="COUNT">%d</xliff:g> ተጠቃሚዎች ብቻ ናቸው ሊፈጠሩ የሚችሉት።</item>
+ </plurals>
<string name="user_remove_user_title" msgid="4681256956076895559">"ተጠቃሚ ይወገድ?"</string>
<string name="user_remove_user_message" msgid="1453218013959498039">"ሁሉም የዚህ ተጠቃሚ መተግበሪያዎች እና ውሂብ ይሰረዛሉ።"</string>
<string name="user_remove_user_remove" msgid="7479275741742178297">"አስወግድ"</string>
@@ -732,8 +734,7 @@
<string name="left_icon" msgid="3096287125959387541">"የግራ አዶ"</string>
<string name="right_icon" msgid="3952104823293824311">"የቀኝ አዶ"</string>
<string name="drag_to_add_tiles" msgid="230586591689084925">"ፋይሎችን ለማከል ይዘት ይጎትቱ"</string>
- <!-- no translation found for drag_to_rearrange_tiles (4566074720193667473) -->
- <skip />
+ <string name="drag_to_rearrange_tiles" msgid="4566074720193667473">"ሰድሮችን ዳግም ለማስተካከል ይያዙ እና ይጎትቱ።"</string>
<string name="drag_to_remove_tiles" msgid="3361212377437088062">"ለማስወገድ ወደዚህ ይጎትቱ"</string>
<string name="drag_to_remove_disabled" msgid="2390968976638993382">"ቢያንስ 6 ሰቆች ያስፈልገዎታል"</string>
<string name="qs_edit" msgid="2232596095725105230">"አርትዕ"</string>
diff --git a/packages/SystemUI/res/values-ar/strings.xml b/packages/SystemUI/res/values-ar/strings.xml
index 598d822295e6..278b00a50740 100644
--- a/packages/SystemUI/res/values-ar/strings.xml
+++ b/packages/SystemUI/res/values-ar/strings.xml
@@ -438,9 +438,15 @@
<string name="user_logout_notification_action" msgid="1195428991423425062">"خروج المستخدم"</string>
<string name="user_add_user_title" msgid="4553596395824132638">"هل تريد إضافة مستخدم جديد؟"</string>
<string name="user_add_user_message_short" msgid="2161624834066214559">"عند إضافة مستخدم جديد، عليه إعداد مساحته.\n\nويُمكن لأي مستخدم تحديث التطبيقات لجميع المستخدمين الآخرين."</string>
- <!-- no translation found for user_limit_reached_title (7374910700117359177) -->
- <skip />
- <!-- no translation found for user_limit_reached_message (1855040563671964242) -->
+ <string name="user_limit_reached_title" msgid="7374910700117359177">"تم الوصول إلى أقصى عدد للمستخدمين"</string>
+ <plurals name="user_limit_reached_message" formatted="false" msgid="1855040563671964242">
+ <item quantity="zero">يمكنك إضافة ما يصل إلى <xliff:g id="COUNT">%d</xliff:g> مستخدم.</item>
+ <item quantity="two">يمكنك إضافة ما يصل إلى مستخدمينِ (<xliff:g id="COUNT">%d</xliff:g>).</item>
+ <item quantity="few">يمكنك إضافة ما يصل إلى <xliff:g id="COUNT">%d</xliff:g> مستخدمين.</item>
+ <item quantity="many">يمكنك إضافة ما يصل إلى <xliff:g id="COUNT">%d</xliff:g> مستخدمًا.</item>
+ <item quantity="other">يمكنك إضافة ما يصل إلى <xliff:g id="COUNT">%d</xliff:g> مستخدم.</item>
+ <item quantity="one">يمكن إنشاء مستخدم واحد فقط.</item>
+ </plurals>
<string name="user_remove_user_title" msgid="4681256956076895559">"هل تريد إزالة المستخدم؟"</string>
<string name="user_remove_user_message" msgid="1453218013959498039">"سيتم حذف جميع تطبيقات وبيانات هذا المستخدم."</string>
<string name="user_remove_user_remove" msgid="7479275741742178297">"إزالة"</string>
@@ -752,8 +758,7 @@
<string name="left_icon" msgid="3096287125959387541">"رمز اليسار"</string>
<string name="right_icon" msgid="3952104823293824311">"رمز اليمين"</string>
<string name="drag_to_add_tiles" msgid="230586591689084925">"انقر باستمرار مع السحب لإضافة المربعات."</string>
- <!-- no translation found for drag_to_rearrange_tiles (4566074720193667473) -->
- <skip />
+ <string name="drag_to_rearrange_tiles" msgid="4566074720193667473">"اضغط باستمرار مع السحب لإعادة ترتيب المربّعات."</string>
<string name="drag_to_remove_tiles" msgid="3361212377437088062">"اسحب هنا للإزالة"</string>
<string name="drag_to_remove_disabled" msgid="2390968976638993382">"تحتاج إلى 6 مربعات على الأقل."</string>
<string name="qs_edit" msgid="2232596095725105230">"تعديل"</string>
diff --git a/packages/SystemUI/res/values-as/strings.xml b/packages/SystemUI/res/values-as/strings.xml
index 84d178b583eb..8912f158dc90 100644
--- a/packages/SystemUI/res/values-as/strings.xml
+++ b/packages/SystemUI/res/values-as/strings.xml
@@ -426,9 +426,11 @@
<string name="user_logout_notification_action" msgid="1195428991423425062">"ব্যৱহাৰকাৰীক লগ আউট কৰক"</string>
<string name="user_add_user_title" msgid="4553596395824132638">"নতুন ব্যৱহাৰকাৰী যোগ কৰিবনে?"</string>
<string name="user_add_user_message_short" msgid="2161624834066214559">"আপুনি যেতিয়া এজন নতুন ব্যৱহাৰকাৰী যোগ কৰে, তেওঁ নিজৰ স্থান ছেট আপ কৰা প্ৰয়োজন।\n\nযিকোনো ব্যৱহাৰকাৰীয়ে নিজৰ লগতে আন ব্যৱহাৰকাৰীৰো এপ্ আপডেট কৰিব পাৰে।"</string>
- <!-- no translation found for user_limit_reached_title (7374910700117359177) -->
- <skip />
- <!-- no translation found for user_limit_reached_message (1855040563671964242) -->
+ <string name="user_limit_reached_title" msgid="7374910700117359177">"অধিকতম ব্যৱহাৰকাৰী সৃষ্টি কৰা হ’ল"</string>
+ <plurals name="user_limit_reached_message" formatted="false" msgid="1855040563671964242">
+ <item quantity="one">আপুনি <xliff:g id="COUNT">%d</xliff:g> জনলৈকে ব্যৱহাৰকাৰী যোগ কৰিব পাৰে।</item>
+ <item quantity="other">আপুনি <xliff:g id="COUNT">%d</xliff:g> জনলৈকে ব্যৱহাৰকাৰী যোগ কৰিব পাৰে।</item>
+ </plurals>
<string name="user_remove_user_title" msgid="4681256956076895559">"ব্যৱহাৰকাৰীক আঁতৰাবনে?"</string>
<string name="user_remove_user_message" msgid="1453218013959498039">"এই ব্যৱহাৰকাৰীৰ সকলো এপ্ আৰু ডেটা মচা হ\'ব।"</string>
<string name="user_remove_user_remove" msgid="7479275741742178297">"আঁতৰাওক"</string>
@@ -732,8 +734,7 @@
<string name="left_icon" msgid="3096287125959387541">"বাওঁ আইকন"</string>
<string name="right_icon" msgid="3952104823293824311">"সোঁ আইকন"</string>
<string name="drag_to_add_tiles" msgid="230586591689084925">"টাইল যোগ কৰিবলৈ হেঁচি ধৰি টানি আনক"</string>
- <!-- no translation found for drag_to_rearrange_tiles (4566074720193667473) -->
- <skip />
+ <string name="drag_to_rearrange_tiles" msgid="4566074720193667473">"টাইলসমূহ পুনৰ সজাবলৈ ধৰি টানক"</string>
<string name="drag_to_remove_tiles" msgid="3361212377437088062">"আঁতৰাবৰ বাবে টানি আনি ইয়াত এৰি দিয়ক"</string>
<string name="drag_to_remove_disabled" msgid="2390968976638993382">"আপোনাক অতি কমেও ৬খন টাইল লাগিব"</string>
<string name="qs_edit" msgid="2232596095725105230">"সম্পাদনা কৰক"</string>
diff --git a/packages/SystemUI/res/values-az/strings.xml b/packages/SystemUI/res/values-az/strings.xml
index bbc67a5279c4..f0779fb550f0 100644
--- a/packages/SystemUI/res/values-az/strings.xml
+++ b/packages/SystemUI/res/values-az/strings.xml
@@ -209,7 +209,7 @@
<string name="accessibility_quick_settings_airplane_changed_off" msgid="66846307818850664">"Təyyarə rejimi deaktiv edildi."</string>
<string name="accessibility_quick_settings_airplane_changed_on" msgid="8983005603505087728">"Təyyarə rejimi aktiv edildi."</string>
<string name="accessibility_quick_settings_dnd_none_on" msgid="2960643943620637020">"tam sakitlik"</string>
- <string name="accessibility_quick_settings_dnd_alarms_on" msgid="3357131899365865386">"yalnız siqnallar"</string>
+ <string name="accessibility_quick_settings_dnd_alarms_on" msgid="3357131899365865386">"yalnız alarmlar"</string>
<string name="accessibility_quick_settings_dnd" msgid="6607873236717185815">"Narahat etməyin."</string>
<string name="accessibility_quick_settings_dnd_changed_off" msgid="898107593453022935">"\"Narahat etməyin\" qeyri-aktivdir."</string>
<string name="accessibility_quick_settings_dnd_changed_on" msgid="4483780856613561039">"\"Narahat etməyin\" aktivdir."</string>
@@ -426,9 +426,11 @@
<string name="user_logout_notification_action" msgid="1195428991423425062">"İSTİFADƏÇİ ÇIXIŞI"</string>
<string name="user_add_user_title" msgid="4553596395824132638">"Yeni istifadəçi əlavə edilsin?"</string>
<string name="user_add_user_message_short" msgid="2161624834066214559">"Yeni istifadəçi əlavə etdiyiniz zaman həmin şəxs öz yerini quraşdırmalıdır. \n\n İstənilən istifadəçi bütün digər istifadəçilərdən olan tətbiqləri güncəlləşdirə bilər."</string>
- <!-- no translation found for user_limit_reached_title (7374910700117359177) -->
- <skip />
- <!-- no translation found for user_limit_reached_message (1855040563671964242) -->
+ <string name="user_limit_reached_title" msgid="7374910700117359177">"İstifadəçi limitinə çatmısınız"</string>
+ <plurals name="user_limit_reached_message" formatted="false" msgid="1855040563671964242">
+ <item quantity="other">Maksimum <xliff:g id="COUNT">%d</xliff:g> istifadəçi əlavə edə bilərsiniz.</item>
+ <item quantity="one">Yalnız bir istifadəçi yaradıla bilər.</item>
+ </plurals>
<string name="user_remove_user_title" msgid="4681256956076895559">"İstifadəçi silinsin?"</string>
<string name="user_remove_user_message" msgid="1453218013959498039">"Bu istifadəçinin bütün tətbiqləri və datası silinəcək."</string>
<string name="user_remove_user_remove" msgid="7479275741742178297">"Silin"</string>
@@ -732,8 +734,7 @@
<string name="left_icon" msgid="3096287125959387541">"Sol ikona"</string>
<string name="right_icon" msgid="3952104823293824311">"Sağ ikona"</string>
<string name="drag_to_add_tiles" msgid="230586591689084925">"Mozaika əlavə etmək üçün basıb saxlayaraq çəkin"</string>
- <!-- no translation found for drag_to_rearrange_tiles (4566074720193667473) -->
- <skip />
+ <string name="drag_to_rearrange_tiles" msgid="4566074720193667473">"Mozaikaları yenidən təşkil etmək üçün basıb saxlayın və çəkin"</string>
<string name="drag_to_remove_tiles" msgid="3361212377437088062">"Silmək üçün bura sürüşdürün"</string>
<string name="drag_to_remove_disabled" msgid="2390968976638993382">"Minimum 6 mozaikaya ehtiyacınız var"</string>
<string name="qs_edit" msgid="2232596095725105230">"Redaktə edin"</string>
diff --git a/packages/SystemUI/res/values-b+sr+Latn/strings.xml b/packages/SystemUI/res/values-b+sr+Latn/strings.xml
index 679fdde85eeb..9dc6460ca9e4 100644
--- a/packages/SystemUI/res/values-b+sr+Latn/strings.xml
+++ b/packages/SystemUI/res/values-b+sr+Latn/strings.xml
@@ -429,9 +429,12 @@
<string name="user_logout_notification_action" msgid="1195428991423425062">"ODJAVI KORISNIKA"</string>
<string name="user_add_user_title" msgid="4553596395824132638">"Dodajete novog korisnika?"</string>
<string name="user_add_user_message_short" msgid="2161624834066214559">"Kada dodate novog korisnika, ta osoba treba da podesi svoj prostor.\n\nSvaki korisnik može da ažurira aplikacije za sve ostale korisnike."</string>
- <!-- no translation found for user_limit_reached_title (7374910700117359177) -->
- <skip />
- <!-- no translation found for user_limit_reached_message (1855040563671964242) -->
+ <string name="user_limit_reached_title" msgid="7374910700117359177">"Dostignut maksimalni broj korisnika"</string>
+ <plurals name="user_limit_reached_message" formatted="false" msgid="1855040563671964242">
+ <item quantity="one">Možete da dodate najviše <xliff:g id="COUNT">%d</xliff:g> korisnika.</item>
+ <item quantity="few">Možete da dodate najviše <xliff:g id="COUNT">%d</xliff:g> korisnika.</item>
+ <item quantity="other">Možete da dodate najviše <xliff:g id="COUNT">%d</xliff:g> korisnika.</item>
+ </plurals>
<string name="user_remove_user_title" msgid="4681256956076895559">"Želite li da uklonite korisnika?"</string>
<string name="user_remove_user_message" msgid="1453218013959498039">"Sve aplikacije i podaci ovog korisnika će biti izbrisani."</string>
<string name="user_remove_user_remove" msgid="7479275741742178297">"Ukloni"</string>
@@ -737,8 +740,7 @@
<string name="left_icon" msgid="3096287125959387541">"Leva ikona"</string>
<string name="right_icon" msgid="3952104823293824311">"Desna ikona"</string>
<string name="drag_to_add_tiles" msgid="230586591689084925">"Zadržite i prevucite da biste dodali pločice"</string>
- <!-- no translation found for drag_to_rearrange_tiles (4566074720193667473) -->
- <skip />
+ <string name="drag_to_rearrange_tiles" msgid="4566074720193667473">"Zadržite i prevucite da biste promenili raspored pločica"</string>
<string name="drag_to_remove_tiles" msgid="3361212377437088062">"Prevucite ovde da biste uklonili"</string>
<string name="drag_to_remove_disabled" msgid="2390968976638993382">"Treba da izaberete najmanje 6 pločica"</string>
<string name="qs_edit" msgid="2232596095725105230">"Izmeni"</string>
diff --git a/packages/SystemUI/res/values-be/strings.xml b/packages/SystemUI/res/values-be/strings.xml
index d26b322b62d6..9898dbd50548 100644
--- a/packages/SystemUI/res/values-be/strings.xml
+++ b/packages/SystemUI/res/values-be/strings.xml
@@ -434,9 +434,13 @@
<string name="user_logout_notification_action" msgid="1195428991423425062">"ВЫКАНАЦЬ ВЫХАД КАРЫСТАЛЬНІКА"</string>
<string name="user_add_user_title" msgid="4553596395824132638">"Дадаць новага карыстальніка?"</string>
<string name="user_add_user_message_short" msgid="2161624834066214559">"Пасля стварэння профіля яго трэба наладзіць.\n\nЛюбы карыстальнік прылады можа абнаўляць праграмы ўсіх іншых карыстальнікаў."</string>
- <!-- no translation found for user_limit_reached_title (7374910700117359177) -->
- <skip />
- <!-- no translation found for user_limit_reached_message (1855040563671964242) -->
+ <string name="user_limit_reached_title" msgid="7374910700117359177">"Дасягнуты ліміт карыстальнікаў"</string>
+ <plurals name="user_limit_reached_message" formatted="false" msgid="1855040563671964242">
+ <item quantity="one">Можна дадаць <xliff:g id="COUNT">%d</xliff:g> карыстальніка.</item>
+ <item quantity="few">Можна дадаць <xliff:g id="COUNT">%d</xliff:g> карыстальнікаў.</item>
+ <item quantity="many">Можна дадаць <xliff:g id="COUNT">%d</xliff:g> карыстальнікаў.</item>
+ <item quantity="other">Можна дадаць <xliff:g id="COUNT">%d</xliff:g> карыстальніка.</item>
+ </plurals>
<string name="user_remove_user_title" msgid="4681256956076895559">"Выдаліць карыстальніка?"</string>
<string name="user_remove_user_message" msgid="1453218013959498039">"Усе праграмы і даныя гэтага карыстальніка будуць выдалены."</string>
<string name="user_remove_user_remove" msgid="7479275741742178297">"Выдаліць"</string>
@@ -744,8 +748,7 @@
<string name="left_icon" msgid="3096287125959387541">"Значок \"улева\""</string>
<string name="right_icon" msgid="3952104823293824311">"Значок \"управа\""</string>
<string name="drag_to_add_tiles" msgid="230586591689084925">"Перацягніце патрэбныя пліткі"</string>
- <!-- no translation found for drag_to_rearrange_tiles (4566074720193667473) -->
- <skip />
+ <string name="drag_to_rearrange_tiles" msgid="4566074720193667473">"Каб змяніць парадак плітак, утрымлівайце і перацягвайце іх"</string>
<string name="drag_to_remove_tiles" msgid="3361212377437088062">"Перацягніце сюды, каб выдаліць"</string>
<string name="drag_to_remove_disabled" msgid="2390968976638993382">"Трэба па меншай меры 6 плітак"</string>
<string name="qs_edit" msgid="2232596095725105230">"Рэдагаваць"</string>
diff --git a/packages/SystemUI/res/values-bg/strings.xml b/packages/SystemUI/res/values-bg/strings.xml
index 2bd6cc4d1166..a5506a38aec3 100644
--- a/packages/SystemUI/res/values-bg/strings.xml
+++ b/packages/SystemUI/res/values-bg/strings.xml
@@ -426,9 +426,11 @@
<string name="user_logout_notification_action" msgid="1195428991423425062">"ИЗЛИЗАНЕ НА ПОТРЕБИТЕЛЯ"</string>
<string name="user_add_user_title" msgid="4553596395824132638">"Да се добави ли нов потреб.?"</string>
<string name="user_add_user_message_short" msgid="2161624834066214559">"Когато добавите нов потребител, той трябва да настрои работното си пространство.\n\nВсеки потребител може да актуализира приложенията за всички останали потребители."</string>
- <!-- no translation found for user_limit_reached_title (7374910700117359177) -->
- <skip />
- <!-- no translation found for user_limit_reached_message (1855040563671964242) -->
+ <string name="user_limit_reached_title" msgid="7374910700117359177">"Достигнахте огранич. за потребители"</string>
+ <plurals name="user_limit_reached_message" formatted="false" msgid="1855040563671964242">
+ <item quantity="other">Можете да добавите до <xliff:g id="COUNT">%d</xliff:g> потребители.</item>
+ <item quantity="one">Може да бъде създаден само един потребител.</item>
+ </plurals>
<string name="user_remove_user_title" msgid="4681256956076895559">"Да се премахне ли потребителят?"</string>
<string name="user_remove_user_message" msgid="1453218013959498039">"Всички приложения и данни на този потребител ще бъдат изтрити."</string>
<string name="user_remove_user_remove" msgid="7479275741742178297">"Премахване"</string>
@@ -732,8 +734,7 @@
<string name="left_icon" msgid="3096287125959387541">"Лява икона"</string>
<string name="right_icon" msgid="3952104823293824311">"Дясна икона"</string>
<string name="drag_to_add_tiles" msgid="230586591689084925">"Задръжте и плъзнете, за да добавите плочки"</string>
- <!-- no translation found for drag_to_rearrange_tiles (4566074720193667473) -->
- <skip />
+ <string name="drag_to_rearrange_tiles" msgid="4566074720193667473">"Задръжте и плъзнете, за да пренаредите плочките"</string>
<string name="drag_to_remove_tiles" msgid="3361212377437088062">"Преместете тук с плъзгане за премахване"</string>
<string name="drag_to_remove_disabled" msgid="2390968976638993382">"Трябва да останат поне 6 плочки"</string>
<string name="qs_edit" msgid="2232596095725105230">"Редактиране"</string>
diff --git a/packages/SystemUI/res/values-bn/strings.xml b/packages/SystemUI/res/values-bn/strings.xml
index 866deaec7562..5d52103e50b6 100644
--- a/packages/SystemUI/res/values-bn/strings.xml
+++ b/packages/SystemUI/res/values-bn/strings.xml
@@ -426,9 +426,11 @@
<string name="user_logout_notification_action" msgid="1195428991423425062">"ব্যবহারকারীকে লগ-আউট করুন"</string>
<string name="user_add_user_title" msgid="4553596395824132638">"নতুন ব্যবহারকারীকে যোগ করবেন?"</string>
<string name="user_add_user_message_short" msgid="2161624834066214559">"আপনি একজন নতুন ব্যবহারকারী যোগ করলে তাকে তার জায়গা সেট আপ করে নিতে হবে৷\n\nযেকোনো ব্যবহারকারী অন্য সব ব্যবহারকারীর জন্য অ্যাপ্লিকেশান আপডেট করতে পারবেন৷"</string>
- <!-- no translation found for user_limit_reached_title (7374910700117359177) -->
- <skip />
- <!-- no translation found for user_limit_reached_message (1855040563671964242) -->
+ <string name="user_limit_reached_title" msgid="7374910700117359177">"আর কোনও প্রোফাইল যোগ করা যাবে না"</string>
+ <plurals name="user_limit_reached_message" formatted="false" msgid="1855040563671964242">
+ <item quantity="one">আপনি <xliff:g id="COUNT">%d</xliff:g> জন পর্যন্ত ব্যবহারকারীর প্রোফাইল যোগ করতে পারেন।</item>
+ <item quantity="other">আপনি <xliff:g id="COUNT">%d</xliff:g> জন পর্যন্ত ব্যবহারকারীর প্রোফাইল যোগ করতে পারেন।</item>
+ </plurals>
<string name="user_remove_user_title" msgid="4681256956076895559">"ব্যবহারকারী সরাবেন?"</string>
<string name="user_remove_user_message" msgid="1453218013959498039">"এই ব্যবহারকারীর সমস্ত অ্যাপ্লিকেশান ও ডেটা মুছে ফেলা হবে।"</string>
<string name="user_remove_user_remove" msgid="7479275741742178297">"সরান"</string>
@@ -732,8 +734,7 @@
<string name="left_icon" msgid="3096287125959387541">"বাঁ দিকের আইকন"</string>
<string name="right_icon" msgid="3952104823293824311">"ডানদিকের আইকন"</string>
<string name="drag_to_add_tiles" msgid="230586591689084925">"টাইল যোগ করতে ট্যাপ করে টেনে আনুন"</string>
- <!-- no translation found for drag_to_rearrange_tiles (4566074720193667473) -->
- <skip />
+ <string name="drag_to_rearrange_tiles" msgid="4566074720193667473">"টাইলগুলি আবার সাজানোর জন্য ধরে থেকে টেনে আনুন"</string>
<string name="drag_to_remove_tiles" msgid="3361212377437088062">"সরানোর জন্য এখানে টেনে আনুন"</string>
<string name="drag_to_remove_disabled" msgid="2390968976638993382">"অন্তত ৬টি টাইল রাখতে হবে"</string>
<string name="qs_edit" msgid="2232596095725105230">"সম্পাদনা করুন"</string>
diff --git a/packages/SystemUI/res/values-bs/strings.xml b/packages/SystemUI/res/values-bs/strings.xml
index 57089b821045..4527e9a9d26c 100644
--- a/packages/SystemUI/res/values-bs/strings.xml
+++ b/packages/SystemUI/res/values-bs/strings.xml
@@ -429,9 +429,12 @@
<string name="user_logout_notification_action" msgid="1195428991423425062">"ODJAVI KORISNIKA"</string>
<string name="user_add_user_title" msgid="4553596395824132638">"Želite dodati novog korisnika?"</string>
<string name="user_add_user_message_short" msgid="2161624834066214559">"Kada dodate novog korisnika, ta osoba treba uspostaviti svoj prostor.\n\nSvaki korisnik može ažurirati aplikacije za sve ostale korisnike."</string>
- <!-- no translation found for user_limit_reached_title (7374910700117359177) -->
- <skip />
- <!-- no translation found for user_limit_reached_message (1855040563671964242) -->
+ <string name="user_limit_reached_title" msgid="7374910700117359177">"Dostignut limit za broj korisnika"</string>
+ <plurals name="user_limit_reached_message" formatted="false" msgid="1855040563671964242">
+ <item quantity="one">Možete dodati najviše <xliff:g id="COUNT">%d</xliff:g> korisnika.</item>
+ <item quantity="few">Možete dodati najviše <xliff:g id="COUNT">%d</xliff:g> korisnika.</item>
+ <item quantity="other">Možete dodati najviše <xliff:g id="COUNT">%d</xliff:g> korisnika.</item>
+ </plurals>
<string name="user_remove_user_title" msgid="4681256956076895559">"Zaista želite ukloniti korisnika?"</string>
<string name="user_remove_user_message" msgid="1453218013959498039">"Sve aplikacije i podaci ovog korisnika bit će izbrisani."</string>
<string name="user_remove_user_remove" msgid="7479275741742178297">"Ukloni"</string>
@@ -739,8 +742,7 @@
<string name="left_icon" msgid="3096287125959387541">"Ikona lijevo"</string>
<string name="right_icon" msgid="3952104823293824311">"Ikona desno"</string>
<string name="drag_to_add_tiles" msgid="230586591689084925">"Držite i prevucite da dodate polja"</string>
- <!-- no translation found for drag_to_rearrange_tiles (4566074720193667473) -->
- <skip />
+ <string name="drag_to_rearrange_tiles" msgid="4566074720193667473">"Držite i prevucite da preuredite polja"</string>
<string name="drag_to_remove_tiles" msgid="3361212377437088062">"Prevucite ovdje za uklanjanje"</string>
<string name="drag_to_remove_disabled" msgid="2390968976638993382">"Trebate najmanje šest polja"</string>
<string name="qs_edit" msgid="2232596095725105230">"Uredi"</string>
@@ -851,7 +853,7 @@
<string name="touch_filtered_warning" msgid="8671693809204767551">"Postavke ne mogu potvrditi vaš odgovor jer aplikacija zaklanja zahtjev za odobrenje."</string>
<string name="slice_permission_title" msgid="7465009437851044444">"Dozvoliti aplikaciji <xliff:g id="APP_0">%1$s</xliff:g> prikazivanje isječaka aplikacije <xliff:g id="APP_2">%2$s</xliff:g>?"</string>
<string name="slice_permission_text_1" msgid="3514586565609596523">"- Može čitati informacije iz aplikacije <xliff:g id="APP">%1$s</xliff:g>"</string>
- <string name="slice_permission_text_2" msgid="3146758297471143723">"- Može poduzeti radnje unutar aplikacije <xliff:g id="APP">%1$s</xliff:g>"</string>
+ <string name="slice_permission_text_2" msgid="3146758297471143723">"- Može poduzeti radnje u aplikaciji <xliff:g id="APP">%1$s</xliff:g>"</string>
<string name="slice_permission_checkbox" msgid="7986504458640562900">"Dozvoli aplikaciji <xliff:g id="APP">%1$s</xliff:g> prikazivanje isječaka iz svake aplikacije"</string>
<string name="slice_permission_allow" msgid="2340244901366722709">"Dozvoli"</string>
<string name="slice_permission_deny" msgid="7683681514008048807">"Odbij"</string>
diff --git a/packages/SystemUI/res/values-ca/strings.xml b/packages/SystemUI/res/values-ca/strings.xml
index 920db25d8378..23754eabba9b 100644
--- a/packages/SystemUI/res/values-ca/strings.xml
+++ b/packages/SystemUI/res/values-ca/strings.xml
@@ -426,9 +426,11 @@
<string name="user_logout_notification_action" msgid="1195428991423425062">"TANCA LA SESSIÓ DE L\'USUARI"</string>
<string name="user_add_user_title" msgid="4553596395824132638">"Vols afegir un usuari nou?"</string>
<string name="user_add_user_message_short" msgid="2161624834066214559">"Quan s\'afegeix un usuari nou, aquest usuari ha de configurar-se l\'espai.\n\nQualsevol usuari pot actualitzar les aplicacions de la resta d\'usuaris."</string>
- <!-- no translation found for user_limit_reached_title (7374910700117359177) -->
- <skip />
- <!-- no translation found for user_limit_reached_message (1855040563671964242) -->
+ <string name="user_limit_reached_title" msgid="7374910700117359177">"S\'ha assolit el límit d\'usuaris"</string>
+ <plurals name="user_limit_reached_message" formatted="false" msgid="1855040563671964242">
+ <item quantity="other">Pots afegir fins a <xliff:g id="COUNT">%d</xliff:g> usuaris.</item>
+ <item quantity="one">Només es pot crear un usuari.</item>
+ </plurals>
<string name="user_remove_user_title" msgid="4681256956076895559">"Vols suprimir l\'usuari?"</string>
<string name="user_remove_user_message" msgid="1453218013959498039">"Totes les aplicacions i les dades d\'aquest usuari se suprimiran."</string>
<string name="user_remove_user_remove" msgid="7479275741742178297">"Suprimeix"</string>
@@ -732,8 +734,7 @@
<string name="left_icon" msgid="3096287125959387541">"Icona de l\'esquerra"</string>
<string name="right_icon" msgid="3952104823293824311">"Icona de la dreta"</string>
<string name="drag_to_add_tiles" msgid="230586591689084925">"Mantén premut i arrossega per afegir funcions"</string>
- <!-- no translation found for drag_to_rearrange_tiles (4566074720193667473) -->
- <skip />
+ <string name="drag_to_rearrange_tiles" msgid="4566074720193667473">"Mantén premut i arrossega per reorganitzar les funcions"</string>
<string name="drag_to_remove_tiles" msgid="3361212377437088062">"Arrossega aquí per suprimir una funció"</string>
<string name="drag_to_remove_disabled" msgid="2390968976638993382">"Necessites com a mínim 6 mosaics"</string>
<string name="qs_edit" msgid="2232596095725105230">"Edita"</string>
diff --git a/packages/SystemUI/res/values-cs/strings.xml b/packages/SystemUI/res/values-cs/strings.xml
index 4077908e3e47..e7583b52a75d 100644
--- a/packages/SystemUI/res/values-cs/strings.xml
+++ b/packages/SystemUI/res/values-cs/strings.xml
@@ -434,9 +434,13 @@
<string name="user_logout_notification_action" msgid="1195428991423425062">"ODHLÁSIT UŽIVATELE"</string>
<string name="user_add_user_title" msgid="4553596395824132638">"Přidat nového uživatele?"</string>
<string name="user_add_user_message_short" msgid="2161624834066214559">"Když přidáte nového uživatele, musí si nastavit vlastní prostor.\n\nJakýkoli uživatel může aktualizovat aplikace všech ostatních uživatelů."</string>
- <!-- no translation found for user_limit_reached_title (7374910700117359177) -->
- <skip />
- <!-- no translation found for user_limit_reached_message (1855040563671964242) -->
+ <string name="user_limit_reached_title" msgid="7374910700117359177">"Bylo dosaženo limitu uživatelů"</string>
+ <plurals name="user_limit_reached_message" formatted="false" msgid="1855040563671964242">
+ <item quantity="few">Lze přidat až <xliff:g id="COUNT">%d</xliff:g> uživatele.</item>
+ <item quantity="many">Lze přidat až <xliff:g id="COUNT">%d</xliff:g> uživatele.</item>
+ <item quantity="other">Lze přidat až <xliff:g id="COUNT">%d</xliff:g> uživatelů.</item>
+ <item quantity="one">Lze vytvořit jen jednoho uživatele.</item>
+ </plurals>
<string name="user_remove_user_title" msgid="4681256956076895559">"Odstranit uživatele?"</string>
<string name="user_remove_user_message" msgid="1453218013959498039">"Veškeré aplikace a data tohoto uživatele budou smazána."</string>
<string name="user_remove_user_remove" msgid="7479275741742178297">"Odstranit"</string>
@@ -744,8 +748,7 @@
<string name="left_icon" msgid="3096287125959387541">"Ikona vlevo"</string>
<string name="right_icon" msgid="3952104823293824311">"Ikona vpravo"</string>
<string name="drag_to_add_tiles" msgid="230586591689084925">"Dlaždice přidáte podržením a přetažením"</string>
- <!-- no translation found for drag_to_rearrange_tiles (4566074720193667473) -->
- <skip />
+ <string name="drag_to_rearrange_tiles" msgid="4566074720193667473">"Dlaždice můžete uspořádat podržením a přetažením"</string>
<string name="drag_to_remove_tiles" msgid="3361212377437088062">"Přetažením sem dlaždice odstraníte"</string>
<string name="drag_to_remove_disabled" msgid="2390968976638993382">"Potřebujete minimálně šest dlaždic"</string>
<string name="qs_edit" msgid="2232596095725105230">"Upravit"</string>
diff --git a/packages/SystemUI/res/values-da/strings.xml b/packages/SystemUI/res/values-da/strings.xml
index 2ebc0e8e2e82..31634a92a92c 100644
--- a/packages/SystemUI/res/values-da/strings.xml
+++ b/packages/SystemUI/res/values-da/strings.xml
@@ -426,9 +426,11 @@
<string name="user_logout_notification_action" msgid="1195428991423425062">"LOG BRUGEREN UD"</string>
<string name="user_add_user_title" msgid="4553596395824132638">"Vil du tilføje den nye bruger?"</string>
<string name="user_add_user_message_short" msgid="2161624834066214559">"Når du tilføjer en ny bruger, skal personen konfigurere sit område.\n\nEnhver bruger kan opdatere apps for alle andre brugere."</string>
- <!-- no translation found for user_limit_reached_title (7374910700117359177) -->
- <skip />
- <!-- no translation found for user_limit_reached_message (1855040563671964242) -->
+ <string name="user_limit_reached_title" msgid="7374910700117359177">"Grænsen for antal brugere er nået"</string>
+ <plurals name="user_limit_reached_message" formatted="false" msgid="1855040563671964242">
+ <item quantity="one">Du kan tilføje op til <xliff:g id="COUNT">%d</xliff:g> bruger.</item>
+ <item quantity="other">Du kan tilføje op til <xliff:g id="COUNT">%d</xliff:g> brugere.</item>
+ </plurals>
<string name="user_remove_user_title" msgid="4681256956076895559">"Vil du fjerne brugeren?"</string>
<string name="user_remove_user_message" msgid="1453218013959498039">"Alle apps og data for denne bruger slettes."</string>
<string name="user_remove_user_remove" msgid="7479275741742178297">"Fjern"</string>
@@ -732,8 +734,7 @@
<string name="left_icon" msgid="3096287125959387541">"Venstre ikon"</string>
<string name="right_icon" msgid="3952104823293824311">"Højre ikon"</string>
<string name="drag_to_add_tiles" msgid="230586591689084925">"Tilføj felter ved at holde dem nede og trække"</string>
- <!-- no translation found for drag_to_rearrange_tiles (4566074720193667473) -->
- <skip />
+ <string name="drag_to_rearrange_tiles" msgid="4566074720193667473">"Omorganiser felter ved at holde dem nede og trække"</string>
<string name="drag_to_remove_tiles" msgid="3361212377437088062">"Træk herhen for at fjerne"</string>
<string name="drag_to_remove_disabled" msgid="2390968976638993382">"Du skal bruge mindst seks felter"</string>
<string name="qs_edit" msgid="2232596095725105230">"Rediger"</string>
diff --git a/packages/SystemUI/res/values-de/strings.xml b/packages/SystemUI/res/values-de/strings.xml
index 6636c9d7b40e..aa6e449fbce8 100644
--- a/packages/SystemUI/res/values-de/strings.xml
+++ b/packages/SystemUI/res/values-de/strings.xml
@@ -430,9 +430,11 @@
<string name="user_logout_notification_action" msgid="1195428991423425062">"Nutzer abmelden"</string>
<string name="user_add_user_title" msgid="4553596395824132638">"Neuen Nutzer hinzufügen?"</string>
<string name="user_add_user_message_short" msgid="2161624834066214559">"Wenn du einen neuen Nutzer hinzufügst, muss dieser seinen Bereich einrichten.\n\nJeder Nutzer kann Apps für alle anderen Nutzer aktualisieren."</string>
- <!-- no translation found for user_limit_reached_title (7374910700117359177) -->
- <skip />
- <!-- no translation found for user_limit_reached_message (1855040563671964242) -->
+ <string name="user_limit_reached_title" msgid="7374910700117359177">"Nutzerlimit erreicht"</string>
+ <plurals name="user_limit_reached_message" formatted="false" msgid="1855040563671964242">
+ <item quantity="other">Du kannst bis zu <xliff:g id="COUNT">%d</xliff:g> Nutzer hinzufügen.</item>
+ <item quantity="one">Es kann nur ein Nutzer erstellt werden.</item>
+ </plurals>
<string name="user_remove_user_title" msgid="4681256956076895559">"Nutzer entfernen?"</string>
<string name="user_remove_user_message" msgid="1453218013959498039">"Alle Apps und Daten dieses Nutzers werden gelöscht."</string>
<string name="user_remove_user_remove" msgid="7479275741742178297">"Entfernen"</string>
@@ -736,8 +738,7 @@
<string name="left_icon" msgid="3096287125959387541">"Linkes Symbol"</string>
<string name="right_icon" msgid="3952104823293824311">"Rechtes Symbol"</string>
<string name="drag_to_add_tiles" msgid="230586591689084925">"Halten und ziehen, um Kacheln hinzuzufügen"</string>
- <!-- no translation found for drag_to_rearrange_tiles (4566074720193667473) -->
- <skip />
+ <string name="drag_to_rearrange_tiles" msgid="4566074720193667473">"Halten und ziehen, um die Kacheln neu anzuordnen"</string>
<string name="drag_to_remove_tiles" msgid="3361212377437088062">"Zum Entfernen hierher ziehen"</string>
<string name="drag_to_remove_disabled" msgid="2390968976638993382">"Du brauchst mindestens sechs Kacheln"</string>
<string name="qs_edit" msgid="2232596095725105230">"Bearbeiten"</string>
diff --git a/packages/SystemUI/res/values-el/strings.xml b/packages/SystemUI/res/values-el/strings.xml
index 60c412ac9d72..1a1c762cd228 100644
--- a/packages/SystemUI/res/values-el/strings.xml
+++ b/packages/SystemUI/res/values-el/strings.xml
@@ -426,9 +426,11 @@
<string name="user_logout_notification_action" msgid="1195428991423425062">"ΑΠΟΣΥΝΔΕΣΗ ΧΡΗΣΤΗ"</string>
<string name="user_add_user_title" msgid="4553596395824132638">"Προσθήκη νέου χρήστη;"</string>
<string name="user_add_user_message_short" msgid="2161624834066214559">"Κατά την προσθήκη ενός νέου χρήστη, αυτός θα πρέπει να ρυθμίσει το χώρο του.\n\nΟποιοσδήποτε χρήστης μπορεί να ενημερώσει τις εφαρμογές για όλους τους άλλους χρήστες."</string>
- <!-- no translation found for user_limit_reached_title (7374910700117359177) -->
- <skip />
- <!-- no translation found for user_limit_reached_message (1855040563671964242) -->
+ <string name="user_limit_reached_title" msgid="7374910700117359177">"Συμπληρώθηκε το όριο χρηστών"</string>
+ <plurals name="user_limit_reached_message" formatted="false" msgid="1855040563671964242">
+ <item quantity="other">Μπορείτε να προσθέσετε έως <xliff:g id="COUNT">%d</xliff:g> χρήστες.</item>
+ <item quantity="one">Είναι δυνατή η δημιουργία μόνο ενός χρήστη.</item>
+ </plurals>
<string name="user_remove_user_title" msgid="4681256956076895559">"Κατάργηση χρήστη;"</string>
<string name="user_remove_user_message" msgid="1453218013959498039">"Όλες οι εφαρμογές και τα δεδομένα αυτού του χρήστη θα διαγραφούν."</string>
<string name="user_remove_user_remove" msgid="7479275741742178297">"Κατάργηση"</string>
@@ -732,8 +734,7 @@
<string name="left_icon" msgid="3096287125959387541">"Αριστερό εικονίδιο"</string>
<string name="right_icon" msgid="3952104823293824311">"Δεξιό εικονίδιο"</string>
<string name="drag_to_add_tiles" msgid="230586591689084925">"Κρατήστε και σύρετε για την προσθήκη πλακιδίων"</string>
- <!-- no translation found for drag_to_rearrange_tiles (4566074720193667473) -->
- <skip />
+ <string name="drag_to_rearrange_tiles" msgid="4566074720193667473">"Κρατήστε και σύρετε για αναδιάταξη των πλακιδίων"</string>
<string name="drag_to_remove_tiles" msgid="3361212377437088062">"Σύρετε εδώ για κατάργηση"</string>
<string name="drag_to_remove_disabled" msgid="2390968976638993382">"Απαιτούνται τουλάχιστον 6 πλακίδια"</string>
<string name="qs_edit" msgid="2232596095725105230">"Επεξεργασία"</string>
diff --git a/packages/SystemUI/res/values-es-rUS/strings.xml b/packages/SystemUI/res/values-es-rUS/strings.xml
index f5587feb3b07..31509dc656a7 100644
--- a/packages/SystemUI/res/values-es-rUS/strings.xml
+++ b/packages/SystemUI/res/values-es-rUS/strings.xml
@@ -428,9 +428,11 @@
<string name="user_logout_notification_action" msgid="1195428991423425062">"SALIR DE SESIÓN DEL USUARIO"</string>
<string name="user_add_user_title" msgid="4553596395824132638">"¿Agregar usuario nuevo?"</string>
<string name="user_add_user_message_short" msgid="2161624834066214559">"Cuando agregas un nuevo usuario, esa persona debe configurar su espacio.\n\nCualquier usuario puede actualizar las aplicaciones del resto de los usuarios."</string>
- <!-- no translation found for user_limit_reached_title (7374910700117359177) -->
- <skip />
- <!-- no translation found for user_limit_reached_message (1855040563671964242) -->
+ <string name="user_limit_reached_title" msgid="7374910700117359177">"Alcanzaste el límite de usuarios"</string>
+ <plurals name="user_limit_reached_message" formatted="false" msgid="1855040563671964242">
+ <item quantity="other">Puedes agregar hasta <xliff:g id="COUNT">%d</xliff:g> usuarios.</item>
+ <item quantity="one">Solo se puede crear un usuario.</item>
+ </plurals>
<string name="user_remove_user_title" msgid="4681256956076895559">"¿Confirmas que quieres quitar el usuario?"</string>
<string name="user_remove_user_message" msgid="1453218013959498039">"Se borrarán todas las aplicaciones y los datos de este usuario."</string>
<string name="user_remove_user_remove" msgid="7479275741742178297">"Quitar"</string>
@@ -734,8 +736,7 @@
<string name="left_icon" msgid="3096287125959387541">"Ícono izquierdo"</string>
<string name="right_icon" msgid="3952104823293824311">"Ícono derecho"</string>
<string name="drag_to_add_tiles" msgid="230586591689084925">"Mantén presionado para agregar mosaicos"</string>
- <!-- no translation found for drag_to_rearrange_tiles (4566074720193667473) -->
- <skip />
+ <string name="drag_to_rearrange_tiles" msgid="4566074720193667473">"Mantén presionado y arrastra para reorganizar los mosaicos"</string>
<string name="drag_to_remove_tiles" msgid="3361212377437088062">"Arrastra aquí para quitar"</string>
<string name="drag_to_remove_disabled" msgid="2390968976638993382">"Necesitas al menos 6 mosaicos"</string>
<string name="qs_edit" msgid="2232596095725105230">"Editar"</string>
diff --git a/packages/SystemUI/res/values-es/strings.xml b/packages/SystemUI/res/values-es/strings.xml
index e78e1301d583..2cc3abd82099 100644
--- a/packages/SystemUI/res/values-es/strings.xml
+++ b/packages/SystemUI/res/values-es/strings.xml
@@ -428,9 +428,11 @@
<string name="user_logout_notification_action" msgid="1195428991423425062">"SALIR DE USUARIO"</string>
<string name="user_add_user_title" msgid="4553596395824132638">"¿Añadir nuevo usuario?"</string>
<string name="user_add_user_message_short" msgid="2161624834066214559">"Al añadir un nuevo usuario, este debe configurar su espacio.\n\nCualquier usuario puede actualizar las aplicaciones del resto de usuarios."</string>
- <!-- no translation found for user_limit_reached_title (7374910700117359177) -->
- <skip />
- <!-- no translation found for user_limit_reached_message (1855040563671964242) -->
+ <string name="user_limit_reached_title" msgid="7374910700117359177">"Has alcanzado el límite de usuarios"</string>
+ <plurals name="user_limit_reached_message" formatted="false" msgid="1855040563671964242">
+ <item quantity="other">Puedes añadir hasta <xliff:g id="COUNT">%d</xliff:g> usuarios.</item>
+ <item quantity="one">Solo se puede crear un usuario.</item>
+ </plurals>
<string name="user_remove_user_title" msgid="4681256956076895559">"¿Quitar usuario?"</string>
<string name="user_remove_user_message" msgid="1453218013959498039">"Se eliminarán todas las aplicaciones y todos los datos de este usuario."</string>
<string name="user_remove_user_remove" msgid="7479275741742178297">"Quitar"</string>
@@ -734,8 +736,7 @@
<string name="left_icon" msgid="3096287125959387541">"Icono a la izquierda"</string>
<string name="right_icon" msgid="3952104823293824311">"Icono a la derecha"</string>
<string name="drag_to_add_tiles" msgid="230586591689084925">"Pulsa y arrastra para añadir funciones"</string>
- <!-- no translation found for drag_to_rearrange_tiles (4566074720193667473) -->
- <skip />
+ <string name="drag_to_rearrange_tiles" msgid="4566074720193667473">"Mantener pulsado y arrastrar para reorganizar los mosaicos"</string>
<string name="drag_to_remove_tiles" msgid="3361212377437088062">"Arrastra aquí para quitar una función"</string>
<string name="drag_to_remove_disabled" msgid="2390968976638993382">"Necesitas 6 mosaicos como mínimo"</string>
<string name="qs_edit" msgid="2232596095725105230">"Editar"</string>
diff --git a/packages/SystemUI/res/values-et/strings.xml b/packages/SystemUI/res/values-et/strings.xml
index 68cb7382cad5..f22dc1ac866e 100644
--- a/packages/SystemUI/res/values-et/strings.xml
+++ b/packages/SystemUI/res/values-et/strings.xml
@@ -428,9 +428,11 @@
<string name="user_logout_notification_action" msgid="1195428991423425062">"LOGI KASUTAJA VÄLJA"</string>
<string name="user_add_user_title" msgid="4553596395824132638">"Kas lisada uus kasutaja?"</string>
<string name="user_add_user_message_short" msgid="2161624834066214559">"Kui lisate uue kasutaja, siis peab ta seadistama oma ruumi.\n\nIga kasutaja saab värskendada rakendusi kõigi kasutajate jaoks."</string>
- <!-- no translation found for user_limit_reached_title (7374910700117359177) -->
- <skip />
- <!-- no translation found for user_limit_reached_message (1855040563671964242) -->
+ <string name="user_limit_reached_title" msgid="7374910700117359177">"Kasutajate limiit on täis"</string>
+ <plurals name="user_limit_reached_message" formatted="false" msgid="1855040563671964242">
+ <item quantity="other">Võite lisada kuni <xliff:g id="COUNT">%d</xliff:g> kasutajat.</item>
+ <item quantity="one">Luua saab ainult ühe kasutaja.</item>
+ </plurals>
<string name="user_remove_user_title" msgid="4681256956076895559">"Kas eemaldada kasutaja?"</string>
<string name="user_remove_user_message" msgid="1453218013959498039">"Kasutaja kõik rakendused ja andmed kustutatakse."</string>
<string name="user_remove_user_remove" msgid="7479275741742178297">"Eemalda"</string>
@@ -734,8 +736,7 @@
<string name="left_icon" msgid="3096287125959387541">"Vasak ikoon"</string>
<string name="right_icon" msgid="3952104823293824311">"Parem ikoon"</string>
<string name="drag_to_add_tiles" msgid="230586591689084925">"Paanide lisamiseks hoidke all ja lohistage"</string>
- <!-- no translation found for drag_to_rearrange_tiles (4566074720193667473) -->
- <skip />
+ <string name="drag_to_rearrange_tiles" msgid="4566074720193667473">"Paanide ümberpaigutamiseks hoidke neid all ja lohistage"</string>
<string name="drag_to_remove_tiles" msgid="3361212377437088062">"Lohistage eemaldamiseks siia"</string>
<string name="drag_to_remove_disabled" msgid="2390968976638993382">"Teil on vaja vähemalt kuut paani"</string>
<string name="qs_edit" msgid="2232596095725105230">"Muutmine"</string>
diff --git a/packages/SystemUI/res/values-eu/strings.xml b/packages/SystemUI/res/values-eu/strings.xml
index e203b76d9b7c..87dba92ae798 100644
--- a/packages/SystemUI/res/values-eu/strings.xml
+++ b/packages/SystemUI/res/values-eu/strings.xml
@@ -428,9 +428,11 @@
<string name="user_logout_notification_action" msgid="1195428991423425062">"AMAITU ERABILTZAILEAREN SAIOA"</string>
<string name="user_add_user_title" msgid="4553596395824132638">"Beste erabiltzaile bat gehitu?"</string>
<string name="user_add_user_message_short" msgid="2161624834066214559">"Erabiltzaile bat gehitzen duzunean, horrek bere eremua konfiguratu beharko du.\n\nEdozein erabiltzailek egunera ditzake beste erabiltzaile guztien aplikazioak."</string>
- <!-- no translation found for user_limit_reached_title (7374910700117359177) -->
- <skip />
- <!-- no translation found for user_limit_reached_message (1855040563671964242) -->
+ <string name="user_limit_reached_title" msgid="7374910700117359177">"Erabiltzaile-mugara iritsi zara"</string>
+ <plurals name="user_limit_reached_message" formatted="false" msgid="1855040563671964242">
+ <item quantity="other">Gehienez, <xliff:g id="COUNT">%d</xliff:g> erabiltzaile gehi ditzakezu.</item>
+ <item quantity="one">Erabiltzaile bakarra sor daiteke.</item>
+ </plurals>
<string name="user_remove_user_title" msgid="4681256956076895559">"Erabiltzailea kendu nahi duzu?"</string>
<string name="user_remove_user_message" msgid="1453218013959498039">"Erabiltzailearen aplikazio eta datu guztiak ezabatuko dira."</string>
<string name="user_remove_user_remove" msgid="7479275741742178297">"Kendu"</string>
@@ -734,8 +736,7 @@
<string name="left_icon" msgid="3096287125959387541">"Ezkerreko ikonoa"</string>
<string name="right_icon" msgid="3952104823293824311">"Eskuineko ikonoa"</string>
<string name="drag_to_add_tiles" msgid="230586591689084925">"Eduki sakatuta eta arrastatu lauzak gehitzeko"</string>
- <!-- no translation found for drag_to_rearrange_tiles (4566074720193667473) -->
- <skip />
+ <string name="drag_to_rearrange_tiles" msgid="4566074720193667473">"Eduki sakatuta eta arrastatu, lauzak berrantolatzeko"</string>
<string name="drag_to_remove_tiles" msgid="3361212377437088062">"Kentzeko, arrastatu hona"</string>
<string name="drag_to_remove_disabled" msgid="2390968976638993382">"Gutxienez sei lauza behar dituzu"</string>
<string name="qs_edit" msgid="2232596095725105230">"Editatu"</string>
diff --git a/packages/SystemUI/res/values-fa/strings.xml b/packages/SystemUI/res/values-fa/strings.xml
index 62bb59faedf5..5411d3d59af0 100644
--- a/packages/SystemUI/res/values-fa/strings.xml
+++ b/packages/SystemUI/res/values-fa/strings.xml
@@ -426,9 +426,11 @@
<string name="user_logout_notification_action" msgid="1195428991423425062">"خروج کاربر از سیستم"</string>
<string name="user_add_user_title" msgid="4553596395824132638">"کاربر جدیدی اضافه می‌کنید؟"</string>
<string name="user_add_user_message_short" msgid="2161624834066214559">"وقتی کاربر جدیدی اضافه می‌کنید آن فرد باید فضای خودش را تنظیم کند.\n\nهر کاربری می‌تواند برنامه‌ها را برای همه کاربران دیگر به‌روزرسانی کند."</string>
- <!-- no translation found for user_limit_reached_title (7374910700117359177) -->
- <skip />
- <!-- no translation found for user_limit_reached_message (1855040563671964242) -->
+ <string name="user_limit_reached_title" msgid="7374910700117359177">"به تعداد مجاز تعداد کاربر رسیده‌اید"</string>
+ <plurals name="user_limit_reached_message" formatted="false" msgid="1855040563671964242">
+ <item quantity="one">می‌توانید حداکثر <xliff:g id="COUNT">%d</xliff:g> کاربر اضافه کنید.</item>
+ <item quantity="other">می‌توانید حداکثر <xliff:g id="COUNT">%d</xliff:g> کاربر اضافه کنید.</item>
+ </plurals>
<string name="user_remove_user_title" msgid="4681256956076895559">"کاربر حذف شود؟"</string>
<string name="user_remove_user_message" msgid="1453218013959498039">"همه برنامه‌ها و داده‌های این کاربر حذف می‌شود."</string>
<string name="user_remove_user_remove" msgid="7479275741742178297">"حذف"</string>
@@ -732,8 +734,7 @@
<string name="left_icon" msgid="3096287125959387541">"نماد چپ"</string>
<string name="right_icon" msgid="3952104823293824311">"نماد راست"</string>
<string name="drag_to_add_tiles" msgid="230586591689084925">"نگه‌داشتن و کشیدن برای افزودن کاشی"</string>
- <!-- no translation found for drag_to_rearrange_tiles (4566074720193667473) -->
- <skip />
+ <string name="drag_to_rearrange_tiles" msgid="4566074720193667473">"برای تغییر دادن ترتیب کاشی‌ها، آن‌ها را نگه دارید و بکشید"</string>
<string name="drag_to_remove_tiles" msgid="3361212377437088062">"برای حذف، به اینجا بکشید"</string>
<string name="drag_to_remove_disabled" msgid="2390968976638993382">"حداقل به ۶ کاشی نیاز دارید"</string>
<string name="qs_edit" msgid="2232596095725105230">"ویرایش"</string>
diff --git a/packages/SystemUI/res/values-fi/strings.xml b/packages/SystemUI/res/values-fi/strings.xml
index 330f7d6f9b88..83345b833b9c 100644
--- a/packages/SystemUI/res/values-fi/strings.xml
+++ b/packages/SystemUI/res/values-fi/strings.xml
@@ -426,9 +426,11 @@
<string name="user_logout_notification_action" msgid="1195428991423425062">"KIRJAA KÄYTTÄJÄ ULOS"</string>
<string name="user_add_user_title" msgid="4553596395824132638">"Lisätäänkö uusi käyttäjä?"</string>
<string name="user_add_user_message_short" msgid="2161624834066214559">"Kun lisäät uuden käyttäjän, hänen tulee määrittää oman tilansa asetukset.\n\nKaikki käyttäjät voivat päivittää sovelluksia muille käyttäjille."</string>
- <!-- no translation found for user_limit_reached_title (7374910700117359177) -->
- <skip />
- <!-- no translation found for user_limit_reached_message (1855040563671964242) -->
+ <string name="user_limit_reached_title" msgid="7374910700117359177">"Käyttäjäraja saavutettu"</string>
+ <plurals name="user_limit_reached_message" formatted="false" msgid="1855040563671964242">
+ <item quantity="other">Voit lisätä korkeintaan <xliff:g id="COUNT">%d</xliff:g> käyttäjää.</item>
+ <item quantity="one">Käyttäjiä voi olla vain yksi.</item>
+ </plurals>
<string name="user_remove_user_title" msgid="4681256956076895559">"Poistetaanko käyttäjä?"</string>
<string name="user_remove_user_message" msgid="1453218013959498039">"Kaikki käyttäjän tiedot ja sovellukset poistetaan."</string>
<string name="user_remove_user_remove" msgid="7479275741742178297">"Poista"</string>
@@ -732,8 +734,7 @@
<string name="left_icon" msgid="3096287125959387541">"Vasen kuvake"</string>
<string name="right_icon" msgid="3952104823293824311">"Oikea kuvake"</string>
<string name="drag_to_add_tiles" msgid="230586591689084925">"Lisää osioita koskettamalla pitkään ja vetämällä"</string>
- <!-- no translation found for drag_to_rearrange_tiles (4566074720193667473) -->
- <skip />
+ <string name="drag_to_rearrange_tiles" msgid="4566074720193667473">"Järjestele ruutuja koskettamalla pitkään ja vetämällä"</string>
<string name="drag_to_remove_tiles" msgid="3361212377437088062">"Poista vetämällä tähän."</string>
<string name="drag_to_remove_disabled" msgid="2390968976638993382">"Kuusi osiota on vähimmäismäärä."</string>
<string name="qs_edit" msgid="2232596095725105230">"Muokkaa"</string>
diff --git a/packages/SystemUI/res/values-fr-rCA/strings.xml b/packages/SystemUI/res/values-fr-rCA/strings.xml
index 47430ba0fe17..c9c252feab05 100644
--- a/packages/SystemUI/res/values-fr-rCA/strings.xml
+++ b/packages/SystemUI/res/values-fr-rCA/strings.xml
@@ -428,9 +428,11 @@
<string name="user_logout_notification_action" msgid="1195428991423425062">"DÉCONNECTER L\'UTILISATEUR"</string>
<string name="user_add_user_title" msgid="4553596395824132638">"Ajouter un utilisateur?"</string>
<string name="user_add_user_message_short" msgid="2161624834066214559">"Lorsque vous ajoutez un utilisateur, celui-ci doit configurer son espace.\n\nTout utilisateur peut mettre à jour les applications pour tous les autres utilisateurs."</string>
- <!-- no translation found for user_limit_reached_title (7374910700117359177) -->
- <skip />
- <!-- no translation found for user_limit_reached_message (1855040563671964242) -->
+ <string name="user_limit_reached_title" msgid="7374910700117359177">"Limite d\'utilisateurs atteinte"</string>
+ <plurals name="user_limit_reached_message" formatted="false" msgid="1855040563671964242">
+ <item quantity="one">Vous pouvez ajouter jusqu\'à <xliff:g id="COUNT">%d</xliff:g> utilisateur.</item>
+ <item quantity="other">Vous pouvez ajouter jusqu\'à <xliff:g id="COUNT">%d</xliff:g> utilisateurs.</item>
+ </plurals>
<string name="user_remove_user_title" msgid="4681256956076895559">"Supprimer l\'utilisateur?"</string>
<string name="user_remove_user_message" msgid="1453218013959498039">"Toutes les applications et les données de cet utilisateur seront supprimées."</string>
<string name="user_remove_user_remove" msgid="7479275741742178297">"Supprimer"</string>
@@ -734,8 +736,7 @@
<string name="left_icon" msgid="3096287125959387541">"Icône à gauche"</string>
<string name="right_icon" msgid="3952104823293824311">"Icône droite"</string>
<string name="drag_to_add_tiles" msgid="230586591689084925">"Maint. doigt sur écran, puis glissez-le pour aj. des tuiles"</string>
- <!-- no translation found for drag_to_rearrange_tiles (4566074720193667473) -->
- <skip />
+ <string name="drag_to_rearrange_tiles" msgid="4566074720193667473">"Maint. doigt sur l\'écran, puis glissez-le pour réorg. tuiles"</string>
<string name="drag_to_remove_tiles" msgid="3361212377437088062">"Faites glisser les tuiles ici pour les supprimer"</string>
<string name="drag_to_remove_disabled" msgid="2390968976638993382">"Vous avez besoin d\'au moins six tuiles"</string>
<string name="qs_edit" msgid="2232596095725105230">"Modifier"</string>
diff --git a/packages/SystemUI/res/values-fr/strings.xml b/packages/SystemUI/res/values-fr/strings.xml
index c10c1d2a7663..4559854cd0f0 100644
--- a/packages/SystemUI/res/values-fr/strings.xml
+++ b/packages/SystemUI/res/values-fr/strings.xml
@@ -361,7 +361,7 @@
<string name="recents_search_bar_label" msgid="8074997400187836677">"rechercher"</string>
<string name="recents_launch_error_message" msgid="2969287838120550506">"Impossible de lancer <xliff:g id="APP">%s</xliff:g>."</string>
<string name="recents_launch_disabled_message" msgid="1624523193008871793">"L\'application <xliff:g id="APP">%s</xliff:g> est désactivée en mode sécurisé."</string>
- <string name="recents_stack_action_button_label" msgid="6593727103310426253">"Tout effacer"</string>
+ <string name="recents_stack_action_button_label" msgid="6593727103310426253">"Tout fermer"</string>
<string name="recents_drag_hint_message" msgid="2649739267073203985">"Faire glisser ici pour utiliser l\'écran partagé"</string>
<string name="recents_swipe_up_onboarding" msgid="3824607135920170001">"Balayer l\'écran vers le haut pour changer d\'application"</string>
<string name="recents_quick_scrub_onboarding" msgid="2778062804333285789">"Déplacer vers la droite pour changer rapidement d\'application"</string>
@@ -428,9 +428,11 @@
<string name="user_logout_notification_action" msgid="1195428991423425062">"DÉCONNECTER L\'UTILISATEUR"</string>
<string name="user_add_user_title" msgid="4553596395824132638">"Ajouter un utilisateur ?"</string>
<string name="user_add_user_message_short" msgid="2161624834066214559">"Lorsque vous ajoutez un utilisateur, celui-ci doit configurer son espace.\n\nN\'importe quel utilisateur peut mettre à jour les applications pour tous les autres utilisateurs."</string>
- <!-- no translation found for user_limit_reached_title (7374910700117359177) -->
- <skip />
- <!-- no translation found for user_limit_reached_message (1855040563671964242) -->
+ <string name="user_limit_reached_title" msgid="7374910700117359177">"Limite nombre utilisateurs atteinte"</string>
+ <plurals name="user_limit_reached_message" formatted="false" msgid="1855040563671964242">
+ <item quantity="one">Vous pouvez ajouter <xliff:g id="COUNT">%d</xliff:g> profil utilisateur.</item>
+ <item quantity="other">Vous pouvez ajouter jusqu\'à <xliff:g id="COUNT">%d</xliff:g> profils utilisateur.</item>
+ </plurals>
<string name="user_remove_user_title" msgid="4681256956076895559">"Supprimer l\'utilisateur ?"</string>
<string name="user_remove_user_message" msgid="1453218013959498039">"Toutes les applications et les données de cet utilisateur seront supprimées."</string>
<string name="user_remove_user_remove" msgid="7479275741742178297">"Supprimer"</string>
@@ -734,8 +736,7 @@
<string name="left_icon" msgid="3096287125959387541">"Icône gauche"</string>
<string name="right_icon" msgid="3952104823293824311">"Icône droite"</string>
<string name="drag_to_add_tiles" msgid="230586591689084925">"Sélectionnez et faites glisser les tuiles pour les ajouter"</string>
- <!-- no translation found for drag_to_rearrange_tiles (4566074720193667473) -->
- <skip />
+ <string name="drag_to_rearrange_tiles" msgid="4566074720193667473">"Sélectionnez et faites glisser les tuiles pour réorganiser"</string>
<string name="drag_to_remove_tiles" msgid="3361212377437088062">"Faites glisser les tuiles ici pour les supprimer."</string>
<string name="drag_to_remove_disabled" msgid="2390968976638993382">"Au minimum six tuiles sont nécessaires"</string>
<string name="qs_edit" msgid="2232596095725105230">"Modifier"</string>
diff --git a/packages/SystemUI/res/values-gl/strings.xml b/packages/SystemUI/res/values-gl/strings.xml
index 5c6737f4c505..9cb251e21174 100644
--- a/packages/SystemUI/res/values-gl/strings.xml
+++ b/packages/SystemUI/res/values-gl/strings.xml
@@ -428,9 +428,11 @@
<string name="user_logout_notification_action" msgid="1195428991423425062">"PECHAR SESIÓN DO USUARIO"</string>
<string name="user_add_user_title" msgid="4553596395824132638">"Engadir un usuario novo?"</string>
<string name="user_add_user_message_short" msgid="2161624834066214559">"Cando engadas un usuario novo, este deberá configurar o seu espazo\n\nCalquera usuario pode actualizar as aplicacións para todos os demais usuarios."</string>
- <!-- no translation found for user_limit_reached_title (7374910700117359177) -->
- <skip />
- <!-- no translation found for user_limit_reached_message (1855040563671964242) -->
+ <string name="user_limit_reached_title" msgid="7374910700117359177">"Alcanzouse o límite de usuarios"</string>
+ <plurals name="user_limit_reached_message" formatted="false" msgid="1855040563671964242">
+ <item quantity="other">Podes engadir ata <xliff:g id="COUNT">%d</xliff:g> usuarios.</item>
+ <item quantity="one">Só se pode crear un usuario.</item>
+ </plurals>
<string name="user_remove_user_title" msgid="4681256956076895559">"Queres eliminar o usuario?"</string>
<string name="user_remove_user_message" msgid="1453218013959498039">"Eliminaranse todas as aplicacións e os datos deste usuario."</string>
<string name="user_remove_user_remove" msgid="7479275741742178297">"Eliminar"</string>
@@ -734,8 +736,7 @@
<string name="left_icon" msgid="3096287125959387541">"Icona á esquerda"</string>
<string name="right_icon" msgid="3952104823293824311">"Icona á dereita"</string>
<string name="drag_to_add_tiles" msgid="230586591689084925">"Mantén premidas as funcións e arrástraas para engadilas"</string>
- <!-- no translation found for drag_to_rearrange_tiles (4566074720193667473) -->
- <skip />
+ <string name="drag_to_rearrange_tiles" msgid="4566074720193667473">"Para reorganizar os mosaicos, mantenos premidos e arrástraos"</string>
<string name="drag_to_remove_tiles" msgid="3361212377437088062">"Arrastra o elemento ata aquí para eliminalo"</string>
<string name="drag_to_remove_disabled" msgid="2390968976638993382">"Necesitas polo menos 6 mosaicos"</string>
<string name="qs_edit" msgid="2232596095725105230">"Editar"</string>
diff --git a/packages/SystemUI/res/values-gu/strings.xml b/packages/SystemUI/res/values-gu/strings.xml
index 76e00d435c17..df06cbeb8bfa 100644
--- a/packages/SystemUI/res/values-gu/strings.xml
+++ b/packages/SystemUI/res/values-gu/strings.xml
@@ -426,9 +426,11 @@
<string name="user_logout_notification_action" msgid="1195428991423425062">"વપરાશકર્તાને લૉગઆઉટ કરો"</string>
<string name="user_add_user_title" msgid="4553596395824132638">"નવા વપરાશકર્તાને ઉમેરીએ?"</string>
<string name="user_add_user_message_short" msgid="2161624834066214559">"જ્યારે તમે કોઈ નવા વપરાશકર્તાને ઉમેરો છો, ત્યારે તે વ્યક્તિને તેમનું સ્થાન સેટ કરવાની જરૂર પડે છે.\n\nકોઈપણ વપરાશકર્તા બધા અન્ય વપરાશકર્તાઓ માટે એપ્લિકેશન્સને અપડેટ કરી શકે છે."</string>
- <!-- no translation found for user_limit_reached_title (7374910700117359177) -->
- <skip />
- <!-- no translation found for user_limit_reached_message (1855040563671964242) -->
+ <string name="user_limit_reached_title" msgid="7374910700117359177">"વપરાશકર્તા સંખ્યાની મર્યાદા"</string>
+ <plurals name="user_limit_reached_message" formatted="false" msgid="1855040563671964242">
+ <item quantity="one">તમે <xliff:g id="COUNT">%d</xliff:g> વપરાશકર્તા સુધી ઉમેરી શકો છો.</item>
+ <item quantity="other">તમે <xliff:g id="COUNT">%d</xliff:g> વપરાશકર્તાઓ સુધી ઉમેરી શકો છો.</item>
+ </plurals>
<string name="user_remove_user_title" msgid="4681256956076895559">"વપરાશકર્તાને દૂર કરીએ?"</string>
<string name="user_remove_user_message" msgid="1453218013959498039">"આ વપરાશકર્તાની તમામ ઍપ્લિકેશનો અને ડેટા કાઢી નાખવામાં આવશે."</string>
<string name="user_remove_user_remove" msgid="7479275741742178297">"દૂર કરો"</string>
@@ -732,8 +734,7 @@
<string name="left_icon" msgid="3096287125959387541">"ડાબું આઇકન"</string>
<string name="right_icon" msgid="3952104823293824311">"જમણું આઇકન"</string>
<string name="drag_to_add_tiles" msgid="230586591689084925">"ટાઇલ ઉમેરવા માટે તેના પર આંગળી દબાવીને ખેંચો"</string>
- <!-- no translation found for drag_to_rearrange_tiles (4566074720193667473) -->
- <skip />
+ <string name="drag_to_rearrange_tiles" msgid="4566074720193667473">"ટાઇલને ફરીથી ગોઠવવા માટે આંગળી દબાવીને ખેંચો"</string>
<string name="drag_to_remove_tiles" msgid="3361212377437088062">"દૂર કરવા માટે અહીં ખેંચો"</string>
<string name="drag_to_remove_disabled" msgid="2390968976638993382">"તમને ઓછામાં ઓછી 6 ટાઇલની જરૂર છે"</string>
<string name="qs_edit" msgid="2232596095725105230">"સંપાદિત કરો"</string>
diff --git a/packages/SystemUI/res/values-hi/strings.xml b/packages/SystemUI/res/values-hi/strings.xml
index ad8d50590ed3..46555a483a59 100644
--- a/packages/SystemUI/res/values-hi/strings.xml
+++ b/packages/SystemUI/res/values-hi/strings.xml
@@ -426,9 +426,11 @@
<string name="user_logout_notification_action" msgid="1195428991423425062">"उपयोगकर्ता को प्रस्थान करवाएं"</string>
<string name="user_add_user_title" msgid="4553596395824132638">"नया उपयोगकर्ता जोड़ें?"</string>
<string name="user_add_user_message_short" msgid="2161624834066214559">"जब आप कोई नया उपयोगकर्ता जोड़ते हैं तो उस व्यक्ति को अपनी जगह सेट करनी होती है.\n\nकोई भी उपयोगकर्ता बाकी सभी उपयोगकर्ताओं के लिए ऐप्लिकेशन अपडेट कर सकता है."</string>
- <!-- no translation found for user_limit_reached_title (7374910700117359177) -->
- <skip />
- <!-- no translation found for user_limit_reached_message (1855040563671964242) -->
+ <string name="user_limit_reached_title" msgid="7374910700117359177">"अब और उपयोगकर्ता नहीं जोड़े जा सकते"</string>
+ <plurals name="user_limit_reached_message" formatted="false" msgid="1855040563671964242">
+ <item quantity="one">आप ज़्यादा से ज़्यादा <xliff:g id="COUNT">%d</xliff:g> उपयोगकर्ता जोड़ सकते हैं.</item>
+ <item quantity="other">आप ज़्यादा से ज़्यादा <xliff:g id="COUNT">%d</xliff:g> उपयोगकर्ता जोड़ सकते हैं.</item>
+ </plurals>
<string name="user_remove_user_title" msgid="4681256956076895559">"उपयोगकर्ता निकालें?"</string>
<string name="user_remove_user_message" msgid="1453218013959498039">"इस उपयोगकर्ता के सभी ऐप और डेटा को हटा दिया जाएगा."</string>
<string name="user_remove_user_remove" msgid="7479275741742178297">"निकालें"</string>
@@ -732,8 +734,7 @@
<string name="left_icon" msgid="3096287125959387541">"बायां आइकॉन"</string>
<string name="right_icon" msgid="3952104823293824311">"दायां आइकॉन"</string>
<string name="drag_to_add_tiles" msgid="230586591689084925">"टाइल जोड़ने के लिए दबाएं और खींचें"</string>
- <!-- no translation found for drag_to_rearrange_tiles (4566074720193667473) -->
- <skip />
+ <string name="drag_to_rearrange_tiles" msgid="4566074720193667473">"टाइल का क्रम फिर से बदलने के लिए उन्हें दबाकर रखें और खींचें"</string>
<string name="drag_to_remove_tiles" msgid="3361212377437088062">"हटाने के लिए यहां खींचें और छोड़ें"</string>
<string name="drag_to_remove_disabled" msgid="2390968976638993382">"आपके पास कम से कम 6 टाइल होनी चाहिए"</string>
<string name="qs_edit" msgid="2232596095725105230">"बदलाव करें"</string>
diff --git a/packages/SystemUI/res/values-hr/strings.xml b/packages/SystemUI/res/values-hr/strings.xml
index 435fc56a684e..7ad2fe295450 100644
--- a/packages/SystemUI/res/values-hr/strings.xml
+++ b/packages/SystemUI/res/values-hr/strings.xml
@@ -429,9 +429,12 @@
<string name="user_logout_notification_action" msgid="1195428991423425062">"ODJAVI KORISNIKA"</string>
<string name="user_add_user_title" msgid="4553596395824132638">"Dodati novog korisnika?"</string>
<string name="user_add_user_message_short" msgid="2161624834066214559">"Kada dodate novog korisnika, ta osoba mora postaviti vlastiti prostor.\n\nBilo koji korisnik može ažurirati aplikacije za sve ostale korisnike."</string>
- <!-- no translation found for user_limit_reached_title (7374910700117359177) -->
- <skip />
- <!-- no translation found for user_limit_reached_message (1855040563671964242) -->
+ <string name="user_limit_reached_title" msgid="7374910700117359177">"Dosegnuto je ograničenje korisnika"</string>
+ <plurals name="user_limit_reached_message" formatted="false" msgid="1855040563671964242">
+ <item quantity="one">Možete dodati najviše <xliff:g id="COUNT">%d</xliff:g> korisnika.</item>
+ <item quantity="few">Možete dodati najviše <xliff:g id="COUNT">%d</xliff:g> korisnika.</item>
+ <item quantity="other">Možete dodati najviše <xliff:g id="COUNT">%d</xliff:g> korisnika.</item>
+ </plurals>
<string name="user_remove_user_title" msgid="4681256956076895559">"Ukloniti korisnika?"</string>
<string name="user_remove_user_message" msgid="1453218013959498039">"Izbrisat će se sve aplikacije i podaci ovog korisnika."</string>
<string name="user_remove_user_remove" msgid="7479275741742178297">"Ukloni"</string>
@@ -737,8 +740,7 @@
<string name="left_icon" msgid="3096287125959387541">"Lijeva ikona"</string>
<string name="right_icon" msgid="3952104823293824311">"Desna ikona"</string>
<string name="drag_to_add_tiles" msgid="230586591689084925">"Zadržite i povucite za dodavanje pločica"</string>
- <!-- no translation found for drag_to_rearrange_tiles (4566074720193667473) -->
- <skip />
+ <string name="drag_to_rearrange_tiles" msgid="4566074720193667473">"Zadržite i povucite da biste preuredili pločice"</string>
<string name="drag_to_remove_tiles" msgid="3361212377437088062">"Povucite ovdje za uklanjanje"</string>
<string name="drag_to_remove_disabled" msgid="2390968976638993382">"Potrebno je barem 6 pločica"</string>
<string name="qs_edit" msgid="2232596095725105230">"Uredi"</string>
diff --git a/packages/SystemUI/res/values-hu/strings.xml b/packages/SystemUI/res/values-hu/strings.xml
index 6574c970ec0b..f5fad274a5fc 100644
--- a/packages/SystemUI/res/values-hu/strings.xml
+++ b/packages/SystemUI/res/values-hu/strings.xml
@@ -426,9 +426,11 @@
<string name="user_logout_notification_action" msgid="1195428991423425062">"FELHASZNÁLÓ KIJELENTKEZÉSE"</string>
<string name="user_add_user_title" msgid="4553596395824132638">"Új felhasználó hozzáadása?"</string>
<string name="user_add_user_message_short" msgid="2161624834066214559">"Ha új felhasználót ad hozzá, az illetőnek be kell állítania saját tárterületét.\n\nBármely felhasználó frissítheti az alkalmazásokat valamennyi felhasználó számára."</string>
- <!-- no translation found for user_limit_reached_title (7374910700117359177) -->
- <skip />
- <!-- no translation found for user_limit_reached_message (1855040563671964242) -->
+ <string name="user_limit_reached_title" msgid="7374910700117359177">"Maximális felhasználószám elérve"</string>
+ <plurals name="user_limit_reached_message" formatted="false" msgid="1855040563671964242">
+ <item quantity="other">Legfeljebb <xliff:g id="COUNT">%d</xliff:g> felhasználót adhat hozzá.</item>
+ <item quantity="one">Csak egy felhasználót lehet létrehozni.</item>
+ </plurals>
<string name="user_remove_user_title" msgid="4681256956076895559">"Törli a felhasználót?"</string>
<string name="user_remove_user_message" msgid="1453218013959498039">"A felhasználóhoz tartozó minden adat és alkalmazás törölve lesz."</string>
<string name="user_remove_user_remove" msgid="7479275741742178297">"Eltávolítás"</string>
@@ -732,8 +734,7 @@
<string name="left_icon" msgid="3096287125959387541">"Bal oldali ikon"</string>
<string name="right_icon" msgid="3952104823293824311">"Jobb oldali ikon"</string>
<string name="drag_to_add_tiles" msgid="230586591689084925">"Tartsa lenyomva, és húzza a mozaikok hozzáadásához"</string>
- <!-- no translation found for drag_to_rearrange_tiles (4566074720193667473) -->
- <skip />
+ <string name="drag_to_rearrange_tiles" msgid="4566074720193667473">"Tartsa lenyomva, és húzza a mozaikok átrendezéséhez"</string>
<string name="drag_to_remove_tiles" msgid="3361212377437088062">"Húzza ide az eltávolításhoz"</string>
<string name="drag_to_remove_disabled" msgid="2390968976638993382">"Legalább hat mozaik szükséges"</string>
<string name="qs_edit" msgid="2232596095725105230">"Szerkesztés"</string>
diff --git a/packages/SystemUI/res/values-hy/strings.xml b/packages/SystemUI/res/values-hy/strings.xml
index 20209a2de471..5eeca4cc352d 100644
--- a/packages/SystemUI/res/values-hy/strings.xml
+++ b/packages/SystemUI/res/values-hy/strings.xml
@@ -426,9 +426,11 @@
<string name="user_logout_notification_action" msgid="1195428991423425062">"ԸՆԹԱՑԻԿ ՕԳՏՎՈՂԻ ԴՈՒՐՍ ԳՐՈՒՄ"</string>
<string name="user_add_user_title" msgid="4553596395824132638">"Ավելացնե՞լ նոր պրոֆիլ:"</string>
<string name="user_add_user_message_short" msgid="2161624834066214559">"Երբ նոր օգտատեր եք ավելացնում, նա պետք է կարգավորի իր պրոֆիլը:\n\nՑանկացած օգտատեր կարող է թարմացնել հավելվածները մյուս բոլոր հաշիվների համար:"</string>
- <!-- no translation found for user_limit_reached_title (7374910700117359177) -->
- <skip />
- <!-- no translation found for user_limit_reached_message (1855040563671964242) -->
+ <string name="user_limit_reached_title" msgid="7374910700117359177">"Սահմանաչափը սպառված է"</string>
+ <plurals name="user_limit_reached_message" formatted="false" msgid="1855040563671964242">
+ <item quantity="one">Հնարավոր է ավելացնել առավելագույնը <xliff:g id="COUNT">%d</xliff:g> օգտատեր։</item>
+ <item quantity="other">Հնարավոր է ավելացնել առավելագույնը <xliff:g id="COUNT">%d</xliff:g> օգտատեր։</item>
+ </plurals>
<string name="user_remove_user_title" msgid="4681256956076895559">"Հեռացնե՞լ օգտատիրոջը:"</string>
<string name="user_remove_user_message" msgid="1453218013959498039">"Այս օգտատիրոջ բոլոր հավելվածներն ու տվյալները կջնջվեն:"</string>
<string name="user_remove_user_remove" msgid="7479275741742178297">"Հեռացնել"</string>
@@ -732,8 +734,7 @@
<string name="left_icon" msgid="3096287125959387541">"Ձախ պատկերակ"</string>
<string name="right_icon" msgid="3952104823293824311">"Աջ պատկերակ"</string>
<string name="drag_to_add_tiles" msgid="230586591689084925">"Պահեք և քաշեք՝ սալիկներ ավելացնելու համար"</string>
- <!-- no translation found for drag_to_rearrange_tiles (4566074720193667473) -->
- <skip />
+ <string name="drag_to_rearrange_tiles" msgid="4566074720193667473">"Պահեք և քաշեք՝ սալիկները վերադասավորելու համար"</string>
<string name="drag_to_remove_tiles" msgid="3361212377437088062">"Քաշեք այստեղ՝ հեռացնելու համար"</string>
<string name="drag_to_remove_disabled" msgid="2390968976638993382">"Հարկավոր է առնվազն 6 սալիկ"</string>
<string name="qs_edit" msgid="2232596095725105230">"Փոփոխել"</string>
diff --git a/packages/SystemUI/res/values-in/strings.xml b/packages/SystemUI/res/values-in/strings.xml
index 5111ed6c68a1..5a61a6428b6b 100644
--- a/packages/SystemUI/res/values-in/strings.xml
+++ b/packages/SystemUI/res/values-in/strings.xml
@@ -426,9 +426,11 @@
<string name="user_logout_notification_action" msgid="1195428991423425062">"KELUARKAN PENGGUNA"</string>
<string name="user_add_user_title" msgid="4553596395824132638">"Tambahkan pengguna baru?"</string>
<string name="user_add_user_message_short" msgid="2161624834066214559">"Saat Anda menambahkan pengguna baru, orang tersebut perlu menyiapkan ruangnya sendiri.\n\nPengguna mana pun dapat mengupdate aplikasi untuk semua pengguna lain."</string>
- <!-- no translation found for user_limit_reached_title (7374910700117359177) -->
- <skip />
- <!-- no translation found for user_limit_reached_message (1855040563671964242) -->
+ <string name="user_limit_reached_title" msgid="7374910700117359177">"Batas pengguna tercapai"</string>
+ <plurals name="user_limit_reached_message" formatted="false" msgid="1855040563671964242">
+ <item quantity="other">Anda dapat menambahkan hingga <xliff:g id="COUNT">%d</xliff:g> pengguna.</item>
+ <item quantity="one">Hanya dapat membuat satu pengguna.</item>
+ </plurals>
<string name="user_remove_user_title" msgid="4681256956076895559">"Hapus pengguna?"</string>
<string name="user_remove_user_message" msgid="1453218013959498039">"Semua aplikasi dan data pengguna ini akan dihapus."</string>
<string name="user_remove_user_remove" msgid="7479275741742178297">"Hapus"</string>
@@ -732,8 +734,7 @@
<string name="left_icon" msgid="3096287125959387541">"Ikon kiri"</string>
<string name="right_icon" msgid="3952104823293824311">"Ikon kanan"</string>
<string name="drag_to_add_tiles" msgid="230586591689084925">"Tahan dan tarik untuk menambahkan tile"</string>
- <!-- no translation found for drag_to_rearrange_tiles (4566074720193667473) -->
- <skip />
+ <string name="drag_to_rearrange_tiles" msgid="4566074720193667473">"Tahan dan tarik untuk mengatur ulang tile"</string>
<string name="drag_to_remove_tiles" msgid="3361212377437088062">"Tarik ke sini untuk menghapus"</string>
<string name="drag_to_remove_disabled" msgid="2390968976638993382">"Anda membutuhkan setidaknya 6 tile"</string>
<string name="qs_edit" msgid="2232596095725105230">"Edit"</string>
diff --git a/packages/SystemUI/res/values-is/strings.xml b/packages/SystemUI/res/values-is/strings.xml
index 508b2bd1c945..fb83ff076458 100644
--- a/packages/SystemUI/res/values-is/strings.xml
+++ b/packages/SystemUI/res/values-is/strings.xml
@@ -426,9 +426,11 @@
<string name="user_logout_notification_action" msgid="1195428991423425062">"SKRÁ NOTANDA ÚT"</string>
<string name="user_add_user_title" msgid="4553596395824132638">"Bæta nýjum notanda við?"</string>
<string name="user_add_user_message_short" msgid="2161624834066214559">"Þegar þú bætir nýjum notanda við þarf sá notandi að setja upp svæðið sitt.\n\nHvaða notandi sem er getur uppfært forrit fyrir alla aðra notendur."</string>
- <!-- no translation found for user_limit_reached_title (7374910700117359177) -->
- <skip />
- <!-- no translation found for user_limit_reached_message (1855040563671964242) -->
+ <string name="user_limit_reached_title" msgid="7374910700117359177">"Notandahámarki náð"</string>
+ <plurals name="user_limit_reached_message" formatted="false" msgid="1855040563671964242">
+ <item quantity="one">Þú getur bætt við allt að <xliff:g id="COUNT">%d</xliff:g> notanda.</item>
+ <item quantity="other">Þú getur bætt við allt að <xliff:g id="COUNT">%d</xliff:g> notendum.</item>
+ </plurals>
<string name="user_remove_user_title" msgid="4681256956076895559">"Fjarlægja notandann?"</string>
<string name="user_remove_user_message" msgid="1453218013959498039">"Öllum forritum og gögnum þessa notanda verður eytt."</string>
<string name="user_remove_user_remove" msgid="7479275741742178297">"Fjarlægja"</string>
@@ -732,8 +734,7 @@
<string name="left_icon" msgid="3096287125959387541">"Tákn til vinstri"</string>
<string name="right_icon" msgid="3952104823293824311">"Tákn til hægri"</string>
<string name="drag_to_add_tiles" msgid="230586591689084925">"Haltu inni og dragðu til að bæta við reitum"</string>
- <!-- no translation found for drag_to_rearrange_tiles (4566074720193667473) -->
- <skip />
+ <string name="drag_to_rearrange_tiles" msgid="4566074720193667473">"Haltu og dragðu til að endurraða flísum"</string>
<string name="drag_to_remove_tiles" msgid="3361212377437088062">"Dragðu hingað til að fjarlægja"</string>
<string name="drag_to_remove_disabled" msgid="2390968976638993382">"Reitirnir mega ekki vera færri en sex"</string>
<string name="qs_edit" msgid="2232596095725105230">"Breyta"</string>
diff --git a/packages/SystemUI/res/values-it/strings.xml b/packages/SystemUI/res/values-it/strings.xml
index 467ca8d29be5..c081eaa5afb8 100644
--- a/packages/SystemUI/res/values-it/strings.xml
+++ b/packages/SystemUI/res/values-it/strings.xml
@@ -428,9 +428,11 @@
<string name="user_logout_notification_action" msgid="1195428991423425062">"DISCONNETTI UTENTE"</string>
<string name="user_add_user_title" msgid="4553596395824132638">"Aggiungere un nuovo utente?"</string>
<string name="user_add_user_message_short" msgid="2161624834066214559">"Il nuovo utente, una volta aggiunto, deve impostare il proprio spazio.\n\nQualsiasi utente può aggiornare le app per tutti gli altri."</string>
- <!-- no translation found for user_limit_reached_title (7374910700117359177) -->
- <skip />
- <!-- no translation found for user_limit_reached_message (1855040563671964242) -->
+ <string name="user_limit_reached_title" msgid="7374910700117359177">"Limite di utenti raggiunto"</string>
+ <plurals name="user_limit_reached_message" formatted="false" msgid="1855040563671964242">
+ <item quantity="other">Puoi aggiungere fino a <xliff:g id="COUNT">%d</xliff:g> utenti.</item>
+ <item quantity="one">È possibile creare un solo utente.</item>
+ </plurals>
<string name="user_remove_user_title" msgid="4681256956076895559">"Rimuovere l\'utente?"</string>
<string name="user_remove_user_message" msgid="1453218013959498039">"Tutte le app e i dati di questo utente verranno eliminati."</string>
<string name="user_remove_user_remove" msgid="7479275741742178297">"Rimuovi"</string>
@@ -734,8 +736,7 @@
<string name="left_icon" msgid="3096287125959387541">"Icona sinistra"</string>
<string name="right_icon" msgid="3952104823293824311">"Icona destra"</string>
<string name="drag_to_add_tiles" msgid="230586591689084925">"Tieni premuto e trascina per aggiungere riquadri"</string>
- <!-- no translation found for drag_to_rearrange_tiles (4566074720193667473) -->
- <skip />
+ <string name="drag_to_rearrange_tiles" msgid="4566074720193667473">"Tieni premuto e trascina per riordinare i riquadri"</string>
<string name="drag_to_remove_tiles" msgid="3361212377437088062">"Trascina qui per rimuovere"</string>
<string name="drag_to_remove_disabled" msgid="2390968976638993382">"Occorrono almeno sei riquadri"</string>
<string name="qs_edit" msgid="2232596095725105230">"Modifica"</string>
diff --git a/packages/SystemUI/res/values-iw/strings.xml b/packages/SystemUI/res/values-iw/strings.xml
index 46d930ea620d..d3d18ae4f9ac 100644
--- a/packages/SystemUI/res/values-iw/strings.xml
+++ b/packages/SystemUI/res/values-iw/strings.xml
@@ -432,9 +432,13 @@
<string name="user_logout_notification_action" msgid="1195428991423425062">"נתק משתמש"</string>
<string name="user_add_user_title" msgid="4553596395824132638">"האם להוסיף משתמש חדש?"</string>
<string name="user_add_user_message_short" msgid="2161624834066214559">"בעת הוספת משתמש חדש, על משתמש זה להגדיר את השטח שלו.\n\nכל משתמש יכול לעדכן אפליקציות עבור כל המשתמשים האחרים."</string>
- <!-- no translation found for user_limit_reached_title (7374910700117359177) -->
- <skip />
- <!-- no translation found for user_limit_reached_message (1855040563671964242) -->
+ <string name="user_limit_reached_title" msgid="7374910700117359177">"הגעת למגבלת המשתמשים שניתן להוסיף"</string>
+ <plurals name="user_limit_reached_message" formatted="false" msgid="1855040563671964242">
+ <item quantity="two">ניתן להוסיף עד <xliff:g id="COUNT">%d</xliff:g> משתמשים.</item>
+ <item quantity="many">ניתן להוסיף עד <xliff:g id="COUNT">%d</xliff:g> משתמשים.</item>
+ <item quantity="other">ניתן להוסיף עד <xliff:g id="COUNT">%d</xliff:g> משתמשים.</item>
+ <item quantity="one">ניתן ליצור רק משתמש אחד.</item>
+ </plurals>
<string name="user_remove_user_title" msgid="4681256956076895559">"האם להסיר את המשתמש?"</string>
<string name="user_remove_user_message" msgid="1453218013959498039">"כל האפליקציות והנתונים של המשתמש הזה יימחקו."</string>
<string name="user_remove_user_remove" msgid="7479275741742178297">"הסר"</string>
@@ -742,8 +746,7 @@
<string name="left_icon" msgid="3096287125959387541">"סמל שמאלי"</string>
<string name="right_icon" msgid="3952104823293824311">"סמל ימני"</string>
<string name="drag_to_add_tiles" msgid="230586591689084925">"יש ללחוץ ולגרור כדי להוסיף אריחים"</string>
- <!-- no translation found for drag_to_rearrange_tiles (4566074720193667473) -->
- <skip />
+ <string name="drag_to_rearrange_tiles" msgid="4566074720193667473">"יש ללחוץ ולגרור כדי לסדר מחדש את האריחים"</string>
<string name="drag_to_remove_tiles" msgid="3361212377437088062">"גרור לכאן כדי להסיר"</string>
<string name="drag_to_remove_disabled" msgid="2390968976638993382">"יש צורך בשישה אריחים לכל הפחות"</string>
<string name="qs_edit" msgid="2232596095725105230">"עריכה"</string>
diff --git a/packages/SystemUI/res/values-ja/strings.xml b/packages/SystemUI/res/values-ja/strings.xml
index b34a5b43a290..8377f0788118 100644
--- a/packages/SystemUI/res/values-ja/strings.xml
+++ b/packages/SystemUI/res/values-ja/strings.xml
@@ -428,9 +428,11 @@
<string name="user_logout_notification_action" msgid="1195428991423425062">"ユーザーをログアウト"</string>
<string name="user_add_user_title" msgid="4553596395824132638">"新しいユーザーを追加しますか?"</string>
<string name="user_add_user_message_short" msgid="2161624834066214559">"新しいユーザーを追加したら、そのユーザーは自分のスペースをセットアップする必要があります。\n\nすべてのユーザーは他のユーザーに代わってアプリを更新できます。"</string>
- <!-- no translation found for user_limit_reached_title (7374910700117359177) -->
- <skip />
- <!-- no translation found for user_limit_reached_message (1855040563671964242) -->
+ <string name="user_limit_reached_title" msgid="7374910700117359177">"ユーザー数が上限に達しました"</string>
+ <plurals name="user_limit_reached_message" formatted="false" msgid="1855040563671964242">
+ <item quantity="other">最大 <xliff:g id="COUNT">%d</xliff:g> 人のユーザーを追加できます。</item>
+ <item quantity="one">作成できるユーザーは 1 人のみです。</item>
+ </plurals>
<string name="user_remove_user_title" msgid="4681256956076895559">"ユーザーを削除しますか?"</string>
<string name="user_remove_user_message" msgid="1453218013959498039">"このユーザーのアプリとデータがすべて削除されます。"</string>
<string name="user_remove_user_remove" msgid="7479275741742178297">"削除"</string>
@@ -734,8 +736,7 @@
<string name="left_icon" msgid="3096287125959387541">"左アイコン"</string>
<string name="right_icon" msgid="3952104823293824311">"右アイコン"</string>
<string name="drag_to_add_tiles" msgid="230586591689084925">"タイルを追加するには押し続けながらドラッグ"</string>
- <!-- no translation found for drag_to_rearrange_tiles (4566074720193667473) -->
- <skip />
+ <string name="drag_to_rearrange_tiles" msgid="4566074720193667473">"タイルを並べ替えるには押し続けながらドラッグ"</string>
<string name="drag_to_remove_tiles" msgid="3361212377437088062">"削除するにはここにドラッグ"</string>
<string name="drag_to_remove_disabled" msgid="2390968976638993382">"タイルは 6 個以上必要"</string>
<string name="qs_edit" msgid="2232596095725105230">"編集"</string>
diff --git a/packages/SystemUI/res/values-ka/strings.xml b/packages/SystemUI/res/values-ka/strings.xml
index e490dac08a1f..fb880c72fe05 100644
--- a/packages/SystemUI/res/values-ka/strings.xml
+++ b/packages/SystemUI/res/values-ka/strings.xml
@@ -426,9 +426,11 @@
<string name="user_logout_notification_action" msgid="1195428991423425062">"მომხმარებლის გასვლა"</string>
<string name="user_add_user_title" msgid="4553596395824132638">"დაემატოს ახალი მომხმარებელი?"</string>
<string name="user_add_user_message_short" msgid="2161624834066214559">"ახალი მომხმარებლის დამატებისას, ამ მომხმარებელს საკუთარი სივრცის შექმნა მოუწევს.\n\nნებისმიერ მომხმარებელს შეუძლია აპები ყველა სხვა მომხმარებლისათვის განაახლოს."</string>
- <!-- no translation found for user_limit_reached_title (7374910700117359177) -->
- <skip />
- <!-- no translation found for user_limit_reached_message (1855040563671964242) -->
+ <string name="user_limit_reached_title" msgid="7374910700117359177">"მიღწეულია მომხმარებელთა ლიმიტი"</string>
+ <plurals name="user_limit_reached_message" formatted="false" msgid="1855040563671964242">
+ <item quantity="other">შესაძლებელია <xliff:g id="COUNT">%d</xliff:g>-მდე მომხმარებლის დამატება.</item>
+ <item quantity="one">შესაძლებელია მხოლოდ ერთი მომხმარებლის შექმნა.</item>
+ </plurals>
<string name="user_remove_user_title" msgid="4681256956076895559">"გსურთ მომხმარებლის წაშლა?"</string>
<string name="user_remove_user_message" msgid="1453218013959498039">"ამ მომხმარებლის ყველა აპი და მონაცემი წაიშლება."</string>
<string name="user_remove_user_remove" msgid="7479275741742178297">"წაშლა"</string>
@@ -732,8 +734,7 @@
<string name="left_icon" msgid="3096287125959387541">"მარცხენა ხატულა"</string>
<string name="right_icon" msgid="3952104823293824311">"მარჯვენა ხატულა"</string>
<string name="drag_to_add_tiles" msgid="230586591689084925">"ჩავლებით გადაიტანეთ ბლოკების დასამატებლად"</string>
- <!-- no translation found for drag_to_rearrange_tiles (4566074720193667473) -->
- <skip />
+ <string name="drag_to_rearrange_tiles" msgid="4566074720193667473">"ფილების გადაწყობა შეგიძლიათ მათი ჩავლებით გადატანით"</string>
<string name="drag_to_remove_tiles" msgid="3361212377437088062">"ამოსაშლელად, ჩავლებით გადმოიტანეთ აქ"</string>
<string name="drag_to_remove_disabled" msgid="2390968976638993382">"გჭირდებათ მინიმუმ 6 ბლოკი"</string>
<string name="qs_edit" msgid="2232596095725105230">"რედაქტირება"</string>
diff --git a/packages/SystemUI/res/values-kk/strings.xml b/packages/SystemUI/res/values-kk/strings.xml
index eb50c28b9037..6e372d754a91 100644
--- a/packages/SystemUI/res/values-kk/strings.xml
+++ b/packages/SystemUI/res/values-kk/strings.xml
@@ -426,9 +426,11 @@
<string name="user_logout_notification_action" msgid="1195428991423425062">"ПАЙДАЛАНУШЫНЫ ШЫҒАРУ"</string>
<string name="user_add_user_title" msgid="4553596395824132638">"Жаңа пайдаланушы қосылсын ба?"</string>
<string name="user_add_user_message_short" msgid="2161624834066214559">"Жаңа пайдаланушыны қосқанда, сол адам өз кеңістігін реттеуі керек.\n\nКез келген пайдаланушы барлық басқа пайдаланушылар үшін қолданбаларды жаңарта алады."</string>
- <!-- no translation found for user_limit_reached_title (7374910700117359177) -->
- <skip />
- <!-- no translation found for user_limit_reached_message (1855040563671964242) -->
+ <string name="user_limit_reached_title" msgid="7374910700117359177">"Пайдаланушылар саны шегіне жетті"</string>
+ <plurals name="user_limit_reached_message" formatted="false" msgid="1855040563671964242">
+ <item quantity="other"><xliff:g id="COUNT">%d</xliff:g> пайдаланушыға дейін енгізуге болады.</item>
+ <item quantity="one">Тек бір пайдаланушыны жасауға болады.</item>
+ </plurals>
<string name="user_remove_user_title" msgid="4681256956076895559">"Пайдаланушы жойылсын ба?"</string>
<string name="user_remove_user_message" msgid="1453218013959498039">"Осы пайдаланушының барлық қолданбалары мен деректері жойылады."</string>
<string name="user_remove_user_remove" msgid="7479275741742178297">"Жою"</string>
@@ -732,8 +734,7 @@
<string name="left_icon" msgid="3096287125959387541">"Сол жақ белгіше"</string>
<string name="right_icon" msgid="3952104823293824311">"Оң жақ белгіше"</string>
<string name="drag_to_add_tiles" msgid="230586591689084925">"Қажетті элементтерді сүйреп әкеліп қойыңыз"</string>
- <!-- no translation found for drag_to_rearrange_tiles (4566074720193667473) -->
- <skip />
+ <string name="drag_to_rearrange_tiles" msgid="4566074720193667473">"Бөлшектердің ретін өзгерту үшін оны басып тұрып сүйреңіз"</string>
<string name="drag_to_remove_tiles" msgid="3361212377437088062">"Керексіздерін осы жерге сүйреңіз"</string>
<string name="drag_to_remove_disabled" msgid="2390968976638993382">"Кемінде 6 бөлшек қажет"</string>
<string name="qs_edit" msgid="2232596095725105230">"Өңдеу"</string>
diff --git a/packages/SystemUI/res/values-km/strings.xml b/packages/SystemUI/res/values-km/strings.xml
index 4f1d71d9f62d..eb9ed6132011 100644
--- a/packages/SystemUI/res/values-km/strings.xml
+++ b/packages/SystemUI/res/values-km/strings.xml
@@ -426,9 +426,11 @@
<string name="user_logout_notification_action" msgid="1195428991423425062">"ចុះឈ្មោះអ្នកប្រើចេញ"</string>
<string name="user_add_user_title" msgid="4553596395824132638">"បន្ថែម​អ្នកប្រើ​ថ្មី?"</string>
<string name="user_add_user_message_short" msgid="2161624834066214559">"ពេល​អ្នក​បន្ថែម​អ្នកប្រើ​ថ្មី អ្នកប្រើ​នោះ​ត្រូវ​កំណត់​ទំហំ​ផ្ទាល់​របស់​គេ។\n\nអ្នក​ប្រើ​ណាមួយ​ក៏​អាច​ធ្វើ​បច្ចុប្បន្នភាព​កម្មវិធី​សម្រាប់​អ្នកប្រើ​ផ្សេង​បាន​ដែរ។"</string>
- <!-- no translation found for user_limit_reached_title (7374910700117359177) -->
- <skip />
- <!-- no translation found for user_limit_reached_message (1855040563671964242) -->
+ <string name="user_limit_reached_title" msgid="7374910700117359177">"​បាន​ឈាន​ដល់ចំនួន​កំណត់អ្នកប្រើប្រាស់"</string>
+ <plurals name="user_limit_reached_message" formatted="false" msgid="1855040563671964242">
+ <item quantity="other">អ្នកអាចបញ្ចូល​អ្នក​ប្រើប្រាស់បាន​រហូតដល់ <xliff:g id="COUNT">%d</xliff:g> នាក់។</item>
+ <item quantity="one">អាច​បង្កើត​អ្នក​ប្រើប្រាស់​បាន​​តែម្នាក់ប៉ុណ្ណោះ។</item>
+ </plurals>
<string name="user_remove_user_title" msgid="4681256956076895559">"យកអ្នកប្រើចេញ?"</string>
<string name="user_remove_user_message" msgid="1453218013959498039">"កម្មវិធី និងទិន្នន័យទាំងអស់របស់អ្នកប្រើនេះនឹងត្រូវបានលុប។"</string>
<string name="user_remove_user_remove" msgid="7479275741742178297">"យកចេញ"</string>
@@ -732,8 +734,7 @@
<string name="left_icon" msgid="3096287125959387541">"រូបតំណាង​ខាង​ឆ្វេង"</string>
<string name="right_icon" msgid="3952104823293824311">"រូបតំណាង​ខាង​ស្ដាំ"</string>
<string name="drag_to_add_tiles" msgid="230586591689084925">"ចុច​ឱ្យ​ជាប់ រួចអូសដើម្បី​បញ្ចូល​ប្រអប់"</string>
- <!-- no translation found for drag_to_rearrange_tiles (4566074720193667473) -->
- <skip />
+ <string name="drag_to_rearrange_tiles" msgid="4566074720193667473">"ចុច​ឱ្យ​ជាប់ រួចអូស​ដើម្បី​រៀបចំ​ប្រអប់​ឡើងវិញ"</string>
<string name="drag_to_remove_tiles" msgid="3361212377437088062">"អូសទីនេះដើម្បីយកចេញ"</string>
<string name="drag_to_remove_disabled" msgid="2390968976638993382">"អ្នកត្រូវការប្រអប់​យ៉ាងតិច 6"</string>
<string name="qs_edit" msgid="2232596095725105230">"កែសម្រួល"</string>
diff --git a/packages/SystemUI/res/values-kn/strings.xml b/packages/SystemUI/res/values-kn/strings.xml
index 49a9419b61e6..c63dbe9f63b8 100644
--- a/packages/SystemUI/res/values-kn/strings.xml
+++ b/packages/SystemUI/res/values-kn/strings.xml
@@ -426,9 +426,11 @@
<string name="user_logout_notification_action" msgid="1195428991423425062">"ಬಳಕೆದಾರರನ್ನು ಲಾಗ್ಔಟ್ ಮಾಡಿ"</string>
<string name="user_add_user_title" msgid="4553596395824132638">"ಹೊಸ ಬಳಕೆದಾರರನ್ನು ಸೇರಿಸುವುದೇ?"</string>
<string name="user_add_user_message_short" msgid="2161624834066214559">"ನೀವು ಒಬ್ಬ ಹೊಸ ಬಳಕೆದಾರರನ್ನು ಸೇರಿಸಿದಾಗ, ಆ ವ್ಯಕ್ತಿಯು ಅವರ ಸ್ಥಳವನ್ನು ಸ್ಥಾಪಿಸಬೇಕಾಗುತ್ತದೆ.\n\nಯಾವುದೇ ಬಳಕೆದಾರರು ಎಲ್ಲಾ ಇತರೆ ಬಳಕೆದಾರರಿಗಾಗಿ ಅಪ್ಲಿಕೇಶನ್‌ಗಳನ್ನು ಅಪ್‌ಡೇಟ್‌ ಮಾಡಬಹುದು."</string>
- <!-- no translation found for user_limit_reached_title (7374910700117359177) -->
- <skip />
- <!-- no translation found for user_limit_reached_message (1855040563671964242) -->
+ <string name="user_limit_reached_title" msgid="7374910700117359177">"ಬಳಕೆದಾರರ ಮಿತಿ ತಲುಪಿದೆ"</string>
+ <plurals name="user_limit_reached_message" formatted="false" msgid="1855040563671964242">
+ <item quantity="one">ನೀವು <xliff:g id="COUNT">%d</xliff:g> ಬಳಕೆದಾರರವರೆಗೆ ಸೇರಿಸಬಹುದು.</item>
+ <item quantity="other">ನೀವು <xliff:g id="COUNT">%d</xliff:g> ಬಳಕೆದಾರರವರೆಗೆ ಸೇರಿಸಬಹುದು.</item>
+ </plurals>
<string name="user_remove_user_title" msgid="4681256956076895559">"ಬಳಕೆದಾರರನ್ನು ತೆಗೆದುಹಾಕುವುದೇ?"</string>
<string name="user_remove_user_message" msgid="1453218013959498039">"ಈ ಬಳಕೆದಾರರ ಎಲ್ಲಾ ಅಪ್ಲಿಕೇಶನ್‌ಗಳು ಮತ್ತು ಡೇಟಾವನ್ನು ಅಳಿಸಲಾಗುವುದು."</string>
<string name="user_remove_user_remove" msgid="7479275741742178297">"ತೆಗೆದುಹಾಕಿ"</string>
@@ -732,8 +734,7 @@
<string name="left_icon" msgid="3096287125959387541">"ಎಡ ಐಕಾನ್"</string>
<string name="right_icon" msgid="3952104823293824311">"ಬಲ ಐಕಾನ್"</string>
<string name="drag_to_add_tiles" msgid="230586591689084925">"ಟೈಲ್‌ಗಳನ್ನು ಸೇರಿಸಲು ಹೋಲ್ಡ್‌ ಮಾಡಿ ಮತ್ತು ಡ್ರ್ಯಾಗ್‌ ಮಾಡಿ"</string>
- <!-- no translation found for drag_to_rearrange_tiles (4566074720193667473) -->
- <skip />
+ <string name="drag_to_rearrange_tiles" msgid="4566074720193667473">"ಟೈಲ್‌ಗಳನ್ನು ಮರುಹೊಂದಿಸಲು ಹೋಲ್ಡ್‌ ಮಾಡಿ ಮತ್ತು ಡ್ರ್ಯಾಗ್‌ ಮಾಡಿ"</string>
<string name="drag_to_remove_tiles" msgid="3361212377437088062">"ತೆಗೆದುಹಾಕಲು ಇಲ್ಲಿ ಡ್ರ್ಯಾಗ್‌ ಮಾಡಿ"</string>
<string name="drag_to_remove_disabled" msgid="2390968976638993382">"ನಿಮಗೆ ಕನಿಷ್ಠ 6 ಟೈಲ್‌ಗಳ ಅಗತ್ಯವಿದೆ"</string>
<string name="qs_edit" msgid="2232596095725105230">"ಎಡಿಟ್"</string>
diff --git a/packages/SystemUI/res/values-ko/strings.xml b/packages/SystemUI/res/values-ko/strings.xml
index ad98bce5bd8e..77c983ed0532 100644
--- a/packages/SystemUI/res/values-ko/strings.xml
+++ b/packages/SystemUI/res/values-ko/strings.xml
@@ -428,9 +428,11 @@
<string name="user_logout_notification_action" msgid="1195428991423425062">"사용자 로그아웃"</string>
<string name="user_add_user_title" msgid="4553596395824132638">"새 사용자를 추가할까요?"</string>
<string name="user_add_user_message_short" msgid="2161624834066214559">"추가된 새로운 사용자는 자신의 공간을 설정해야 합니다.\n\n모든 사용자는 다른 사용자들을 위하여 앱을 업데이트할 수 있습니다."</string>
- <!-- no translation found for user_limit_reached_title (7374910700117359177) -->
- <skip />
- <!-- no translation found for user_limit_reached_message (1855040563671964242) -->
+ <string name="user_limit_reached_title" msgid="7374910700117359177">"사용자 제한 도달"</string>
+ <plurals name="user_limit_reached_message" formatted="false" msgid="1855040563671964242">
+ <item quantity="other">사용자를 <xliff:g id="COUNT">%d</xliff:g>명까지 추가할 수 있습니다.</item>
+ <item quantity="one">사용자를 한 명만 만들 수 있습니다.</item>
+ </plurals>
<string name="user_remove_user_title" msgid="4681256956076895559">"사용자를 삭제할까요?"</string>
<string name="user_remove_user_message" msgid="1453218013959498039">"이 사용자의 모든 앱과 데이터가 삭제됩니다."</string>
<string name="user_remove_user_remove" msgid="7479275741742178297">"삭제"</string>
@@ -734,8 +736,7 @@
<string name="left_icon" msgid="3096287125959387541">"왼쪽 아이콘"</string>
<string name="right_icon" msgid="3952104823293824311">"오른쪽 아이콘"</string>
<string name="drag_to_add_tiles" msgid="230586591689084925">"길게 터치하고 드래그하여 타일 추가"</string>
- <!-- no translation found for drag_to_rearrange_tiles (4566074720193667473) -->
- <skip />
+ <string name="drag_to_rearrange_tiles" msgid="4566074720193667473">"길게 터치하고 드래그하여 타일을 다시 정렬"</string>
<string name="drag_to_remove_tiles" msgid="3361212377437088062">"여기로 드래그하여 삭제"</string>
<string name="drag_to_remove_disabled" msgid="2390968976638993382">"6개 이상의 타일이 필요합니다."</string>
<string name="qs_edit" msgid="2232596095725105230">"수정"</string>
diff --git a/packages/SystemUI/res/values-ky/strings.xml b/packages/SystemUI/res/values-ky/strings.xml
index 0bbdc916694a..e334da40fd4d 100644
--- a/packages/SystemUI/res/values-ky/strings.xml
+++ b/packages/SystemUI/res/values-ky/strings.xml
@@ -426,9 +426,11 @@
<string name="user_logout_notification_action" msgid="1195428991423425062">"КОЛДОНУУЧУНУ ТУТУМДАН ЧЫГАРУУ"</string>
<string name="user_add_user_title" msgid="4553596395824132638">"Жаңы колдонуучу кошосузбу?"</string>
<string name="user_add_user_message_short" msgid="2161624834066214559">"Жаңы колдонуучу кошулганда, ал өз мейкиндигин түзүп алышы керек.\n\nКолдонмолорду бир колдонуучу жаңыртканда, ал калган бардык колдонуучулар үчүн да жаңырат."</string>
- <!-- no translation found for user_limit_reached_title (7374910700117359177) -->
- <skip />
- <!-- no translation found for user_limit_reached_message (1855040563671964242) -->
+ <string name="user_limit_reached_title" msgid="7374910700117359177">"Дагы колдонуучу кошууга болбойт"</string>
+ <plurals name="user_limit_reached_message" formatted="false" msgid="1855040563671964242">
+ <item quantity="other"><xliff:g id="COUNT">%d</xliff:g> колдонуучуга чейин кошууга болот.</item>
+ <item quantity="one">Бир колдонуучуну гана кошууга болот.</item>
+ </plurals>
<string name="user_remove_user_title" msgid="4681256956076895559">"Колдонуучу алынып салынсынбы?"</string>
<string name="user_remove_user_message" msgid="1453218013959498039">"Бул колдонуучунун бардык колдонмолору жана дайындары жок кылынат."</string>
<string name="user_remove_user_remove" msgid="7479275741742178297">"Алып салуу"</string>
@@ -732,8 +734,7 @@
<string name="left_icon" msgid="3096287125959387541">"Сол жактагы сүрөтчө"</string>
<string name="right_icon" msgid="3952104823293824311">"Оң жактагы сүрөтчө"</string>
<string name="drag_to_add_tiles" msgid="230586591689084925">"Керектүү элементтерди сүйрөп келиңиз"</string>
- <!-- no translation found for drag_to_rearrange_tiles (4566074720193667473) -->
- <skip />
+ <string name="drag_to_rearrange_tiles" msgid="4566074720193667473">"Мозаикаларды иреттөө үчүн кармап туруп, сүйрөңүз"</string>
<string name="drag_to_remove_tiles" msgid="3361212377437088062">"Алып салуу үчүн бул жерге сүйрөңүз"</string>
<string name="drag_to_remove_disabled" msgid="2390968976638993382">"Сизге жок дегенде 6 мозаика керек"</string>
<string name="qs_edit" msgid="2232596095725105230">"Түзөтүү"</string>
diff --git a/packages/SystemUI/res/values-lo/strings.xml b/packages/SystemUI/res/values-lo/strings.xml
index 12c67dbed30c..56f9e1db06d3 100644
--- a/packages/SystemUI/res/values-lo/strings.xml
+++ b/packages/SystemUI/res/values-lo/strings.xml
@@ -426,9 +426,11 @@
<string name="user_logout_notification_action" msgid="1195428991423425062">"ເອົາຜູ້ໃຊ້ອອກຈາກລະບົບ"</string>
<string name="user_add_user_title" msgid="4553596395824132638">"ເພີ່ມຜູ້ໃຊ້ໃໝ່ບໍ?"</string>
<string name="user_add_user_message_short" msgid="2161624834066214559">"ເມື່ອ​ທ່ານ​ເພີ່ມ​ຜູ້ໃຊ້​ໃໝ່, ຜູ້ໃຊ້​ນັ້ນ​ຈະ​ຕ້ອງ​ຕັ້ງ​ຄ່າ​ພື້ນ​ທີ່​ບ່ອນ​ຈັດ​ເກັບ​ຂໍ້​ມູນ​ຂອງ​ລາວ.\n\nຜູ້ໃຊ້​ທຸກ​ຄົນ​ສາ​ມາດ​ອັບ​ເດດ​ແອັບຯຂອງ​ຜູ້​ໃຊ້​ຄົນ​ອື່ນ​ທັງ​ໝົດ​ໄດ້."</string>
- <!-- no translation found for user_limit_reached_title (7374910700117359177) -->
- <skip />
- <!-- no translation found for user_limit_reached_message (1855040563671964242) -->
+ <string name="user_limit_reached_title" msgid="7374910700117359177">"ຮອດຂີດຈຳກັດຜູ້ໃຊ້ແລ້ວ"</string>
+ <plurals name="user_limit_reached_message" formatted="false" msgid="1855040563671964242">
+ <item quantity="other">ທ່ານສາມາດເພີ່ມໄດ້ສູງສຸດ <xliff:g id="COUNT">%d</xliff:g> ຄົນ.</item>
+ <item quantity="one">ສາມາດສ້າງໄດ້ໜຶ່ງຜູ້ໃຊ້ເທົ່ານັ້ນ.</item>
+ </plurals>
<string name="user_remove_user_title" msgid="4681256956076895559">"ລຶບຜູ້ໃຊ້ອອກບໍ?"</string>
<string name="user_remove_user_message" msgid="1453218013959498039">"ທຸກ​ແອັບ ແລະ ຂໍ້​ມູນ​ຂອງ​ຜູ້​ໃຊ້​ນີ້​ຈະ​ຖືກ​ລຶບ."</string>
<string name="user_remove_user_remove" msgid="7479275741742178297">"ເອົາ​ອອກ"</string>
@@ -732,8 +734,7 @@
<string name="left_icon" msgid="3096287125959387541">"ໄອຄອນຊ້າຍ"</string>
<string name="right_icon" msgid="3952104823293824311">"ໄອຄອນຂວາ"</string>
<string name="drag_to_add_tiles" msgid="230586591689084925">"ກົດຄ້າງໄວ້ແລ້ວລາກເພື່ອເພີ່ມຊ່ອງ"</string>
- <!-- no translation found for drag_to_rearrange_tiles (4566074720193667473) -->
- <skip />
+ <string name="drag_to_rearrange_tiles" msgid="4566074720193667473">"ກົດຄ້າງໄວ້ແລ້ວລາກເພື່ອຈັດຮຽງໃໝ່"</string>
<string name="drag_to_remove_tiles" msgid="3361212377437088062">"ລາກມາບ່ອນນີ້ເພື່ອລຶບອອກ"</string>
<string name="drag_to_remove_disabled" msgid="2390968976638993382">"ທ່ານຍຕ້ອງໃຊ້ຢ່າງໜ້ອຍ 6 ຊ່ອງ"</string>
<string name="qs_edit" msgid="2232596095725105230">"ແກ້ໄຂ"</string>
diff --git a/packages/SystemUI/res/values-lt/strings.xml b/packages/SystemUI/res/values-lt/strings.xml
index f59b1adf3674..b8ae38b3dfaa 100644
--- a/packages/SystemUI/res/values-lt/strings.xml
+++ b/packages/SystemUI/res/values-lt/strings.xml
@@ -432,9 +432,13 @@
<string name="user_logout_notification_action" msgid="1195428991423425062">"ATJUNGTI NAUDOTOJĄ"</string>
<string name="user_add_user_title" msgid="4553596395824132638">"Pridėti naują naudotoją?"</string>
<string name="user_add_user_message_short" msgid="2161624834066214559">"Kai pridedate naują naudotoją, šis asmuo turi nustatyti savo erdvę.\n\nBet kuris naudotojas gali atnaujinti visų kitų naudotojų programas."</string>
- <!-- no translation found for user_limit_reached_title (7374910700117359177) -->
- <skip />
- <!-- no translation found for user_limit_reached_message (1855040563671964242) -->
+ <string name="user_limit_reached_title" msgid="7374910700117359177">"Pasiekta naudotojų riba"</string>
+ <plurals name="user_limit_reached_message" formatted="false" msgid="1855040563671964242">
+ <item quantity="one">Galite pridėti iki <xliff:g id="COUNT">%d</xliff:g> naudotojo.</item>
+ <item quantity="few">Galite pridėti iki <xliff:g id="COUNT">%d</xliff:g> naudotojų.</item>
+ <item quantity="many">Galite pridėti iki <xliff:g id="COUNT">%d</xliff:g> naudotojo.</item>
+ <item quantity="other">Galite pridėti iki <xliff:g id="COUNT">%d</xliff:g> naudotojų.</item>
+ </plurals>
<string name="user_remove_user_title" msgid="4681256956076895559">"Pašalinti naudotoją?"</string>
<string name="user_remove_user_message" msgid="1453218013959498039">"Bus ištrinti visi šio naudotojo duomenys ir programos."</string>
<string name="user_remove_user_remove" msgid="7479275741742178297">"Pašalinti"</string>
@@ -742,8 +746,7 @@
<string name="left_icon" msgid="3096287125959387541">"Piktograma kairėje"</string>
<string name="right_icon" msgid="3952104823293824311">"Piktograma dešinėje"</string>
<string name="drag_to_add_tiles" msgid="230586591689084925">"Jei norite pridėti išklotinių, laikykite nuspaudę ir vilkite"</string>
- <!-- no translation found for drag_to_rearrange_tiles (4566074720193667473) -->
- <skip />
+ <string name="drag_to_rearrange_tiles" msgid="4566074720193667473">"Norėdami pertvarkyti išklot., laikykite nuspaudę ir vilkite"</string>
<string name="drag_to_remove_tiles" msgid="3361212377437088062">"Vilkite čia, jei norite pašalinti"</string>
<string name="drag_to_remove_disabled" msgid="2390968976638993382">"Turi būti bent 6 išklotinės"</string>
<string name="qs_edit" msgid="2232596095725105230">"Redaguoti"</string>
diff --git a/packages/SystemUI/res/values-lv/strings.xml b/packages/SystemUI/res/values-lv/strings.xml
index 007509416ab3..4a0ee10229ed 100644
--- a/packages/SystemUI/res/values-lv/strings.xml
+++ b/packages/SystemUI/res/values-lv/strings.xml
@@ -429,9 +429,12 @@
<string name="user_logout_notification_action" msgid="1195428991423425062">"ATTEIKT LIETOTĀJU"</string>
<string name="user_add_user_title" msgid="4553596395824132638">"Vai pievienot jaunu lietotāju?"</string>
<string name="user_add_user_message_short" msgid="2161624834066214559">"Kad pievienosiet jaunu lietotāju, viņam būs jāizveido savs profils.\n\nIkviens lietotājs var atjaunināt lietotnes citu lietotāju vietā."</string>
- <!-- no translation found for user_limit_reached_title (7374910700117359177) -->
- <skip />
- <!-- no translation found for user_limit_reached_message (1855040563671964242) -->
+ <string name="user_limit_reached_title" msgid="7374910700117359177">"Sasniegts lietotāju ierobežojums"</string>
+ <plurals name="user_limit_reached_message" formatted="false" msgid="1855040563671964242">
+ <item quantity="zero">Varat pievienot ne vairāk kā <xliff:g id="COUNT">%d</xliff:g> lietotājus.</item>
+ <item quantity="one">Varat pievienot ne vairāk kā <xliff:g id="COUNT">%d</xliff:g> lietotāju.</item>
+ <item quantity="other">Varat pievienot ne vairāk kā <xliff:g id="COUNT">%d</xliff:g> lietotājus.</item>
+ </plurals>
<string name="user_remove_user_title" msgid="4681256956076895559">"Vai noņemt lietotāju?"</string>
<string name="user_remove_user_message" msgid="1453218013959498039">"Tiks dzēstas visas šī lietotāja lietotnes un dati."</string>
<string name="user_remove_user_remove" msgid="7479275741742178297">"Noņemt"</string>
@@ -737,8 +740,7 @@
<string name="left_icon" msgid="3096287125959387541">"Ikona kreisajā pusē"</string>
<string name="right_icon" msgid="3952104823293824311">"Ikona labajā pusē"</string>
<string name="drag_to_add_tiles" msgid="230586591689084925">"Lai pievienotu elementus, pieturiet tos un velciet"</string>
- <!-- no translation found for drag_to_rearrange_tiles (4566074720193667473) -->
- <skip />
+ <string name="drag_to_rearrange_tiles" msgid="4566074720193667473">"Lai pārkārtotu elementus, turiet un velciet tos"</string>
<string name="drag_to_remove_tiles" msgid="3361212377437088062">"Lai noņemtu vienumus, velciet tos šeit."</string>
<string name="drag_to_remove_disabled" msgid="2390968976638993382">"Nepieciešami vismaz 6 elementi"</string>
<string name="qs_edit" msgid="2232596095725105230">"Rediģēt"</string>
diff --git a/packages/SystemUI/res/values-mk/strings.xml b/packages/SystemUI/res/values-mk/strings.xml
index 68dc653e644f..bf9cc35fa9fe 100644
--- a/packages/SystemUI/res/values-mk/strings.xml
+++ b/packages/SystemUI/res/values-mk/strings.xml
@@ -426,9 +426,11 @@
<string name="user_logout_notification_action" msgid="1195428991423425062">"ОДЈАВИ ГО КОРИСНИКОТ"</string>
<string name="user_add_user_title" msgid="4553596395824132638">"Да се додаде нов корисник?"</string>
<string name="user_add_user_message_short" msgid="2161624834066214559">"Кога додавате нов корисник, тоа лице треба да го постави својот простор.\n\nСекој корисник може да ажурира апликации за сите други корисници."</string>
- <!-- no translation found for user_limit_reached_title (7374910700117359177) -->
- <skip />
- <!-- no translation found for user_limit_reached_message (1855040563671964242) -->
+ <string name="user_limit_reached_title" msgid="7374910700117359177">"Достигнато ограничување на корисник"</string>
+ <plurals name="user_limit_reached_message" formatted="false" msgid="1855040563671964242">
+ <item quantity="one">Може да додадете најмногу <xliff:g id="COUNT">%d</xliff:g> корисник.</item>
+ <item quantity="other">Може да додадете најмногу <xliff:g id="COUNT">%d</xliff:g> корисници.</item>
+ </plurals>
<string name="user_remove_user_title" msgid="4681256956076895559">"Да се отстрани корисникот?"</string>
<string name="user_remove_user_message" msgid="1453218013959498039">"Сите апликации и податоци од овој корисник ќе се избришат."</string>
<string name="user_remove_user_remove" msgid="7479275741742178297">"Отстрани"</string>
@@ -732,8 +734,7 @@
<string name="left_icon" msgid="3096287125959387541">"Лева икона"</string>
<string name="right_icon" msgid="3952104823293824311">"Десна икона"</string>
<string name="drag_to_add_tiles" msgid="230586591689084925">"Задржете и влечете за да додадете плочки"</string>
- <!-- no translation found for drag_to_rearrange_tiles (4566074720193667473) -->
- <skip />
+ <string name="drag_to_rearrange_tiles" msgid="4566074720193667473">"Задржете и влечете за да ги преуредите плочките"</string>
<string name="drag_to_remove_tiles" msgid="3361212377437088062">"Повлечете тука за да се отстрани"</string>
<string name="drag_to_remove_disabled" msgid="2390968976638993382">"Потребни ви се најмалку 6 плочки"</string>
<string name="qs_edit" msgid="2232596095725105230">"Измени"</string>
diff --git a/packages/SystemUI/res/values-ml/strings.xml b/packages/SystemUI/res/values-ml/strings.xml
index 507cbbf34d4c..fefd073eb75f 100644
--- a/packages/SystemUI/res/values-ml/strings.xml
+++ b/packages/SystemUI/res/values-ml/strings.xml
@@ -426,9 +426,11 @@
<string name="user_logout_notification_action" msgid="1195428991423425062">"ഉപയോക്താവിനെ ലോഗൗട്ട് ചെയ്യുക"</string>
<string name="user_add_user_title" msgid="4553596395824132638">"പുതിയ ഉപയോക്താവിനെ ചേർക്കണോ?"</string>
<string name="user_add_user_message_short" msgid="2161624834066214559">"നിങ്ങൾ ഒരു പുതിയ ഉപയോക്താവിനെ ചേർക്കുമ്പോൾ, ആ വ്യക്തിക്ക് അവരുടെ ഇടം സജ്ജീകരിക്കേണ്ടതുണ്ട്.\n\nമറ്റ് എല്ലാ ഉപയോക്താക്കൾക്കുമായി ഏതൊരു ഉപയോക്താവിനും അപ്ലിക്കേഷനുകൾ അപ്‌ഡേറ്റ് ചെയ്യാനാവും."</string>
- <!-- no translation found for user_limit_reached_title (7374910700117359177) -->
- <skip />
- <!-- no translation found for user_limit_reached_message (1855040563671964242) -->
+ <string name="user_limit_reached_title" msgid="7374910700117359177">"ഉപയോക്തൃ പരിധി എത്തി"</string>
+ <plurals name="user_limit_reached_message" formatted="false" msgid="1855040563671964242">
+ <item quantity="other">നിങ്ങൾക്ക് <xliff:g id="COUNT">%d</xliff:g> ഉപയോക്താക്കളെ വരെ ചേർക്കാനാവും.</item>
+ <item quantity="one">ഒരു ഉപയോക്താവിന് മാത്രമേ സൃഷ്‌ടിക്കാനാവൂ.</item>
+ </plurals>
<string name="user_remove_user_title" msgid="4681256956076895559">"ഉപയോക്താവിനെ ഇല്ലാതാക്കണോ?"</string>
<string name="user_remove_user_message" msgid="1453218013959498039">"ഈ ഉപയോക്താവിന്റെ എല്ലാ ആപ്സും ഡാറ്റയും ഇല്ലാതാക്കും."</string>
<string name="user_remove_user_remove" msgid="7479275741742178297">"നീക്കംചെയ്യുക"</string>
@@ -732,8 +734,7 @@
<string name="left_icon" msgid="3096287125959387541">"ഇടതുവശത്തെ ചിഹ്നം"</string>
<string name="right_icon" msgid="3952104823293824311">"വലതുവശത്തെ ചിഹ്നം"</string>
<string name="drag_to_add_tiles" msgid="230586591689084925">"ടൈലുകൾ ചേർക്കാൻ ക്ലിക്ക് ചെയ്ത് ഇഴയ്‌ക്കുക"</string>
- <!-- no translation found for drag_to_rearrange_tiles (4566074720193667473) -->
- <skip />
+ <string name="drag_to_rearrange_tiles" msgid="4566074720193667473">"ടൈലുകൾ പുനഃക്രമീകരിക്കാൻ അമർത്തിപ്പിടിച്ച് വലിച്ചിടുക"</string>
<string name="drag_to_remove_tiles" msgid="3361212377437088062">"നീക്കംചെയ്യുന്നതിന് ഇവിടെ വലിച്ചിടുക"</string>
<string name="drag_to_remove_disabled" msgid="2390968976638993382">"നിങ്ങൾക്ക് ചുരുങ്ങിയത് 6 ടൈലുകൾ വേണം"</string>
<string name="qs_edit" msgid="2232596095725105230">"എഡിറ്റുചെയ്യുക"</string>
diff --git a/packages/SystemUI/res/values-mn/strings.xml b/packages/SystemUI/res/values-mn/strings.xml
index 8e27efe06ee6..e86dc64cd9e8 100644
--- a/packages/SystemUI/res/values-mn/strings.xml
+++ b/packages/SystemUI/res/values-mn/strings.xml
@@ -424,9 +424,11 @@
<string name="user_logout_notification_action" msgid="1195428991423425062">"ХЭРЭГЛЭГЧЭЭС ГАРАХ"</string>
<string name="user_add_user_title" msgid="4553596395824132638">"Шинэ хэрэглэгч нэмэх үү?"</string>
<string name="user_add_user_message_short" msgid="2161624834066214559">"Та шинэ хэрэглэгч нэмбэл тухайн хүн өөрийн профайлыг тохируулах шаардлагатай.\n\nАль ч хэрэглэгч бүх хэрэглэгчийн апп-уудыг шинэчлэх боломжтой."</string>
- <!-- no translation found for user_limit_reached_title (7374910700117359177) -->
- <skip />
- <!-- no translation found for user_limit_reached_message (1855040563671964242) -->
+ <string name="user_limit_reached_title" msgid="7374910700117359177">"Хэрэглэгчийн хязгаарт хүрсэн"</string>
+ <plurals name="user_limit_reached_message" formatted="false" msgid="1855040563671964242">
+ <item quantity="other">Та <xliff:g id="COUNT">%d</xliff:g> хүртэлх хэрэглэгч нэмэх боломжтой.</item>
+ <item quantity="one">Зөвхөн нэг хэрэглэгч үүсгэх боломжтой.</item>
+ </plurals>
<string name="user_remove_user_title" msgid="4681256956076895559">"Хэрэглэгчийг устгах уу?"</string>
<string name="user_remove_user_message" msgid="1453218013959498039">"Энэ хэрэглэгчийн бүх апп болон мэдээлэл устах болно."</string>
<string name="user_remove_user_remove" msgid="7479275741742178297">"Арилгах"</string>
@@ -730,8 +732,7 @@
<string name="left_icon" msgid="3096287125959387541">"Зүүн дүрс тэмдэг"</string>
<string name="right_icon" msgid="3952104823293824311">"Баруун дүрс тэмдэг"</string>
<string name="drag_to_add_tiles" msgid="230586591689084925">"Хавтанд нэмэхийн тулд дараад чирэх"</string>
- <!-- no translation found for drag_to_rearrange_tiles (4566074720193667473) -->
- <skip />
+ <string name="drag_to_rearrange_tiles" msgid="4566074720193667473">"Хавтангуудыг дахин засварлахын тулд дараад чирнэ үү"</string>
<string name="drag_to_remove_tiles" msgid="3361212377437088062">"Устгахын тулд энд зөөнө үү"</string>
<string name="drag_to_remove_disabled" msgid="2390968976638993382">"Танд хамгийн багадаа 6 хавтан шаардлагатай"</string>
<string name="qs_edit" msgid="2232596095725105230">"Засах"</string>
diff --git a/packages/SystemUI/res/values-mr/strings.xml b/packages/SystemUI/res/values-mr/strings.xml
index 1c16dc23f7e8..a9f9af4a0804 100644
--- a/packages/SystemUI/res/values-mr/strings.xml
+++ b/packages/SystemUI/res/values-mr/strings.xml
@@ -426,9 +426,11 @@
<string name="user_logout_notification_action" msgid="1195428991423425062">"वापरकर्त्यास लॉगआउट करा"</string>
<string name="user_add_user_title" msgid="4553596395824132638">"नवीन वापरकर्ता जोडायचा?"</string>
<string name="user_add_user_message_short" msgid="2161624834066214559">"तुम्ही एक नवीन वापरकर्ता जोडता तेव्हा, त्या व्यक्तीने त्यांचे स्थान सेट करणे आवश्यक असते.\n\nकोणताही वापरकर्ता इतर सर्व वापरकर्त्यांसाठी अॅप्स अपडेट करू शकतो."</string>
- <!-- no translation found for user_limit_reached_title (7374910700117359177) -->
- <skip />
- <!-- no translation found for user_limit_reached_message (1855040563671964242) -->
+ <string name="user_limit_reached_title" msgid="7374910700117359177">"वापरकर्ता मर्यादा गाठली"</string>
+ <plurals name="user_limit_reached_message" formatted="false" msgid="1855040563671964242">
+ <item quantity="one">तुम्ही <xliff:g id="COUNT">%d</xliff:g> वापरकर्त्यापर्यंत जोडू शकता.</item>
+ <item quantity="other">तुम्ही <xliff:g id="COUNT">%d</xliff:g> वापरकर्त्यांपर्यंत जोडू शकता.</item>
+ </plurals>
<string name="user_remove_user_title" msgid="4681256956076895559">"वापरकर्त्यास काढायचे?"</string>
<string name="user_remove_user_message" msgid="1453218013959498039">"या वापरकर्त्याचे सर्व अॅप्स आणि डेटा काढून टाकला जाईल."</string>
<string name="user_remove_user_remove" msgid="7479275741742178297">"काढा"</string>
@@ -732,8 +734,7 @@
<string name="left_icon" msgid="3096287125959387541">"डावे आयकन"</string>
<string name="right_icon" msgid="3952104823293824311">"उजवे आयकन"</string>
<string name="drag_to_add_tiles" msgid="230586591689084925">"टाइल जोडण्यासाठी धरून ठेवा आणि ड्रॅग करा"</string>
- <!-- no translation found for drag_to_rearrange_tiles (4566074720193667473) -->
- <skip />
+ <string name="drag_to_rearrange_tiles" msgid="4566074720193667473">"टाइलची पुनर्रचना करण्यासाठी धरून ठेवा आणि ड्रॅग करा"</string>
<string name="drag_to_remove_tiles" msgid="3361212377437088062">"काढण्यासाठी येथे ड्रॅग करा"</string>
<string name="drag_to_remove_disabled" msgid="2390968976638993382">"तुम्हाला किमान ६ टाइलची गरज आहे"</string>
<string name="qs_edit" msgid="2232596095725105230">"संपादित करा"</string>
diff --git a/packages/SystemUI/res/values-ms/strings.xml b/packages/SystemUI/res/values-ms/strings.xml
index 947c0ff11742..6ec7889db372 100644
--- a/packages/SystemUI/res/values-ms/strings.xml
+++ b/packages/SystemUI/res/values-ms/strings.xml
@@ -426,9 +426,11 @@
<string name="user_logout_notification_action" msgid="1195428991423425062">"LOG KELUAR PENGGUNA"</string>
<string name="user_add_user_title" msgid="4553596395824132638">"Tambah pengguna baharu?"</string>
<string name="user_add_user_message_short" msgid="2161624834066214559">"Apabila anda menambah pengguna baharu, orang itu perlu menyediakan ruang mereka.\n\nMana-mana pengguna boleh mengemas kini apl untuk semua pengguna lain."</string>
- <!-- no translation found for user_limit_reached_title (7374910700117359177) -->
- <skip />
- <!-- no translation found for user_limit_reached_message (1855040563671964242) -->
+ <string name="user_limit_reached_title" msgid="7374910700117359177">"Had pengguna dicapai"</string>
+ <plurals name="user_limit_reached_message" formatted="false" msgid="1855040563671964242">
+ <item quantity="other">Anda boleh menambah sehingga <xliff:g id="COUNT">%d</xliff:g> pengguna.</item>
+ <item quantity="one">Hanya satu pengguna yang boleh dibuat.</item>
+ </plurals>
<string name="user_remove_user_title" msgid="4681256956076895559">"Alih keluar pengguna?"</string>
<string name="user_remove_user_message" msgid="1453218013959498039">"Semua apl dan data pengguna ini akan dipadamkan."</string>
<string name="user_remove_user_remove" msgid="7479275741742178297">"Alih keluar"</string>
@@ -732,8 +734,7 @@
<string name="left_icon" msgid="3096287125959387541">"Ikon kiri"</string>
<string name="right_icon" msgid="3952104823293824311">"Ikon kanan"</string>
<string name="drag_to_add_tiles" msgid="230586591689084925">"Tahan dan seret untuk menambah jubin"</string>
- <!-- no translation found for drag_to_rearrange_tiles (4566074720193667473) -->
- <skip />
+ <string name="drag_to_rearrange_tiles" msgid="4566074720193667473">"Tahan dan seret untuk mengatur semula jubin"</string>
<string name="drag_to_remove_tiles" msgid="3361212377437088062">"Seret ke sini untuk mengalih keluar"</string>
<string name="drag_to_remove_disabled" msgid="2390968976638993382">"Anda memerlukan sekurang-kurangnya 6 jubin"</string>
<string name="qs_edit" msgid="2232596095725105230">"Edit"</string>
diff --git a/packages/SystemUI/res/values-my/strings.xml b/packages/SystemUI/res/values-my/strings.xml
index 82642406f2ac..7afb3b9478e4 100644
--- a/packages/SystemUI/res/values-my/strings.xml
+++ b/packages/SystemUI/res/values-my/strings.xml
@@ -426,9 +426,11 @@
<string name="user_logout_notification_action" msgid="1195428991423425062">"အသုံးပြုသူ ထွက်လိုက်ပါ"</string>
<string name="user_add_user_title" msgid="4553596395824132638">"အသုံးပြုသူအသစ်ကို ထည့်မလား။"</string>
<string name="user_add_user_message_short" msgid="2161624834066214559">"သင်ထည့်လိုက်သော အသုံးပြုသူအသစ်သည် ၎င်း၏နေရာကို သတ်မှတ်စီစဉ်ရန် လိုအပ်သည်။\n\nမည်သည့်အသုံးပြုသူမဆို ကျန်သူများအားလုံးအတွက် အက်ပ်များကို အပ်ဒိတ်လုပ်ပေးနိုင်သည်။"</string>
- <!-- no translation found for user_limit_reached_title (7374910700117359177) -->
- <skip />
- <!-- no translation found for user_limit_reached_message (1855040563671964242) -->
+ <string name="user_limit_reached_title" msgid="7374910700117359177">"အသုံးပြုသူ အကန့်အသတ် ပြည့်သွားပါပြီ"</string>
+ <plurals name="user_limit_reached_message" formatted="false" msgid="1855040563671964242">
+ <item quantity="other">အသုံးပြုသူ <xliff:g id="COUNT">%d</xliff:g> ဦးအထိ ထည့်နိုင်သည်။</item>
+ <item quantity="one">အသုံးပြုသူ တစ်ဦးသာ ထည့်နိုင်သည်။</item>
+ </plurals>
<string name="user_remove_user_title" msgid="4681256956076895559">"သုံးစွဲသူကိုဖယ်ရှားမည်လား?"</string>
<string name="user_remove_user_message" msgid="1453218013959498039">"ဤအသုံးပြုသူ၏ ဒေတာနှင့် အပ်ဖ်များအားလုံး ဖျက်လိုက်ပါမည်"</string>
<string name="user_remove_user_remove" msgid="7479275741742178297">"ဖယ်ရှားရန်"</string>
@@ -732,8 +734,7 @@
<string name="left_icon" msgid="3096287125959387541">"လက်ဝဲသင်္ကေတ"</string>
<string name="right_icon" msgid="3952104823293824311">"လက်ယာသင်္ကေတ"</string>
<string name="drag_to_add_tiles" msgid="230586591689084925">"အကွက်များထည့်ရန် ဖိဆွဲပါ"</string>
- <!-- no translation found for drag_to_rearrange_tiles (4566074720193667473) -->
- <skip />
+ <string name="drag_to_rearrange_tiles" msgid="4566074720193667473">"အကွက်ငယ်များ ပြန်စီစဉ်ရန် ဖိပြီးဆွဲပါ"</string>
<string name="drag_to_remove_tiles" msgid="3361212377437088062">"ဖယ်ရှားရန် ဤနေရာသို့ဖိဆွဲပါ"</string>
<string name="drag_to_remove_disabled" msgid="2390968976638993382">"အနည်းဆုံး ၆ ကွက် ရှိရမည်"</string>
<string name="qs_edit" msgid="2232596095725105230">"တည်းဖြတ်ပါ"</string>
diff --git a/packages/SystemUI/res/values-nb/strings.xml b/packages/SystemUI/res/values-nb/strings.xml
index 8c8e90542173..b8178774c1c1 100644
--- a/packages/SystemUI/res/values-nb/strings.xml
+++ b/packages/SystemUI/res/values-nb/strings.xml
@@ -426,9 +426,11 @@
<string name="user_logout_notification_action" msgid="1195428991423425062">"LOGG UT BRUKER"</string>
<string name="user_add_user_title" msgid="4553596395824132638">"Vil du legge til en ny bruker?"</string>
<string name="user_add_user_message_short" msgid="2161624834066214559">"Når du legger til en ny bruker, må vedkommende konfigurere sitt eget område.\n\nAlle brukere kan oppdatere apper for alle andre brukere."</string>
- <!-- no translation found for user_limit_reached_title (7374910700117359177) -->
- <skip />
- <!-- no translation found for user_limit_reached_message (1855040563671964242) -->
+ <string name="user_limit_reached_title" msgid="7374910700117359177">"Grensen for antall brukere er nådd"</string>
+ <plurals name="user_limit_reached_message" formatted="false" msgid="1855040563671964242">
+ <item quantity="other">Du kan legge til opptil <xliff:g id="COUNT">%d</xliff:g> brukere.</item>
+ <item quantity="one">Du kan bare opprette én bruker.</item>
+ </plurals>
<string name="user_remove_user_title" msgid="4681256956076895559">"Vil du fjerne brukeren?"</string>
<string name="user_remove_user_message" msgid="1453218013959498039">"Alle apper og data som tilhører denne brukeren, blir slettet."</string>
<string name="user_remove_user_remove" msgid="7479275741742178297">"Fjern"</string>
@@ -732,8 +734,7 @@
<string name="left_icon" msgid="3096287125959387541">"Venstre-ikon"</string>
<string name="right_icon" msgid="3952104823293824311">"Høyre-ikon"</string>
<string name="drag_to_add_tiles" msgid="230586591689084925">"Hold og dra for å legge til ruter"</string>
- <!-- no translation found for drag_to_rearrange_tiles (4566074720193667473) -->
- <skip />
+ <string name="drag_to_rearrange_tiles" msgid="4566074720193667473">"Hold og dra for å endre rekkefølge for ruter"</string>
<string name="drag_to_remove_tiles" msgid="3361212377437088062">"Dra hit for å fjerne"</string>
<string name="drag_to_remove_disabled" msgid="2390968976638993382">"Du trenger minst seks ruter"</string>
<string name="qs_edit" msgid="2232596095725105230">"Endre"</string>
diff --git a/packages/SystemUI/res/values-ne/strings.xml b/packages/SystemUI/res/values-ne/strings.xml
index 1b8149e810fe..6cc405fb07a0 100644
--- a/packages/SystemUI/res/values-ne/strings.xml
+++ b/packages/SystemUI/res/values-ne/strings.xml
@@ -426,9 +426,11 @@
<string name="user_logout_notification_action" msgid="1195428991423425062">"प्रयोगकर्ता लगआउट गर्नुहोस्"</string>
<string name="user_add_user_title" msgid="4553596395824132638">"नयाँ प्रयोगकर्ता थप्ने हो?"</string>
<string name="user_add_user_message_short" msgid="2161624834066214559">"जब तपाईँले नयाँ प्रयोगकर्ता थप्नुहुन्छ, त्यस प्रयोगकर्ताले आफ्नो स्थान स्थापना गर्न पर्ने छ।\n\nकुनै पनि प्रयोगकर्ताले सबै अन्य प्रयोगकर्ताहरूका लागि अनुप्रयोगहरू अद्यावधिक गर्न सक्छन्।"</string>
- <!-- no translation found for user_limit_reached_title (7374910700117359177) -->
- <skip />
- <!-- no translation found for user_limit_reached_message (1855040563671964242) -->
+ <string name="user_limit_reached_title" msgid="7374910700117359177">"प्रयोगकर्ताको सीमा पुग्यो"</string>
+ <plurals name="user_limit_reached_message" formatted="false" msgid="1855040563671964242">
+ <item quantity="other">तपाईं अधिकतम <xliff:g id="COUNT">%d</xliff:g> प्रयोगहरू मात्र थप्न सक्नुहुन्छ।</item>
+ <item quantity="one">एउटा प्रयोगकर्ता मात्र सिर्जना गर्न सकिन्छ।</item>
+ </plurals>
<string name="user_remove_user_title" msgid="4681256956076895559">"प्रयोगकर्ता हटाउन चाहनुहुन्छ?"</string>
<string name="user_remove_user_message" msgid="1453218013959498039">"यस प्रयोगकर्ताको सबै अनुप्रयोगहरू तथा डेटा हटाइनेछ।"</string>
<string name="user_remove_user_remove" msgid="7479275741742178297">"हटाउनुहोस्"</string>
@@ -732,8 +734,7 @@
<string name="left_icon" msgid="3096287125959387541">"बायाँतिर देखाउने आइकन"</string>
<string name="right_icon" msgid="3952104823293824311">"दायाँतिरको आइकन"</string>
<string name="drag_to_add_tiles" msgid="230586591689084925">"टाइलहरू थप्न होल्ड गरी ड्र्याग गर्नुहोस्"</string>
- <!-- no translation found for drag_to_rearrange_tiles (4566074720193667473) -->
- <skip />
+ <string name="drag_to_rearrange_tiles" msgid="4566074720193667473">"टाइलहरू पुनः क्रमबद्ध गर्न होल्ड गरी ड्र्याग गर्नुहोस्"</string>
<string name="drag_to_remove_tiles" msgid="3361212377437088062">"हटाउनका लागि यहाँ तान्नुहोस्"</string>
<string name="drag_to_remove_disabled" msgid="2390968976638993382">"तपाईंलाई कम्तीमा ६ वटा टाइलहरू चाहिन्छ"</string>
<string name="qs_edit" msgid="2232596095725105230">"सम्पादन गर्नुहोस्"</string>
diff --git a/packages/SystemUI/res/values-nl/strings.xml b/packages/SystemUI/res/values-nl/strings.xml
index 61dba4ab3843..e8c6f8df486c 100644
--- a/packages/SystemUI/res/values-nl/strings.xml
+++ b/packages/SystemUI/res/values-nl/strings.xml
@@ -426,9 +426,11 @@
<string name="user_logout_notification_action" msgid="1195428991423425062">"GEBRUIKER UITLOGGEN"</string>
<string name="user_add_user_title" msgid="4553596395824132638">"Nieuwe gebruiker toevoegen?"</string>
<string name="user_add_user_message_short" msgid="2161624834066214559">"Wanneer u een nieuwe gebruiker toevoegt, moet die persoon zijn eigen profiel instellen.\n\nElke gebruiker kan apps updaten voor alle andere gebruikers."</string>
- <!-- no translation found for user_limit_reached_title (7374910700117359177) -->
- <skip />
- <!-- no translation found for user_limit_reached_message (1855040563671964242) -->
+ <string name="user_limit_reached_title" msgid="7374910700117359177">"Gebruikerslimiet bereikt"</string>
+ <plurals name="user_limit_reached_message" formatted="false" msgid="1855040563671964242">
+ <item quantity="other">Je kunt maximaal <xliff:g id="COUNT">%d</xliff:g> gebruikers toevoegen.</item>
+ <item quantity="one">Er kan maar één gebruiker worden gemaakt.</item>
+ </plurals>
<string name="user_remove_user_title" msgid="4681256956076895559">"Gebruiker verwijderen?"</string>
<string name="user_remove_user_message" msgid="1453218013959498039">"Alle apps en gegevens van deze gebruiker worden verwijderd."</string>
<string name="user_remove_user_remove" msgid="7479275741742178297">"Verwijderen"</string>
@@ -732,8 +734,7 @@
<string name="left_icon" msgid="3096287125959387541">"Pictogram links"</string>
<string name="right_icon" msgid="3952104823293824311">"Pictogram rechts"</string>
<string name="drag_to_add_tiles" msgid="230586591689084925">"Houd vast en sleep om tegels toe te voegen"</string>
- <!-- no translation found for drag_to_rearrange_tiles (4566074720193667473) -->
- <skip />
+ <string name="drag_to_rearrange_tiles" msgid="4566074720193667473">"Houd vast en sleep om tegels opnieuw in te delen"</string>
<string name="drag_to_remove_tiles" msgid="3361212377437088062">"Sleep hier naartoe om te verwijderen"</string>
<string name="drag_to_remove_disabled" msgid="2390968976638993382">"Je hebt minimaal zes tegels nodig"</string>
<string name="qs_edit" msgid="2232596095725105230">"Bewerken"</string>
diff --git a/packages/SystemUI/res/values-or/strings.xml b/packages/SystemUI/res/values-or/strings.xml
index 7f7909029218..277181f77fed 100644
--- a/packages/SystemUI/res/values-or/strings.xml
+++ b/packages/SystemUI/res/values-or/strings.xml
@@ -426,9 +426,11 @@
<string name="user_logout_notification_action" msgid="1195428991423425062">"ୟୁଜରଙ୍କୁ ଲଗଆଉଟ୍‍ କରନ୍ତୁ"</string>
<string name="user_add_user_title" msgid="4553596395824132638">"ନୂତନ ୟୁଜର୍‍ ଯୋଡ଼ିବେ?"</string>
<string name="user_add_user_message_short" msgid="2161624834066214559">"ଜଣେ ନୂଆ ୟୁଜର୍‍ଙ୍କୁ ଯୋଡ଼ିବାବେଳେ, ସେହି ବ୍ୟକ୍ତିଙ୍କୁ ସ୍ଥାନ ସେଟ୍‍ କରିବାକୁ ପଡ଼ିବ। \n \n ଅନ୍ୟ ସମସ୍ତ ୟୁଜର୍‍ଙ୍କ ପାଇଁ ଯେକୌଣସି ୟୁଜର୍‍ ଆପ୍‌ଗୁଡ଼ିକୁ ଅପଡେଟ୍‌ କରିପାରିବେ।"</string>
- <!-- no translation found for user_limit_reached_title (7374910700117359177) -->
- <skip />
- <!-- no translation found for user_limit_reached_message (1855040563671964242) -->
+ <string name="user_limit_reached_title" msgid="7374910700117359177">"ଉପଯୋଗକର୍ତ୍ତା ସୀମାରେ ପହଞ୍ଚିଛି"</string>
+ <plurals name="user_limit_reached_message" formatted="false" msgid="1855040563671964242">
+ <item quantity="other">କେବଳ <xliff:g id="COUNT">%d</xliff:g> ଉପଯୋଗକର୍ତ୍ତା ହିଁ ତିଆରି କରିହେବ।</item>
+ <item quantity="one">କେବଳ ଜଣେ ଉପଯୋଗକର୍ତ୍ତା ହିଁ ତିଆରି କରିହେବ।</item>
+ </plurals>
<string name="user_remove_user_title" msgid="4681256956076895559">"ୟୁଜରଙ୍କୁ ବାହାର କରିବେ?"</string>
<string name="user_remove_user_message" msgid="1453218013959498039">"ଏହି ୟୁଜରଙ୍କ ସମସ୍ତ ଆପ୍‍ ଓ ଡାଟା ଡିଲିଟ୍‍ ହେବ।"</string>
<string name="user_remove_user_remove" msgid="7479275741742178297">"ବାହାର କରନ୍ତୁ"</string>
@@ -732,8 +734,7 @@
<string name="left_icon" msgid="3096287125959387541">"ବାମ ଆଇକନ୍‍"</string>
<string name="right_icon" msgid="3952104823293824311">"ଡାହାଣ ଆଇକନ୍"</string>
<string name="drag_to_add_tiles" msgid="230586591689084925">"ଟାଇଲ୍ ଯୋଡ଼ିବା ପାଇଁ ଦାବିଧରି ଟାଣନ୍ତୁ"</string>
- <!-- no translation found for drag_to_rearrange_tiles (4566074720193667473) -->
- <skip />
+ <string name="drag_to_rearrange_tiles" msgid="4566074720193667473">"ଟାଇଲ୍‍ ପୁଣି ଆୟୋଜିତ କରିବାକୁ ଦାବିଧରି ଟାଣନ୍ତୁ"</string>
<string name="drag_to_remove_tiles" msgid="3361212377437088062">"ବାହାର କରିବାକୁ ଏଠାକୁ ଡ୍ରାଗ୍‍ କରନ୍ତୁ"</string>
<string name="drag_to_remove_disabled" msgid="2390968976638993382">"ଆପଣଙ୍କର ଅତିକମରେ 6ଟି ଟାଇଲ୍ ଆବଶ୍ୟକ"</string>
<string name="qs_edit" msgid="2232596095725105230">"ଏଡିଟ୍‌ କରନ୍ତୁ"</string>
diff --git a/packages/SystemUI/res/values-pa/strings.xml b/packages/SystemUI/res/values-pa/strings.xml
index c6ec96e8d5bb..65098716cad8 100644
--- a/packages/SystemUI/res/values-pa/strings.xml
+++ b/packages/SystemUI/res/values-pa/strings.xml
@@ -426,9 +426,11 @@
<string name="user_logout_notification_action" msgid="1195428991423425062">"ਉਪਭੋਗਤਾ ਨੂੰ ਲੌਗ ਆਉਟ ਕਰੋ"</string>
<string name="user_add_user_title" msgid="4553596395824132638">"ਕੀ ਨਵਾਂ ਵਰਤੋਂਕਾਰ ਸ਼ਾਮਲ ਕਰਨਾ ਹੈ?"</string>
<string name="user_add_user_message_short" msgid="2161624834066214559">"ਜਦੋਂ ਤੁਸੀਂ ਇੱਕ ਨਵਾਂ ਵਰਤੋਂਕਾਰ ਸ਼ਾਮਲ ਕਰਦੇ ਹੋ, ਉਸ ਵਿਅਕਤੀ ਨੂੰ ਆਪਣੀ ਜਗ੍ਹਾ ਸਥਾਪਤ ਕਰਨ ਦੀ ਲੋੜ ਹੁੰਦੀ ਹੈ।\n\nਕੋਈ ਵੀ ਵਰਤੋਂਕਾਰ ਹੋਰ ਸਾਰੇ ਵਰਤੋਂਕਾਰਾਂ ਦੀਆਂ ਐਪਾਂ ਨੂੰ ਅੱਪਡੇਟ ਕਰ ਸਕਦਾ ਹੈ।"</string>
- <!-- no translation found for user_limit_reached_title (7374910700117359177) -->
- <skip />
- <!-- no translation found for user_limit_reached_message (1855040563671964242) -->
+ <string name="user_limit_reached_title" msgid="7374910700117359177">"ਵਰਤੋਂਕਾਰ ਸ਼ਾਮਲ ਕਰਨ ਦੀ ਸੀਮਾ ਪੂਰੀ ਹੋਈ"</string>
+ <plurals name="user_limit_reached_message" formatted="false" msgid="1855040563671964242">
+ <item quantity="one">ਤੁਸੀਂ <xliff:g id="COUNT">%d</xliff:g> ਤੱਕ ਵਰਤੋਂਕਾਰ ਸ਼ਾਮਲ ਕਰ ਸਕਦੇ ਹੋ।</item>
+ <item quantity="other">ਤੁਸੀਂ <xliff:g id="COUNT">%d</xliff:g> ਤੱਕ ਵਰਤੋਂਕਾਰਾਂ ਨੂੰ ਸ਼ਾਮਲ ਕਰ ਸਕਦੇ ਹੋ।</item>
+ </plurals>
<string name="user_remove_user_title" msgid="4681256956076895559">"ਕੀ ਵਰਤੋਂਕਾਰ ਹਟਾਉਣਾ ਹੈ?"</string>
<string name="user_remove_user_message" msgid="1453218013959498039">"ਇਸ ਉਪਭੋਗਤਾ ਦੇ ਸਾਰੇ ਐਪਸ ਅਤੇ ਡਾਟਾ ਮਿਟਾ ਦਿੱਤਾ ਜਾਏਗਾ।"</string>
<string name="user_remove_user_remove" msgid="7479275741742178297">"ਹਟਾਓ"</string>
@@ -732,8 +734,7 @@
<string name="left_icon" msgid="3096287125959387541">"ਖੱਬਾ ਪ੍ਰਤੀਕ"</string>
<string name="right_icon" msgid="3952104823293824311">"ਸੱਜਾ ਪ੍ਰਤੀਕ"</string>
<string name="drag_to_add_tiles" msgid="230586591689084925">"ਟਾਇਲਾਂ ਸ਼ਾਮਲ ਕਰਨ ਲਈ ਫੜ੍ਹ ਕੇ ਰੱਖੋ ਅਤੇ ਘਸੀਟੋ"</string>
- <!-- no translation found for drag_to_rearrange_tiles (4566074720193667473) -->
- <skip />
+ <string name="drag_to_rearrange_tiles" msgid="4566074720193667473">"ਟਾਇਲਾਂ ਨੂੰ ਮੁੜ-ਵਿਵਸਥਿਤ ਕਰਨ ਲਈ ਫੜ੍ਹ ਕੇ ਘਸੀਟੋ"</string>
<string name="drag_to_remove_tiles" msgid="3361212377437088062">"ਹਟਾਉਣ ਲਈ ਇੱਥੇ ਘਸੀਟੋ"</string>
<string name="drag_to_remove_disabled" msgid="2390968976638993382">"ਤੁਹਾਨੂੰ ਘੱਟੋ-ਘੱਟ 6 ਟਾਇਲਾਂ ਦੀ ਲੋੜ ਪਵੇਗੀ"</string>
<string name="qs_edit" msgid="2232596095725105230">"ਸੰਪਾਦਨ ਕਰੋ"</string>
diff --git a/packages/SystemUI/res/values-pl/strings.xml b/packages/SystemUI/res/values-pl/strings.xml
index 33a8117b42c2..2959a8da85e2 100644
--- a/packages/SystemUI/res/values-pl/strings.xml
+++ b/packages/SystemUI/res/values-pl/strings.xml
@@ -432,9 +432,13 @@
<string name="user_logout_notification_action" msgid="1195428991423425062">"WYLOGUJ UŻYTKOWNIKA"</string>
<string name="user_add_user_title" msgid="4553596395824132638">"Dodać nowego użytkownika?"</string>
<string name="user_add_user_message_short" msgid="2161624834066214559">"Gdy dodasz nowego użytkownika, musi on skonfigurować swój profil.\n\nKażdy użytkownik może aktualizować aplikacje wszystkich innych użytkowników."</string>
- <!-- no translation found for user_limit_reached_title (7374910700117359177) -->
- <skip />
- <!-- no translation found for user_limit_reached_message (1855040563671964242) -->
+ <string name="user_limit_reached_title" msgid="7374910700117359177">"Osiągnięto limit użytkowników"</string>
+ <plurals name="user_limit_reached_message" formatted="false" msgid="1855040563671964242">
+ <item quantity="few">Możesz dodać maksymalnie <xliff:g id="COUNT">%d</xliff:g> użytkowników.</item>
+ <item quantity="many">Możesz dodać maksymalnie <xliff:g id="COUNT">%d</xliff:g> użytkowników.</item>
+ <item quantity="other">Możesz dodać maksymalnie <xliff:g id="COUNT">%d</xliff:g> użytkownika.</item>
+ <item quantity="one">Można utworzyć tylko jednego użytkownika.</item>
+ </plurals>
<string name="user_remove_user_title" msgid="4681256956076895559">"Usunąć użytkownika?"</string>
<string name="user_remove_user_message" msgid="1453218013959498039">"Wszystkie aplikacje i dane tego użytkownika zostaną usunięte."</string>
<string name="user_remove_user_remove" msgid="7479275741742178297">"Usuń"</string>
@@ -742,8 +746,7 @@
<string name="left_icon" msgid="3096287125959387541">"Lewa ikona"</string>
<string name="right_icon" msgid="3952104823293824311">"Prawa ikona"</string>
<string name="drag_to_add_tiles" msgid="230586591689084925">"Przytrzymaj i przeciągnij, by dodać kafelki"</string>
- <!-- no translation found for drag_to_rearrange_tiles (4566074720193667473) -->
- <skip />
+ <string name="drag_to_rearrange_tiles" msgid="4566074720193667473">"Przytrzymaj i przeciągnij, by przestawić kafelki"</string>
<string name="drag_to_remove_tiles" msgid="3361212377437088062">"Przeciągnij tutaj, by usunąć"</string>
<string name="drag_to_remove_disabled" msgid="2390968976638993382">"Potrzebnych jest co najmniej sześć kafelków"</string>
<string name="qs_edit" msgid="2232596095725105230">"Edytuj"</string>
diff --git a/packages/SystemUI/res/values-pt-rBR/strings.xml b/packages/SystemUI/res/values-pt-rBR/strings.xml
index 60825b76f960..ba50c13f3d0f 100644
--- a/packages/SystemUI/res/values-pt-rBR/strings.xml
+++ b/packages/SystemUI/res/values-pt-rBR/strings.xml
@@ -160,7 +160,7 @@
<string name="data_connection_roaming" msgid="6037232010953697354">"Roaming"</string>
<string name="data_connection_edge" msgid="871835227939216682">"EDGE"</string>
<string name="accessibility_data_connection_wifi" msgid="2324496756590645221">"Wi-Fi"</string>
- <string name="accessibility_no_sim" msgid="8274017118472455155">"Sem SIM."</string>
+ <string name="accessibility_no_sim" msgid="8274017118472455155">"Sem chip."</string>
<string name="accessibility_cell_data" msgid="5326139158682385073">"Dados móveis"</string>
<string name="accessibility_cell_data_on" msgid="5927098403452994422">"Dados móveis ativados"</string>
<string name="cell_data_off_content_description" msgid="4356113230238585072">"Dados móveis desativados"</string>
@@ -168,7 +168,7 @@
<string name="accessibility_bluetooth_tether" msgid="4102784498140271969">"Tethering Bluetooth."</string>
<string name="accessibility_airplane_mode" msgid="834748999790763092">"Modo avião."</string>
<string name="accessibility_vpn_on" msgid="5993385083262856059">"VPN ativada."</string>
- <string name="accessibility_no_sims" msgid="3957997018324995781">"Sem cartão SIM."</string>
+ <string name="accessibility_no_sims" msgid="3957997018324995781">"Sem chip."</string>
<string name="carrier_network_change_mode" msgid="8149202439957837762">"Alteração de rede da operadora"</string>
<string name="accessibility_battery_details" msgid="7645516654955025422">"Abrir detalhes da bateria"</string>
<string name="accessibility_battery_level" msgid="7451474187113371965">"Bateria em <xliff:g id="NUMBER">%d</xliff:g> por cento."</string>
@@ -428,9 +428,11 @@
<string name="user_logout_notification_action" msgid="1195428991423425062">"DESCONECTAR USUÁRIO"</string>
<string name="user_add_user_title" msgid="4553596395824132638">"Adicionar novo usuário?"</string>
<string name="user_add_user_message_short" msgid="2161624834066214559">"Quando você adiciona um novo usuário, essa pessoa precisa configurar o próprio espaço.\n\nQualquer usuário pode atualizar apps para os demais usuários."</string>
- <!-- no translation found for user_limit_reached_title (7374910700117359177) -->
- <skip />
- <!-- no translation found for user_limit_reached_message (1855040563671964242) -->
+ <string name="user_limit_reached_title" msgid="7374910700117359177">"Limite de usuários atingido"</string>
+ <plurals name="user_limit_reached_message" formatted="false" msgid="1855040563671964242">
+ <item quantity="one">É possível adicionar até <xliff:g id="COUNT">%d</xliff:g> usuário.</item>
+ <item quantity="other">É possível adicionar até <xliff:g id="COUNT">%d</xliff:g> usuários.</item>
+ </plurals>
<string name="user_remove_user_title" msgid="4681256956076895559">"Remover usuário?"</string>
<string name="user_remove_user_message" msgid="1453218013959498039">"Todos os apps e dados deste usuário serão excluídos."</string>
<string name="user_remove_user_remove" msgid="7479275741742178297">"Remover"</string>
@@ -734,8 +736,7 @@
<string name="left_icon" msgid="3096287125959387541">"Ícone à esquerda"</string>
<string name="right_icon" msgid="3952104823293824311">"Ícone à direita"</string>
<string name="drag_to_add_tiles" msgid="230586591689084925">"Mantenha pressionado e arraste para adicionar blocos"</string>
- <!-- no translation found for drag_to_rearrange_tiles (4566074720193667473) -->
- <skip />
+ <string name="drag_to_rearrange_tiles" msgid="4566074720193667473">"Mantenha pressionado e arraste para reorganizar os blocos"</string>
<string name="drag_to_remove_tiles" msgid="3361212377437088062">"Arraste aqui para remover"</string>
<string name="drag_to_remove_disabled" msgid="2390968976638993382">"É preciso haver pelo menos seis blocos"</string>
<string name="qs_edit" msgid="2232596095725105230">"Editar"</string>
diff --git a/packages/SystemUI/res/values-pt-rPT/strings.xml b/packages/SystemUI/res/values-pt-rPT/strings.xml
index 4be72810958e..a03dba2c419f 100644
--- a/packages/SystemUI/res/values-pt-rPT/strings.xml
+++ b/packages/SystemUI/res/values-pt-rPT/strings.xml
@@ -426,9 +426,11 @@
<string name="user_logout_notification_action" msgid="1195428991423425062">"TERMINAR SESSÃO DO UTILIZADOR"</string>
<string name="user_add_user_title" msgid="4553596395824132638">"Adicionar um novo utilizador?"</string>
<string name="user_add_user_message_short" msgid="2161624834066214559">"Ao adicionar um novo utilizador, essa pessoa tem de configurar o respetivo espaço.\n\nQualquer utilizador pode atualizar aplicações para todos os outros utilizadores."</string>
- <!-- no translation found for user_limit_reached_title (7374910700117359177) -->
- <skip />
- <!-- no translation found for user_limit_reached_message (1855040563671964242) -->
+ <string name="user_limit_reached_title" msgid="7374910700117359177">"Limite de utilizadores alcançado"</string>
+ <plurals name="user_limit_reached_message" formatted="false" msgid="1855040563671964242">
+ <item quantity="other">Pode adicionar até <xliff:g id="COUNT">%d</xliff:g> utilizadores.</item>
+ <item quantity="one">Apenas é possível criar um utilizador.</item>
+ </plurals>
<string name="user_remove_user_title" msgid="4681256956076895559">"Pretende remover o utilizador?"</string>
<string name="user_remove_user_message" msgid="1453218013959498039">"Serão eliminados todos os dados e todas as aplicações deste utilizador."</string>
<string name="user_remove_user_remove" msgid="7479275741742178297">"Remover"</string>
@@ -732,8 +734,7 @@
<string name="left_icon" msgid="3096287125959387541">"Ícone esquerdo"</string>
<string name="right_icon" msgid="3952104823293824311">"Ícone direito"</string>
<string name="drag_to_add_tiles" msgid="230586591689084925">"Toque sem soltar e arraste para adicionar mosaicos."</string>
- <!-- no translation found for drag_to_rearrange_tiles (4566074720193667473) -->
- <skip />
+ <string name="drag_to_rearrange_tiles" msgid="4566074720193667473">"Tocar sem soltar e arrastar para reorganizar os mosaicos"</string>
<string name="drag_to_remove_tiles" msgid="3361212377437088062">"Arrastar para aqui para remover"</string>
<string name="drag_to_remove_disabled" msgid="2390968976638993382">"Necessita de, pelo menos, 6 mosaicos."</string>
<string name="qs_edit" msgid="2232596095725105230">"Editar"</string>
diff --git a/packages/SystemUI/res/values-pt/strings.xml b/packages/SystemUI/res/values-pt/strings.xml
index 60825b76f960..ba50c13f3d0f 100644
--- a/packages/SystemUI/res/values-pt/strings.xml
+++ b/packages/SystemUI/res/values-pt/strings.xml
@@ -160,7 +160,7 @@
<string name="data_connection_roaming" msgid="6037232010953697354">"Roaming"</string>
<string name="data_connection_edge" msgid="871835227939216682">"EDGE"</string>
<string name="accessibility_data_connection_wifi" msgid="2324496756590645221">"Wi-Fi"</string>
- <string name="accessibility_no_sim" msgid="8274017118472455155">"Sem SIM."</string>
+ <string name="accessibility_no_sim" msgid="8274017118472455155">"Sem chip."</string>
<string name="accessibility_cell_data" msgid="5326139158682385073">"Dados móveis"</string>
<string name="accessibility_cell_data_on" msgid="5927098403452994422">"Dados móveis ativados"</string>
<string name="cell_data_off_content_description" msgid="4356113230238585072">"Dados móveis desativados"</string>
@@ -168,7 +168,7 @@
<string name="accessibility_bluetooth_tether" msgid="4102784498140271969">"Tethering Bluetooth."</string>
<string name="accessibility_airplane_mode" msgid="834748999790763092">"Modo avião."</string>
<string name="accessibility_vpn_on" msgid="5993385083262856059">"VPN ativada."</string>
- <string name="accessibility_no_sims" msgid="3957997018324995781">"Sem cartão SIM."</string>
+ <string name="accessibility_no_sims" msgid="3957997018324995781">"Sem chip."</string>
<string name="carrier_network_change_mode" msgid="8149202439957837762">"Alteração de rede da operadora"</string>
<string name="accessibility_battery_details" msgid="7645516654955025422">"Abrir detalhes da bateria"</string>
<string name="accessibility_battery_level" msgid="7451474187113371965">"Bateria em <xliff:g id="NUMBER">%d</xliff:g> por cento."</string>
@@ -428,9 +428,11 @@
<string name="user_logout_notification_action" msgid="1195428991423425062">"DESCONECTAR USUÁRIO"</string>
<string name="user_add_user_title" msgid="4553596395824132638">"Adicionar novo usuário?"</string>
<string name="user_add_user_message_short" msgid="2161624834066214559">"Quando você adiciona um novo usuário, essa pessoa precisa configurar o próprio espaço.\n\nQualquer usuário pode atualizar apps para os demais usuários."</string>
- <!-- no translation found for user_limit_reached_title (7374910700117359177) -->
- <skip />
- <!-- no translation found for user_limit_reached_message (1855040563671964242) -->
+ <string name="user_limit_reached_title" msgid="7374910700117359177">"Limite de usuários atingido"</string>
+ <plurals name="user_limit_reached_message" formatted="false" msgid="1855040563671964242">
+ <item quantity="one">É possível adicionar até <xliff:g id="COUNT">%d</xliff:g> usuário.</item>
+ <item quantity="other">É possível adicionar até <xliff:g id="COUNT">%d</xliff:g> usuários.</item>
+ </plurals>
<string name="user_remove_user_title" msgid="4681256956076895559">"Remover usuário?"</string>
<string name="user_remove_user_message" msgid="1453218013959498039">"Todos os apps e dados deste usuário serão excluídos."</string>
<string name="user_remove_user_remove" msgid="7479275741742178297">"Remover"</string>
@@ -734,8 +736,7 @@
<string name="left_icon" msgid="3096287125959387541">"Ícone à esquerda"</string>
<string name="right_icon" msgid="3952104823293824311">"Ícone à direita"</string>
<string name="drag_to_add_tiles" msgid="230586591689084925">"Mantenha pressionado e arraste para adicionar blocos"</string>
- <!-- no translation found for drag_to_rearrange_tiles (4566074720193667473) -->
- <skip />
+ <string name="drag_to_rearrange_tiles" msgid="4566074720193667473">"Mantenha pressionado e arraste para reorganizar os blocos"</string>
<string name="drag_to_remove_tiles" msgid="3361212377437088062">"Arraste aqui para remover"</string>
<string name="drag_to_remove_disabled" msgid="2390968976638993382">"É preciso haver pelo menos seis blocos"</string>
<string name="qs_edit" msgid="2232596095725105230">"Editar"</string>
diff --git a/packages/SystemUI/res/values-ro/strings.xml b/packages/SystemUI/res/values-ro/strings.xml
index 618c89039d5e..149803b1ee9d 100644
--- a/packages/SystemUI/res/values-ro/strings.xml
+++ b/packages/SystemUI/res/values-ro/strings.xml
@@ -431,9 +431,12 @@
<string name="user_logout_notification_action" msgid="1195428991423425062">"DECONECTAȚI UTILIZATORUL"</string>
<string name="user_add_user_title" msgid="4553596395824132638">"Adăugați un utilizator nou?"</string>
<string name="user_add_user_message_short" msgid="2161624834066214559">"Când adăugați un utilizator nou, acesta trebuie să-și configureze spațiul.\n\nOrice utilizator poate actualiza aplicațiile pentru toți ceilalți utilizatori."</string>
- <!-- no translation found for user_limit_reached_title (7374910700117359177) -->
- <skip />
- <!-- no translation found for user_limit_reached_message (1855040563671964242) -->
+ <string name="user_limit_reached_title" msgid="7374910700117359177">"Ați atins limita de utilizatori"</string>
+ <plurals name="user_limit_reached_message" formatted="false" msgid="1855040563671964242">
+ <item quantity="few">Puteți adăuga maximum <xliff:g id="COUNT">%d</xliff:g> utilizatori.</item>
+ <item quantity="other">Puteți adăuga maximum <xliff:g id="COUNT">%d</xliff:g> de utilizatori.</item>
+ <item quantity="one">Poate fi creat doar un utilizator.</item>
+ </plurals>
<string name="user_remove_user_title" msgid="4681256956076895559">"Eliminați utilizatorul?"</string>
<string name="user_remove_user_message" msgid="1453218013959498039">"Toate aplicațiile și datele acestui utilizator vor fi șterse."</string>
<string name="user_remove_user_remove" msgid="7479275741742178297">"Eliminați"</string>
@@ -739,8 +742,7 @@
<string name="left_icon" msgid="3096287125959387541">"Pictograma din stânga"</string>
<string name="right_icon" msgid="3952104823293824311">"Pictograma din dreapta"</string>
<string name="drag_to_add_tiles" msgid="230586591689084925">"Țineți apăsat și trageți pentru a adăuga piese"</string>
- <!-- no translation found for drag_to_rearrange_tiles (4566074720193667473) -->
- <skip />
+ <string name="drag_to_rearrange_tiles" msgid="4566074720193667473">"Țineți apăsat și trageți pentru a rearanja piesele"</string>
<string name="drag_to_remove_tiles" msgid="3361212377437088062">"Trageți aici pentru a elimina"</string>
<string name="drag_to_remove_disabled" msgid="2390968976638993382">"Aveți nevoie de cel puțin 6 piese"</string>
<string name="qs_edit" msgid="2232596095725105230">"Editați"</string>
diff --git a/packages/SystemUI/res/values-ru/strings.xml b/packages/SystemUI/res/values-ru/strings.xml
index c754c36305d7..7a756cdb1304 100644
--- a/packages/SystemUI/res/values-ru/strings.xml
+++ b/packages/SystemUI/res/values-ru/strings.xml
@@ -434,9 +434,13 @@
<string name="user_logout_notification_action" msgid="1195428991423425062">"ВЫЙТИ ОТ ИМЕНИ ПОЛЬЗОВАТЕЛЯ"</string>
<string name="user_add_user_title" msgid="4553596395824132638">"Добавить пользователя?"</string>
<string name="user_add_user_message_short" msgid="2161624834066214559">"Когда вы добавите пользователя, ему потребуется настроить профиль.\n\nЛюбой пользователь устройства может обновлять приложения для всех аккаунтов."</string>
- <!-- no translation found for user_limit_reached_title (7374910700117359177) -->
- <skip />
- <!-- no translation found for user_limit_reached_message (1855040563671964242) -->
+ <string name="user_limit_reached_title" msgid="7374910700117359177">"Достигнут лимит"</string>
+ <plurals name="user_limit_reached_message" formatted="false" msgid="1855040563671964242">
+ <item quantity="one">Можно добавить не более <xliff:g id="COUNT">%d</xliff:g> пользователя.</item>
+ <item quantity="few">Можно добавить не более <xliff:g id="COUNT">%d</xliff:g> пользователей.</item>
+ <item quantity="many">Можно добавить не более <xliff:g id="COUNT">%d</xliff:g> пользователей.</item>
+ <item quantity="other">Можно добавить не более <xliff:g id="COUNT">%d</xliff:g> пользователя.</item>
+ </plurals>
<string name="user_remove_user_title" msgid="4681256956076895559">"Удалить аккаунт?"</string>
<string name="user_remove_user_message" msgid="1453218013959498039">"Все приложения и данные этого пользователя будут удалены."</string>
<string name="user_remove_user_remove" msgid="7479275741742178297">"Удалить"</string>
@@ -744,8 +748,7 @@
<string name="left_icon" msgid="3096287125959387541">"Значок \"Влево\""</string>
<string name="right_icon" msgid="3952104823293824311">"Значок \"Вправо\""</string>
<string name="drag_to_add_tiles" msgid="230586591689084925">"Перетащите нужные элементы"</string>
- <!-- no translation found for drag_to_rearrange_tiles (4566074720193667473) -->
- <skip />
+ <string name="drag_to_rearrange_tiles" msgid="4566074720193667473">"Чтобы изменить порядок элементов, перетащите их"</string>
<string name="drag_to_remove_tiles" msgid="3361212377437088062">"Чтобы удалить, перетащите сюда"</string>
<string name="drag_to_remove_disabled" msgid="2390968976638993382">"Должно остаться не менее 6 элементов"</string>
<string name="qs_edit" msgid="2232596095725105230">"Изменить"</string>
diff --git a/packages/SystemUI/res/values-si/strings.xml b/packages/SystemUI/res/values-si/strings.xml
index 8ec763d324d5..e29aedad6571 100644
--- a/packages/SystemUI/res/values-si/strings.xml
+++ b/packages/SystemUI/res/values-si/strings.xml
@@ -426,9 +426,11 @@
<string name="user_logout_notification_action" msgid="1195428991423425062">"පරිශීලකයා වරන්න"</string>
<string name="user_add_user_title" msgid="4553596395824132638">"අලුත් පරිශීලකයෙක් එක් කරන්නද?"</string>
<string name="user_add_user_message_short" msgid="2161624834066214559">"ඔබ අලුත් පරිශීලකයෙක් එකතු කරන විට, එම පුද්ගලයා ඔහුගේ වැඩ කරන ඉඩ සකසා ගත යුතුය.\n\nසියළුම අනෙක් පරිශීලකයින් සඳහා ඕනෑම පරිශීලකයෙකුට යාවත්කාලීන කළ හැක."</string>
- <!-- no translation found for user_limit_reached_title (7374910700117359177) -->
- <skip />
- <!-- no translation found for user_limit_reached_message (1855040563671964242) -->
+ <string name="user_limit_reached_title" msgid="7374910700117359177">"පරිශීලක සීමාවට ළඟා විය"</string>
+ <plurals name="user_limit_reached_message" formatted="false" msgid="1855040563671964242">
+ <item quantity="one">ඔබට පරිශීලකයින් <xliff:g id="COUNT">%d</xliff:g>ක් දක්වා එක් කළ හැකිය.</item>
+ <item quantity="other">ඔබට පරිශීලකයින් <xliff:g id="COUNT">%d</xliff:g>ක් දක්වා එක් කළ හැකිය.</item>
+ </plurals>
<string name="user_remove_user_title" msgid="4681256956076895559">"පරිශීලකයා ඉවත් කරන්නද?"</string>
<string name="user_remove_user_message" msgid="1453218013959498039">"මෙම පරිශීලකයාගේ සියලු යෙදුම් සහ දත්ත මකනු ඇත."</string>
<string name="user_remove_user_remove" msgid="7479275741742178297">"ඉවත් කරන්න"</string>
@@ -732,8 +734,7 @@
<string name="left_icon" msgid="3096287125959387541">"වම් නිරූපකය"</string>
<string name="right_icon" msgid="3952104823293824311">"දකුණු නිරූපකය"</string>
<string name="drag_to_add_tiles" msgid="230586591689084925">"ටයිල් එක් කිරීමට අල්ලාගෙන සිට අදින්න"</string>
- <!-- no translation found for drag_to_rearrange_tiles (4566074720193667473) -->
- <skip />
+ <string name="drag_to_rearrange_tiles" msgid="4566074720193667473">"ටයිල් නැවත සකස් කිරීමට අල්ලාගෙන සිට අදින්න"</string>
<string name="drag_to_remove_tiles" msgid="3361212377437088062">"ඉවත් කිරීමට මෙතැනට අදින්න"</string>
<string name="drag_to_remove_disabled" msgid="2390968976638993382">"ඔබ අවම වශයෙන් ටයිල් 6ක් අවශ්‍ය වේ"</string>
<string name="qs_edit" msgid="2232596095725105230">"සංස්කරණය"</string>
diff --git a/packages/SystemUI/res/values-sk/strings.xml b/packages/SystemUI/res/values-sk/strings.xml
index de32ae5649c2..8193e3fe3712 100644
--- a/packages/SystemUI/res/values-sk/strings.xml
+++ b/packages/SystemUI/res/values-sk/strings.xml
@@ -434,9 +434,13 @@
<string name="user_logout_notification_action" msgid="1195428991423425062">"ODHLÁSIŤ POUŽÍVATEĽA"</string>
<string name="user_add_user_title" msgid="4553596395824132638">"Pridať nového používateľa?"</string>
<string name="user_add_user_message_short" msgid="2161624834066214559">"Keď pridáte nového používateľa, musí si nastaviť vlastný priestor.\n\nKtorýkoľvek používateľ môže aktualizovať aplikácie všetkých ostatných používateľov."</string>
- <!-- no translation found for user_limit_reached_title (7374910700117359177) -->
- <skip />
- <!-- no translation found for user_limit_reached_message (1855040563671964242) -->
+ <string name="user_limit_reached_title" msgid="7374910700117359177">"Dosiahnutý limit počtu používateľov"</string>
+ <plurals name="user_limit_reached_message" formatted="false" msgid="1855040563671964242">
+ <item quantity="few">Môžete pridať maximálne <xliff:g id="COUNT">%d</xliff:g> používateľov.</item>
+ <item quantity="many">You can add up to <xliff:g id="COUNT">%d</xliff:g> users.</item>
+ <item quantity="other">Môžete pridať maximálne <xliff:g id="COUNT">%d</xliff:g> používateľov.</item>
+ <item quantity="one">Môžete vytvoriť iba jedného používateľa.</item>
+ </plurals>
<string name="user_remove_user_title" msgid="4681256956076895559">"Odstrániť používateľa?"</string>
<string name="user_remove_user_message" msgid="1453218013959498039">"Všetky aplikácie a údaje tohto používateľa budú odstránené."</string>
<string name="user_remove_user_remove" msgid="7479275741742178297">"Odstrániť"</string>
@@ -744,8 +748,7 @@
<string name="left_icon" msgid="3096287125959387541">"Ľavá ikona"</string>
<string name="right_icon" msgid="3952104823293824311">"Pravá ikona"</string>
<string name="drag_to_add_tiles" msgid="230586591689084925">"Pridržaním a presunutím pridáte dlaždice"</string>
- <!-- no translation found for drag_to_rearrange_tiles (4566074720193667473) -->
- <skip />
+ <string name="drag_to_rearrange_tiles" msgid="4566074720193667473">"Dlaždice môžete usporiadať pridržaním a presunutím"</string>
<string name="drag_to_remove_tiles" msgid="3361212377437088062">"Presunutím sem odstránite"</string>
<string name="drag_to_remove_disabled" msgid="2390968976638993382">"Potrebujete aspoň šesť dlaždíc"</string>
<string name="qs_edit" msgid="2232596095725105230">"Upraviť"</string>
diff --git a/packages/SystemUI/res/values-sl/strings.xml b/packages/SystemUI/res/values-sl/strings.xml
index 11de2d5d0073..71694417ca3d 100644
--- a/packages/SystemUI/res/values-sl/strings.xml
+++ b/packages/SystemUI/res/values-sl/strings.xml
@@ -434,9 +434,13 @@
<string name="user_logout_notification_action" msgid="1195428991423425062">"ODJAVA UPORABNIKA"</string>
<string name="user_add_user_title" msgid="4553596395824132638">"Dodajanje novega uporabnika?"</string>
<string name="user_add_user_message_short" msgid="2161624834066214559">"Ko dodate novega uporabnika, mora ta nastaviti svoj prostor.\n\nVsak uporabnik lahko posodobi aplikacije za vse druge uporabnike."</string>
- <!-- no translation found for user_limit_reached_title (7374910700117359177) -->
- <skip />
- <!-- no translation found for user_limit_reached_message (1855040563671964242) -->
+ <string name="user_limit_reached_title" msgid="7374910700117359177">"Omejitev uporabnikov je dosežena"</string>
+ <plurals name="user_limit_reached_message" formatted="false" msgid="1855040563671964242">
+ <item quantity="one">Dodate lahko do <xliff:g id="COUNT">%d</xliff:g> uporabnika.</item>
+ <item quantity="two">Dodate lahko do <xliff:g id="COUNT">%d</xliff:g> uporabnika.</item>
+ <item quantity="few">Dodate lahko do <xliff:g id="COUNT">%d</xliff:g> uporabnike.</item>
+ <item quantity="other">Dodate lahko do <xliff:g id="COUNT">%d</xliff:g> uporabnikov.</item>
+ </plurals>
<string name="user_remove_user_title" msgid="4681256956076895559">"Želite odstraniti uporabnika?"</string>
<string name="user_remove_user_message" msgid="1453218013959498039">"Vse aplikacije in podatki tega uporabnika bodo izbrisani."</string>
<string name="user_remove_user_remove" msgid="7479275741742178297">"Odstrani"</string>
@@ -744,8 +748,7 @@
<string name="left_icon" msgid="3096287125959387541">"Leva ikona"</string>
<string name="right_icon" msgid="3952104823293824311">"Desna ikona"</string>
<string name="drag_to_add_tiles" msgid="230586591689084925">"Držite in povlecite, da dodate ploščice"</string>
- <!-- no translation found for drag_to_rearrange_tiles (4566074720193667473) -->
- <skip />
+ <string name="drag_to_rearrange_tiles" msgid="4566074720193667473">"Držite in povlecite, da prerazporedite ploščice"</string>
<string name="drag_to_remove_tiles" msgid="3361212377437088062">"Če želite odstraniti, povlecite sem"</string>
<string name="drag_to_remove_disabled" msgid="2390968976638993382">"Imeti morate vsaj 6 ploščic"</string>
<string name="qs_edit" msgid="2232596095725105230">"Uredi"</string>
diff --git a/packages/SystemUI/res/values-sq/strings.xml b/packages/SystemUI/res/values-sq/strings.xml
index ab7076c2b3db..f2903ef70ac3 100644
--- a/packages/SystemUI/res/values-sq/strings.xml
+++ b/packages/SystemUI/res/values-sq/strings.xml
@@ -426,9 +426,11 @@
<string name="user_logout_notification_action" msgid="1195428991423425062">"NXJERRJA E PËRDORUESIT NGA IDENTIFIKIMI"</string>
<string name="user_add_user_title" msgid="4553596395824132638">"Të shtohet përdorues i ri?"</string>
<string name="user_add_user_message_short" msgid="2161624834066214559">"Kur shton një përdorues të ri, ai person duhet të konfigurojë hapësirën e vet.\n\nÇdo përdorues mund t\'i përditësojë aplikacionet për të gjithë përdoruesit e tjerë."</string>
- <!-- no translation found for user_limit_reached_title (7374910700117359177) -->
- <skip />
- <!-- no translation found for user_limit_reached_message (1855040563671964242) -->
+ <string name="user_limit_reached_title" msgid="7374910700117359177">"U arrit kufiri i përdoruesve"</string>
+ <plurals name="user_limit_reached_message" formatted="false" msgid="1855040563671964242">
+ <item quantity="other">Mund të shtosh deri në <xliff:g id="COUNT">%d</xliff:g> përdorues.</item>
+ <item quantity="one">Mund të krijohet vetëm një përdorues.</item>
+ </plurals>
<string name="user_remove_user_title" msgid="4681256956076895559">"Të hiqet ky përdorues?"</string>
<string name="user_remove_user_message" msgid="1453218013959498039">"Të gjitha aplikacionet dhe të dhënat e këtij përdoruesi do të fshihen."</string>
<string name="user_remove_user_remove" msgid="7479275741742178297">"Hiqe"</string>
@@ -732,8 +734,7 @@
<string name="left_icon" msgid="3096287125959387541">"Ikona majtas"</string>
<string name="right_icon" msgid="3952104823293824311">"Ikona djathtas"</string>
<string name="drag_to_add_tiles" msgid="230586591689084925">"Mbaje të shtypur dhe zvarrit për të shtuar pllakëza"</string>
- <!-- no translation found for drag_to_rearrange_tiles (4566074720193667473) -->
- <skip />
+ <string name="drag_to_rearrange_tiles" msgid="4566074720193667473">"Mbaje të shtypur dhe zvarrit për të risistemuar pllakëzat"</string>
<string name="drag_to_remove_tiles" msgid="3361212377437088062">"Zvarrit këtu për ta hequr"</string>
<string name="drag_to_remove_disabled" msgid="2390968976638993382">"Të duhen të paktën 6 pllakëza"</string>
<string name="qs_edit" msgid="2232596095725105230">"Redakto"</string>
diff --git a/packages/SystemUI/res/values-sr/strings.xml b/packages/SystemUI/res/values-sr/strings.xml
index 2dbdc3db5c3b..e77b080eaeeb 100644
--- a/packages/SystemUI/res/values-sr/strings.xml
+++ b/packages/SystemUI/res/values-sr/strings.xml
@@ -429,9 +429,12 @@
<string name="user_logout_notification_action" msgid="1195428991423425062">"ОДЈАВИ КОРИСНИКА"</string>
<string name="user_add_user_title" msgid="4553596395824132638">"Додајете новог корисника?"</string>
<string name="user_add_user_message_short" msgid="2161624834066214559">"Када додате новог корисника, та особа треба да подеси свој простор.\n\nСваки корисник може да ажурира апликације за све остале кориснике."</string>
- <!-- no translation found for user_limit_reached_title (7374910700117359177) -->
- <skip />
- <!-- no translation found for user_limit_reached_message (1855040563671964242) -->
+ <string name="user_limit_reached_title" msgid="7374910700117359177">"Достигнут максимални број корисника"</string>
+ <plurals name="user_limit_reached_message" formatted="false" msgid="1855040563671964242">
+ <item quantity="one">Можете да додате највише <xliff:g id="COUNT">%d</xliff:g> корисника.</item>
+ <item quantity="few">Можете да додате највише <xliff:g id="COUNT">%d</xliff:g> корисника.</item>
+ <item quantity="other">Можете да додате највише <xliff:g id="COUNT">%d</xliff:g> корисника.</item>
+ </plurals>
<string name="user_remove_user_title" msgid="4681256956076895559">"Желите ли да уклоните корисника?"</string>
<string name="user_remove_user_message" msgid="1453218013959498039">"Све апликације и подаци овог корисника ће бити избрисани."</string>
<string name="user_remove_user_remove" msgid="7479275741742178297">"Уклони"</string>
@@ -737,8 +740,7 @@
<string name="left_icon" msgid="3096287125959387541">"Лева икона"</string>
<string name="right_icon" msgid="3952104823293824311">"Десна икона"</string>
<string name="drag_to_add_tiles" msgid="230586591689084925">"Задржите и превуците да бисте додали плочице"</string>
- <!-- no translation found for drag_to_rearrange_tiles (4566074720193667473) -->
- <skip />
+ <string name="drag_to_rearrange_tiles" msgid="4566074720193667473">"Задржите и превуците да бисте променили распоред плочица"</string>
<string name="drag_to_remove_tiles" msgid="3361212377437088062">"Превуците овде да бисте уклонили"</string>
<string name="drag_to_remove_disabled" msgid="2390968976638993382">"Треба да изаберете најмање 6 плочица"</string>
<string name="qs_edit" msgid="2232596095725105230">"Измени"</string>
diff --git a/packages/SystemUI/res/values-sv/strings.xml b/packages/SystemUI/res/values-sv/strings.xml
index 4b05e27d5ad8..ccc498e7f9b2 100644
--- a/packages/SystemUI/res/values-sv/strings.xml
+++ b/packages/SystemUI/res/values-sv/strings.xml
@@ -426,9 +426,11 @@
<string name="user_logout_notification_action" msgid="1195428991423425062">"LOGGA UT ANVÄNDAREN"</string>
<string name="user_add_user_title" msgid="4553596395824132638">"Lägga till ny användare?"</string>
<string name="user_add_user_message_short" msgid="2161624834066214559">"När du lägger till en ny användare måste den personen konfigurera sitt utrymme.\n\nAlla användare kan uppdatera appar för samtliga användares räkning."</string>
- <!-- no translation found for user_limit_reached_title (7374910700117359177) -->
- <skip />
- <!-- no translation found for user_limit_reached_message (1855040563671964242) -->
+ <string name="user_limit_reached_title" msgid="7374910700117359177">"Användargränsen har nåtts"</string>
+ <plurals name="user_limit_reached_message" formatted="false" msgid="1855040563671964242">
+ <item quantity="other">Det går att lägga till upp till <xliff:g id="COUNT">%d</xliff:g> användare.</item>
+ <item quantity="one">Det går bara att skapa en användare.</item>
+ </plurals>
<string name="user_remove_user_title" msgid="4681256956076895559">"Vill du ta bort användaren?"</string>
<string name="user_remove_user_message" msgid="1453218013959498039">"Alla appar och all data som tillhör den här användaren raderas."</string>
<string name="user_remove_user_remove" msgid="7479275741742178297">"Ta bort"</string>
@@ -732,8 +734,7 @@
<string name="left_icon" msgid="3096287125959387541">"Vänster ikon"</string>
<string name="right_icon" msgid="3952104823293824311">"Höger ikon"</string>
<string name="drag_to_add_tiles" msgid="230586591689084925">"Lägg till rutor genom att trycka och dra"</string>
- <!-- no translation found for drag_to_rearrange_tiles (4566074720193667473) -->
- <skip />
+ <string name="drag_to_rearrange_tiles" msgid="4566074720193667473">"Ordna om rutor genom att trycka och dra"</string>
<string name="drag_to_remove_tiles" msgid="3361212377437088062">"Ta bort genom att dra här"</string>
<string name="drag_to_remove_disabled" msgid="2390968976638993382">"Minst sex rutor måste finnas kvar"</string>
<string name="qs_edit" msgid="2232596095725105230">"Redigera"</string>
diff --git a/packages/SystemUI/res/values-sw/strings.xml b/packages/SystemUI/res/values-sw/strings.xml
index 7cb38b2aa157..83e9997e3763 100644
--- a/packages/SystemUI/res/values-sw/strings.xml
+++ b/packages/SystemUI/res/values-sw/strings.xml
@@ -426,9 +426,11 @@
<string name="user_logout_notification_action" msgid="1195428991423425062">"ONDOA MTUMIAJI"</string>
<string name="user_add_user_title" msgid="4553596395824132638">"Ungependa kuongeza mtumiaji?"</string>
<string name="user_add_user_message_short" msgid="2161624834066214559">"Mtumiaji mpya utakayemwongeza atahitaji kuongeza akaunti yake.\n\nMtumiaji yoyote anaweza kusasisha programu kwa niaba ya wengine wote."</string>
- <!-- no translation found for user_limit_reached_title (7374910700117359177) -->
- <skip />
- <!-- no translation found for user_limit_reached_message (1855040563671964242) -->
+ <string name="user_limit_reached_title" msgid="7374910700117359177">"Umefikia kima cha juu cha watumiaji"</string>
+ <plurals name="user_limit_reached_message" formatted="false" msgid="1855040563671964242">
+ <item quantity="other">Unaruhusiwa kuongeza hadi watumiaji <xliff:g id="COUNT">%d</xliff:g>.</item>
+ <item quantity="one">Unaruhusiwa kuongeza mtumiaji mmoja pekee.</item>
+ </plurals>
<string name="user_remove_user_title" msgid="4681256956076895559">"Je, ungependa kuondoa mtumiaji?"</string>
<string name="user_remove_user_message" msgid="1453218013959498039">"Programu na data yote ya mtumiaji huyu itafutwa."</string>
<string name="user_remove_user_remove" msgid="7479275741742178297">"Ondoa"</string>
@@ -732,8 +734,7 @@
<string name="left_icon" msgid="3096287125959387541">"Aikoni ya kushoto"</string>
<string name="right_icon" msgid="3952104823293824311">"Aikoni ya kulia"</string>
<string name="drag_to_add_tiles" msgid="230586591689084925">"Shikilia na uburute ili uongeze vigae"</string>
- <!-- no translation found for drag_to_rearrange_tiles (4566074720193667473) -->
- <skip />
+ <string name="drag_to_rearrange_tiles" msgid="4566074720193667473">"Shikilia na uburute ili upange vigae upya"</string>
<string name="drag_to_remove_tiles" msgid="3361212377437088062">"Buruta hapa ili uondoe"</string>
<string name="drag_to_remove_disabled" msgid="2390968976638993382">"Unahitaji angalau vigae 6"</string>
<string name="qs_edit" msgid="2232596095725105230">"Badilisha"</string>
diff --git a/packages/SystemUI/res/values-ta/strings.xml b/packages/SystemUI/res/values-ta/strings.xml
index 84041a92a64c..6f06ab5d567e 100644
--- a/packages/SystemUI/res/values-ta/strings.xml
+++ b/packages/SystemUI/res/values-ta/strings.xml
@@ -426,9 +426,11 @@
<string name="user_logout_notification_action" msgid="1195428991423425062">"பயனரை வெளியேற்று"</string>
<string name="user_add_user_title" msgid="4553596395824132638">"புதியவரைச் சேர்க்கவா?"</string>
<string name="user_add_user_message_short" msgid="2161624834066214559">"புதிய பயனரைச் சேர்க்கும்போது, அவர் தனக்கான இடத்தை அமைக்க வேண்டும்.\n\nஎந்தவொரு பயனரும், மற்ற எல்லா பயனர்களுக்காகவும் பயன்பாடுகளைப் புதுப்பிக்கலாம்."</string>
- <!-- no translation found for user_limit_reached_title (7374910700117359177) -->
- <skip />
- <!-- no translation found for user_limit_reached_message (1855040563671964242) -->
+ <string name="user_limit_reached_title" msgid="7374910700117359177">"பயனர் வரம்பை அடைந்துவிட்டீர்கள்"</string>
+ <plurals name="user_limit_reached_message" formatted="false" msgid="1855040563671964242">
+ <item quantity="other"><xliff:g id="COUNT">%d</xliff:g> பயனர்கள் வரை சேர்க்க முடியும்.</item>
+ <item quantity="one">ஒரு பயனரை மட்டுமே சேர்க்க முடியும்.</item>
+ </plurals>
<string name="user_remove_user_title" msgid="4681256956076895559">"பயனரை அகற்றவா?"</string>
<string name="user_remove_user_message" msgid="1453218013959498039">"இந்தப் பயனரின் எல்லா பயன்பாடுகளும் தரவும் நீக்கப்படும்."</string>
<string name="user_remove_user_remove" msgid="7479275741742178297">"அகற்று"</string>
@@ -732,8 +734,7 @@
<string name="left_icon" msgid="3096287125959387541">"இடப்புற ஐகான்"</string>
<string name="right_icon" msgid="3952104823293824311">"வலப்புற ஐகான்"</string>
<string name="drag_to_add_tiles" msgid="230586591689084925">"கட்டங்களைச் சேர்க்க, அவற்றைப் பிடித்து இழுக்கவும்"</string>
- <!-- no translation found for drag_to_rearrange_tiles (4566074720193667473) -->
- <skip />
+ <string name="drag_to_rearrange_tiles" msgid="4566074720193667473">"கட்டங்களை மறுவரிசைப்படுத்த அவற்றைப் பிடித்து இழுக்கவும்"</string>
<string name="drag_to_remove_tiles" msgid="3361212377437088062">"அகற்ற, இங்கே இழுக்கவும்"</string>
<string name="drag_to_remove_disabled" msgid="2390968976638993382">"குறைந்தது 6 கட்டங்கள் தேவை"</string>
<string name="qs_edit" msgid="2232596095725105230">"மாற்று"</string>
diff --git a/packages/SystemUI/res/values-te/strings.xml b/packages/SystemUI/res/values-te/strings.xml
index fc48ac1a64a6..7c096992b6f5 100644
--- a/packages/SystemUI/res/values-te/strings.xml
+++ b/packages/SystemUI/res/values-te/strings.xml
@@ -426,9 +426,11 @@
<string name="user_logout_notification_action" msgid="1195428991423425062">"వినియోగదారుని లాగ్ అవుట్ చేయి"</string>
<string name="user_add_user_title" msgid="4553596395824132638">"కొత్త వినియోగదారుని జోడించాలా?"</string>
<string name="user_add_user_message_short" msgid="2161624834066214559">"మీరు కొత్త వినియోగదారుని జోడించినప్పుడు, ఆ వ్యక్తి తన స్థలాన్ని సెటప్ చేసుకోవాలి.\n\nఏ వినియోగదారు అయినా మిగతా అందరు వినియోగదారుల కోసం అనువర్తనాలను నవీకరించగలరు."</string>
- <!-- no translation found for user_limit_reached_title (7374910700117359177) -->
- <skip />
- <!-- no translation found for user_limit_reached_message (1855040563671964242) -->
+ <string name="user_limit_reached_title" msgid="7374910700117359177">"వినియోగదారు పరిమితిని చేరుకున్నారు"</string>
+ <plurals name="user_limit_reached_message" formatted="false" msgid="1855040563671964242">
+ <item quantity="other">మీరు <xliff:g id="COUNT">%d</xliff:g> వినియోగదారుల వరకు జోడించవచ్చు.</item>
+ <item quantity="one">ఒక్క వినియోగదారుని మాత్రమే సృష్టించవచ్చు.</item>
+ </plurals>
<string name="user_remove_user_title" msgid="4681256956076895559">"వినియోగదారుని తీసివేయాలా?"</string>
<string name="user_remove_user_message" msgid="1453218013959498039">"ఈ వినియోగదారుకు సంబంధించిన అన్ని అనువర్తనాలు మరియు డేటా తొలగించబడతాయి."</string>
<string name="user_remove_user_remove" msgid="7479275741742178297">"తీసివేయి"</string>
@@ -732,8 +734,7 @@
<string name="left_icon" msgid="3096287125959387541">"ఎడమ వైపు చిహ్నం"</string>
<string name="right_icon" msgid="3952104823293824311">"కుడివైపు ఉన్న చిహ్నం"</string>
<string name="drag_to_add_tiles" msgid="230586591689084925">"టైల్‌లను జోడించడం కోసం పట్టుకుని, లాగండి"</string>
- <!-- no translation found for drag_to_rearrange_tiles (4566074720193667473) -->
- <skip />
+ <string name="drag_to_rearrange_tiles" msgid="4566074720193667473">"టైల్‌ల క్రమం మార్చడానికి వాటిని పట్టుకుని, లాగండి"</string>
<string name="drag_to_remove_tiles" msgid="3361212377437088062">"తీసివేయడానికి ఇక్కడికి లాగండి"</string>
<string name="drag_to_remove_disabled" msgid="2390968976638993382">"మీ వద్ద కనీసం 6 టైల్‌లు ఉండాలి"</string>
<string name="qs_edit" msgid="2232596095725105230">"సవరించు"</string>
diff --git a/packages/SystemUI/res/values-th/strings.xml b/packages/SystemUI/res/values-th/strings.xml
index bf619864527d..1d59868b046a 100644
--- a/packages/SystemUI/res/values-th/strings.xml
+++ b/packages/SystemUI/res/values-th/strings.xml
@@ -426,14 +426,16 @@
<string name="user_logout_notification_action" msgid="1195428991423425062">"ออกจากระบบผู้ใช้"</string>
<string name="user_add_user_title" msgid="4553596395824132638">"ต้องการเพิ่มผู้ใช้ใหม่ใช่ไหม"</string>
<string name="user_add_user_message_short" msgid="2161624834066214559">"เมื่อคุณเพิ่มผู้ใช้ใหม่ ผู้ใช้ดังกล่าวจะต้องตั้งค่าพื้นที่ของตนเอง\n\nผู้ใช้ทุกคนสามารถอัปเดตแอปสำหรับผู้ใช้รายอื่นทุกคนได้"</string>
- <!-- no translation found for user_limit_reached_title (7374910700117359177) -->
- <skip />
- <!-- no translation found for user_limit_reached_message (1855040563671964242) -->
+ <string name="user_limit_reached_title" msgid="7374910700117359177">"ถึงขีดจำกัดผู้ใช้แล้ว"</string>
+ <plurals name="user_limit_reached_message" formatted="false" msgid="1855040563671964242">
+ <item quantity="other">คุณเพิ่มผู้ใช้ได้สูงสุด <xliff:g id="COUNT">%d</xliff:g> คน</item>
+ <item quantity="one">สร้างผู้ใช้ได้เพียง 1 คนเท่านั้น</item>
+ </plurals>
<string name="user_remove_user_title" msgid="4681256956076895559">"นำผู้ใช้ออกใช่ไหม"</string>
<string name="user_remove_user_message" msgid="1453218013959498039">"แอปและข้อมูลทั้งหมดของผู้ใช้นี้จะถูกลบ"</string>
<string name="user_remove_user_remove" msgid="7479275741742178297">"นำออก"</string>
<string name="battery_saver_notification_title" msgid="8614079794522291840">"เปิดโหมดประหยัดแบตเตอรี่อยู่"</string>
- <string name="battery_saver_notification_text" msgid="820318788126672692">"ลดการใช้แบตเตอรี่และข้อมูลแบ็กกราวด์"</string>
+ <string name="battery_saver_notification_text" msgid="820318788126672692">"ลดการใช้แบตเตอรี่และอินเทอร์เน็ตที่ใช้งานอยู่เบื้องหลัง"</string>
<string name="battery_saver_notification_action_text" msgid="132118784269455533">"ปิดโหมดประหยัดแบตเตอรี่"</string>
<string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> จะเริ่มจับภาพทุกอย่างที่แสดงบนหน้าจอ"</string>
<string name="media_projection_remember_text" msgid="3103510882172746752">"ไม่ต้องแสดงข้อความนี้อีก"</string>
@@ -646,7 +648,7 @@
<string name="battery_panel_title" msgid="7944156115535366613">"การใช้งานแบตเตอรี่"</string>
<string name="battery_detail_charging_summary" msgid="1279095653533044008">"ไม่สามารถใช้โหมดประหยัดแบตเตอรี่ระหว่างการชาร์จ"</string>
<string name="battery_detail_switch_title" msgid="6285872470260795421">"โหมดประหยัดแบตเตอรี่"</string>
- <string name="battery_detail_switch_summary" msgid="9049111149407626804">"ลดประสิทธิภาพการทำงานและข้อมูลแบ็กกราวด์"</string>
+ <string name="battery_detail_switch_summary" msgid="9049111149407626804">"ลดประสิทธิภาพการทำงานและอินเทอร์เน็ตที่ใช้งานอยู่เบื้องหลัง"</string>
<string name="keyboard_key_button_template" msgid="6230056639734377300">"ปุ่ม <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="keyboard_key_home" msgid="2243500072071305073">"Home"</string>
<string name="keyboard_key_back" msgid="2337450286042721351">"กลับ"</string>
@@ -732,8 +734,7 @@
<string name="left_icon" msgid="3096287125959387541">"ไอคอนทางซ้าย"</string>
<string name="right_icon" msgid="3952104823293824311">"ไอคอนทางขวา"</string>
<string name="drag_to_add_tiles" msgid="230586591689084925">"กดชิ้นส่วนค้างไว้แล้วลากไปเพื่อเพิ่ม"</string>
- <!-- no translation found for drag_to_rearrange_tiles (4566074720193667473) -->
- <skip />
+ <string name="drag_to_rearrange_tiles" msgid="4566074720193667473">"กดชิ้นส่วนค้างไว้แล้วลากไปเพื่อจัดลำดับใหม่"</string>
<string name="drag_to_remove_tiles" msgid="3361212377437088062">"ลากมาที่นี่เพื่อนำออก"</string>
<string name="drag_to_remove_disabled" msgid="2390968976638993382">"คุณต้องมีชิ้นส่วนอย่างน้อย 6 ชิ้น"</string>
<string name="qs_edit" msgid="2232596095725105230">"แก้ไข"</string>
diff --git a/packages/SystemUI/res/values-tl/strings.xml b/packages/SystemUI/res/values-tl/strings.xml
index fef76327b46a..013acd427630 100644
--- a/packages/SystemUI/res/values-tl/strings.xml
+++ b/packages/SystemUI/res/values-tl/strings.xml
@@ -426,9 +426,11 @@
<string name="user_logout_notification_action" msgid="1195428991423425062">"I-LOGOUT ANG USER"</string>
<string name="user_add_user_title" msgid="4553596395824132638">"Magdagdag ng bagong user?"</string>
<string name="user_add_user_message_short" msgid="2161624834066214559">"Kapag nagdagdag ka ng bagong user, kailangang i-set up ng taong iyon ang kanyang espasyo.\n\nAng sinumang user ay maaaring mag-update ng mga app para sa lahat ng iba pang user."</string>
- <!-- no translation found for user_limit_reached_title (7374910700117359177) -->
- <skip />
- <!-- no translation found for user_limit_reached_message (1855040563671964242) -->
+ <string name="user_limit_reached_title" msgid="7374910700117359177">"Naabot na ang limitasyon sa user"</string>
+ <plurals name="user_limit_reached_message" formatted="false" msgid="1855040563671964242">
+ <item quantity="one">Maaari kang magdagdag ng hanggang <xliff:g id="COUNT">%d</xliff:g> user.</item>
+ <item quantity="other">Maaari kang magdagdag ng hanggang <xliff:g id="COUNT">%d</xliff:g> na user.</item>
+ </plurals>
<string name="user_remove_user_title" msgid="4681256956076895559">"Gusto mo bang alisin ang user?"</string>
<string name="user_remove_user_message" msgid="1453218013959498039">"Made-delete ang lahat ng app at data ng user na ito."</string>
<string name="user_remove_user_remove" msgid="7479275741742178297">"Alisin"</string>
@@ -732,8 +734,7 @@
<string name="left_icon" msgid="3096287125959387541">"Icon ng kaliwa"</string>
<string name="right_icon" msgid="3952104823293824311">"Icon ng kanan"</string>
<string name="drag_to_add_tiles" msgid="230586591689084925">"Pindutin nang matagal at i-drag para magdagdag ng mga tile"</string>
- <!-- no translation found for drag_to_rearrange_tiles (4566074720193667473) -->
- <skip />
+ <string name="drag_to_rearrange_tiles" msgid="4566074720193667473">"Pindutin nang matagal at i-drag para ayusing muli ang tile"</string>
<string name="drag_to_remove_tiles" msgid="3361212377437088062">"I-drag dito upang alisin"</string>
<string name="drag_to_remove_disabled" msgid="2390968976638993382">"Kailangan mo ng hindi bababa sa 6 na tile"</string>
<string name="qs_edit" msgid="2232596095725105230">"I-edit"</string>
diff --git a/packages/SystemUI/res/values-tr/strings.xml b/packages/SystemUI/res/values-tr/strings.xml
index fd8ab73df641..9030113bfbf6 100644
--- a/packages/SystemUI/res/values-tr/strings.xml
+++ b/packages/SystemUI/res/values-tr/strings.xml
@@ -426,9 +426,11 @@
<string name="user_logout_notification_action" msgid="1195428991423425062">"KULLANICI OTURUMUNU KAPAT"</string>
<string name="user_add_user_title" msgid="4553596395824132638">"Yeni kullanıcı eklensin mi?"</string>
<string name="user_add_user_message_short" msgid="2161624834066214559">"Yeni bir kullanıcı eklediğinizde, bu kişinin kendi alanını ayarlaması gerekir.\n\nHerhangi bir kullanıcı, diğer tüm kullanıcılar için uygulamaları güncelleyebilir."</string>
- <!-- no translation found for user_limit_reached_title (7374910700117359177) -->
- <skip />
- <!-- no translation found for user_limit_reached_message (1855040563671964242) -->
+ <string name="user_limit_reached_title" msgid="7374910700117359177">"Kullanıcı sınırına ulaşıldı"</string>
+ <plurals name="user_limit_reached_message" formatted="false" msgid="1855040563671964242">
+ <item quantity="other">En fazla <xliff:g id="COUNT">%d</xliff:g> kullanıcı ekleyebilirsiniz.</item>
+ <item quantity="one">Yalnızca bir kullanıcı oluşturulabilir.</item>
+ </plurals>
<string name="user_remove_user_title" msgid="4681256956076895559">"Kullanıcı kaldırılsın mı?"</string>
<string name="user_remove_user_message" msgid="1453218013959498039">"Bu kullanıcının tüm uygulamaları ve verileri silinecek."</string>
<string name="user_remove_user_remove" msgid="7479275741742178297">"Kaldır"</string>
@@ -732,8 +734,7 @@
<string name="left_icon" msgid="3096287125959387541">"Sol simge"</string>
<string name="right_icon" msgid="3952104823293824311">"Sağ simge"</string>
<string name="drag_to_add_tiles" msgid="230586591689084925">"Blok eklemek için basılı tutup sürükleyin"</string>
- <!-- no translation found for drag_to_rearrange_tiles (4566074720193667473) -->
- <skip />
+ <string name="drag_to_rearrange_tiles" msgid="4566074720193667473">"Blokları yeniden düzenlemek için basılı tutun ve sürükleyin"</string>
<string name="drag_to_remove_tiles" msgid="3361212377437088062">"Kaldırmak için buraya sürükleyin"</string>
<string name="drag_to_remove_disabled" msgid="2390968976638993382">"En az 6 blok gerekiyor"</string>
<string name="qs_edit" msgid="2232596095725105230">"Düzenle"</string>
diff --git a/packages/SystemUI/res/values-uk/strings.xml b/packages/SystemUI/res/values-uk/strings.xml
index 7d61d37df200..cf21c0f03d47 100644
--- a/packages/SystemUI/res/values-uk/strings.xml
+++ b/packages/SystemUI/res/values-uk/strings.xml
@@ -434,9 +434,13 @@
<string name="user_logout_notification_action" msgid="1195428991423425062">"ВИЙТИ З ОБЛІКОВОГО ЗАПИСУ"</string>
<string name="user_add_user_title" msgid="4553596395824132638">"Додати нового користувача?"</string>
<string name="user_add_user_message_short" msgid="2161624834066214559">"Користувач має налаштувати свій профіль після створення.\n\nБудь-який користувач пристрою може оновлювати додатки для решти користувачів."</string>
- <!-- no translation found for user_limit_reached_title (7374910700117359177) -->
- <skip />
- <!-- no translation found for user_limit_reached_message (1855040563671964242) -->
+ <string name="user_limit_reached_title" msgid="7374910700117359177">"Ви досягли ліміту користувачів"</string>
+ <plurals name="user_limit_reached_message" formatted="false" msgid="1855040563671964242">
+ <item quantity="one">Можна додати до <xliff:g id="COUNT">%d</xliff:g> користувача.</item>
+ <item quantity="few">Можна додати до <xliff:g id="COUNT">%d</xliff:g> користувачів.</item>
+ <item quantity="many">Можна додати до <xliff:g id="COUNT">%d</xliff:g> користувачів.</item>
+ <item quantity="other">Можна додати до <xliff:g id="COUNT">%d</xliff:g> користувача.</item>
+ </plurals>
<string name="user_remove_user_title" msgid="4681256956076895559">"Видалити користувача?"</string>
<string name="user_remove_user_message" msgid="1453218013959498039">"Усі додатки й дані цього користувача буде видалено."</string>
<string name="user_remove_user_remove" msgid="7479275741742178297">"Видалити"</string>
@@ -744,8 +748,7 @@
<string name="left_icon" msgid="3096287125959387541">"Значок ліворуч"</string>
<string name="right_icon" msgid="3952104823293824311">"Значок праворуч"</string>
<string name="drag_to_add_tiles" msgid="230586591689084925">"Натисніть і перетягніть, щоб додати фрагменти"</string>
- <!-- no translation found for drag_to_rearrange_tiles (4566074720193667473) -->
- <skip />
+ <string name="drag_to_rearrange_tiles" msgid="4566074720193667473">"Щоб упорядковувати компоненти, перетягуйте їх"</string>
<string name="drag_to_remove_tiles" msgid="3361212377437088062">"Перетягніть сюди, щоб видалити"</string>
<string name="drag_to_remove_disabled" msgid="2390968976638993382">"Потрібно принаймні 6 фрагментів"</string>
<string name="qs_edit" msgid="2232596095725105230">"Редагувати"</string>
diff --git a/packages/SystemUI/res/values-ur/strings.xml b/packages/SystemUI/res/values-ur/strings.xml
index dbdc03446d9a..d2ee8c760185 100644
--- a/packages/SystemUI/res/values-ur/strings.xml
+++ b/packages/SystemUI/res/values-ur/strings.xml
@@ -426,9 +426,11 @@
<string name="user_logout_notification_action" msgid="1195428991423425062">"صارف لاگ آؤٹ کریں"</string>
<string name="user_add_user_title" msgid="4553596395824132638">"نیا صارف شامل کریں؟"</string>
<string name="user_add_user_message_short" msgid="2161624834066214559">"جب آپ ایک نیا صارف شامل کرتے ہیں تو اس شخص کو اپنی جگہ کو ترتیب دینے کی ضرورت ہوتی ہے۔\n\nکوئی بھی صارف دیگر سبھی صارفین کیلئے ایپس کو اپ ڈیٹ کر سکتا ہے۔"</string>
- <!-- no translation found for user_limit_reached_title (7374910700117359177) -->
- <skip />
- <!-- no translation found for user_limit_reached_message (1855040563671964242) -->
+ <string name="user_limit_reached_title" msgid="7374910700117359177">"صارف کی حد مکمل ہو گئی"</string>
+ <plurals name="user_limit_reached_message" formatted="false" msgid="1855040563671964242">
+ <item quantity="other">صرف <xliff:g id="COUNT">%d</xliff:g> صارفین بنائے جا سکتے ہیں۔</item>
+ <item quantity="one">صرف ایک صارف بنایا جا سکتا ہے۔</item>
+ </plurals>
<string name="user_remove_user_title" msgid="4681256956076895559">"صارف کو ہٹائیں؟"</string>
<string name="user_remove_user_message" msgid="1453218013959498039">"اس صارف کی سبھی ایپس اور ڈیٹا حذف کر دیا جائے گا۔"</string>
<string name="user_remove_user_remove" msgid="7479275741742178297">"ہٹائیں"</string>
@@ -732,8 +734,7 @@
<string name="left_icon" msgid="3096287125959387541">"بائیں جانب کا آئیکن"</string>
<string name="right_icon" msgid="3952104823293824311">"دائيں جانب کا آئيکن"</string>
<string name="drag_to_add_tiles" msgid="230586591689084925">"ٹائلز شامل کرنے کے لئے پکڑ کر گھسیٹیں"</string>
- <!-- no translation found for drag_to_rearrange_tiles (4566074720193667473) -->
- <skip />
+ <string name="drag_to_rearrange_tiles" msgid="4566074720193667473">"ٹائلز کو دوبارہ ترتیب دینے کیلئے پکڑ کر گھسیٹیں"</string>
<string name="drag_to_remove_tiles" msgid="3361212377437088062">"ہٹانے کیلئے یہاں گھسیٹیں؟"</string>
<string name="drag_to_remove_disabled" msgid="2390968976638993382">"آپ کو کم از کم 6 ٹائلز کی ضرورت ہے"</string>
<string name="qs_edit" msgid="2232596095725105230">"ترمیم کریں"</string>
diff --git a/packages/SystemUI/res/values-uz/strings.xml b/packages/SystemUI/res/values-uz/strings.xml
index f4403e7e3122..2c45ab80156e 100644
--- a/packages/SystemUI/res/values-uz/strings.xml
+++ b/packages/SystemUI/res/values-uz/strings.xml
@@ -428,9 +428,11 @@
<string name="user_logout_notification_action" msgid="1195428991423425062">"FOYDALANUVCHI NOMIDAN CHIQISH"</string>
<string name="user_add_user_title" msgid="4553596395824132638">"Foydalanuvchi qo‘shilsinmi?"</string>
<string name="user_add_user_message_short" msgid="2161624834066214559">"Yangi profil qo‘shilgach, uni sozlash lozim.\n\nQurilmaning istalgan foydalanuvchisi ilovalarni barcha hisoblar uchun yangilashi mumkin."</string>
- <!-- no translation found for user_limit_reached_title (7374910700117359177) -->
- <skip />
- <!-- no translation found for user_limit_reached_message (1855040563671964242) -->
+ <string name="user_limit_reached_title" msgid="7374910700117359177">"Limitga yetib keldi"</string>
+ <plurals name="user_limit_reached_message" formatted="false" msgid="1855040563671964242">
+ <item quantity="other"><xliff:g id="COUNT">%d</xliff:g> tagacha foydalanuvchi qo‘shish mumkin.</item>
+ <item quantity="one">Faqat bitta foydalanuvchi yaratish mumkin.</item>
+ </plurals>
<string name="user_remove_user_title" msgid="4681256956076895559">"Foydalanuvchi olib tashlansinmi?"</string>
<string name="user_remove_user_message" msgid="1453218013959498039">"Ushbu foydalanuvchining barcha ilovalari va ma’lumotlari o‘chirib tashlanadi."</string>
<string name="user_remove_user_remove" msgid="7479275741742178297">"Olib tashlash"</string>
@@ -734,8 +736,7 @@
<string name="left_icon" msgid="3096287125959387541">"Chapga belgisi"</string>
<string name="right_icon" msgid="3952104823293824311">"O‘ngga belgisi"</string>
<string name="drag_to_add_tiles" msgid="230586591689084925">"Keraklisini ushlab torting"</string>
- <!-- no translation found for drag_to_rearrange_tiles (4566074720193667473) -->
- <skip />
+ <string name="drag_to_rearrange_tiles" msgid="4566074720193667473">"Qayta tartiblash uchun ushlab torting"</string>
<string name="drag_to_remove_tiles" msgid="3361212377437088062">"O‘chirish uchun bu yerga torting"</string>
<string name="drag_to_remove_disabled" msgid="2390968976638993382">"Kamida 6 ta katakcha lozim"</string>
<string name="qs_edit" msgid="2232596095725105230">"Tahrirlash"</string>
diff --git a/packages/SystemUI/res/values-vi/strings.xml b/packages/SystemUI/res/values-vi/strings.xml
index d8fd0ebf12aa..8c5e10de3fed 100644
--- a/packages/SystemUI/res/values-vi/strings.xml
+++ b/packages/SystemUI/res/values-vi/strings.xml
@@ -204,8 +204,8 @@
<string name="accessibility_quick_settings_wifi_changed_on" msgid="6440117170789528622">"Đã bật Wifi."</string>
<string name="accessibility_quick_settings_mobile" msgid="4876806564086241341">"Di động <xliff:g id="SIGNAL">%1$s</xliff:g>. <xliff:g id="TYPE">%2$s</xliff:g>. <xliff:g id="NETWORK">%3$s</xliff:g>."</string>
<string name="accessibility_quick_settings_battery" msgid="1480931583381408972">"Pin <xliff:g id="STATE">%s</xliff:g>."</string>
- <string name="accessibility_quick_settings_airplane_off" msgid="7786329360056634412">"Chế độ trên máy bay tắt."</string>
- <string name="accessibility_quick_settings_airplane_on" msgid="6406141469157599296">"Chế độ trên máy bay bật."</string>
+ <string name="accessibility_quick_settings_airplane_off" msgid="7786329360056634412">"Chế độ trên máy bay đang tắt."</string>
+ <string name="accessibility_quick_settings_airplane_on" msgid="6406141469157599296">"Chế độ trên máy bay đang bật."</string>
<string name="accessibility_quick_settings_airplane_changed_off" msgid="66846307818850664">"Đã tắt chế độ trên máy bay."</string>
<string name="accessibility_quick_settings_airplane_changed_on" msgid="8983005603505087728">"Đã bật chế độ trên máy bay."</string>
<string name="accessibility_quick_settings_dnd_none_on" msgid="2960643943620637020">"hoàn toàn tắt tiếng"</string>
@@ -426,9 +426,11 @@
<string name="user_logout_notification_action" msgid="1195428991423425062">"ĐĂNG XUẤT NGƯỜI DÙNG"</string>
<string name="user_add_user_title" msgid="4553596395824132638">"Thêm người dùng mới?"</string>
<string name="user_add_user_message_short" msgid="2161624834066214559">"Khi bạn thêm người dùng mới, người dùng đó cần thiết lập dung lượng lưu trữ của mình.\n\nMọi người dùng đều có thể cập nhật ứng dụng cho tất cả người dùng khác."</string>
- <!-- no translation found for user_limit_reached_title (7374910700117359177) -->
- <skip />
- <!-- no translation found for user_limit_reached_message (1855040563671964242) -->
+ <string name="user_limit_reached_title" msgid="7374910700117359177">"Đã đạt đến giới hạn người dùng"</string>
+ <plurals name="user_limit_reached_message" formatted="false" msgid="1855040563671964242">
+ <item quantity="other">Bạn có thể thêm tối đa <xliff:g id="COUNT">%d</xliff:g> người dùng.</item>
+ <item quantity="one">Chỉ có thể tạo một người dùng.</item>
+ </plurals>
<string name="user_remove_user_title" msgid="4681256956076895559">"Xóa người dùng?"</string>
<string name="user_remove_user_message" msgid="1453218013959498039">"Tất cả các ứng dụng và dữ liệu của người dùng này sẽ bị xóa."</string>
<string name="user_remove_user_remove" msgid="7479275741742178297">"Xóa"</string>
@@ -732,8 +734,7 @@
<string name="left_icon" msgid="3096287125959387541">"Biểu tượng bên trái"</string>
<string name="right_icon" msgid="3952104823293824311">"Biểu tượng bên phải"</string>
<string name="drag_to_add_tiles" msgid="230586591689084925">"Giữ và kéo để thêm ô"</string>
- <!-- no translation found for drag_to_rearrange_tiles (4566074720193667473) -->
- <skip />
+ <string name="drag_to_rearrange_tiles" msgid="4566074720193667473">"Giữ và kéo để sắp xếp lại các ô"</string>
<string name="drag_to_remove_tiles" msgid="3361212377437088062">"Kéo vào đây để xóa"</string>
<string name="drag_to_remove_disabled" msgid="2390968976638993382">"Bạn cần ít nhất 6 ô"</string>
<string name="qs_edit" msgid="2232596095725105230">"Chỉnh sửa"</string>
diff --git a/packages/SystemUI/res/values-zh-rCN/strings.xml b/packages/SystemUI/res/values-zh-rCN/strings.xml
index c7443febafe3..6259bfd31f3a 100644
--- a/packages/SystemUI/res/values-zh-rCN/strings.xml
+++ b/packages/SystemUI/res/values-zh-rCN/strings.xml
@@ -426,9 +426,11 @@
<string name="user_logout_notification_action" msgid="1195428991423425062">"退出当前用户"</string>
<string name="user_add_user_title" msgid="4553596395824132638">"要添加新用户吗?"</string>
<string name="user_add_user_message_short" msgid="2161624834066214559">"当您添加新用户时,该用户必须设置自己的空间。\n\n任何用户均可为其他所有用户更新应用。"</string>
- <!-- no translation found for user_limit_reached_title (7374910700117359177) -->
- <skip />
- <!-- no translation found for user_limit_reached_message (1855040563671964242) -->
+ <string name="user_limit_reached_title" msgid="7374910700117359177">"已达到用户数上限"</string>
+ <plurals name="user_limit_reached_message" formatted="false" msgid="1855040563671964242">
+ <item quantity="other">您最多可以添加 <xliff:g id="COUNT">%d</xliff:g> 位用户。</item>
+ <item quantity="one">您只能创建一位用户。</item>
+ </plurals>
<string name="user_remove_user_title" msgid="4681256956076895559">"是否移除用户?"</string>
<string name="user_remove_user_message" msgid="1453218013959498039">"此用户的所有应用和数据均将被删除。"</string>
<string name="user_remove_user_remove" msgid="7479275741742178297">"移除"</string>
@@ -732,8 +734,7 @@
<string name="left_icon" msgid="3096287125959387541">"向左图标"</string>
<string name="right_icon" msgid="3952104823293824311">"向右图标"</string>
<string name="drag_to_add_tiles" msgid="230586591689084925">"按住并拖动即可添加图块"</string>
- <!-- no translation found for drag_to_rearrange_tiles (4566074720193667473) -->
- <skip />
+ <string name="drag_to_rearrange_tiles" msgid="4566074720193667473">"按住并拖动即可重新排列图块"</string>
<string name="drag_to_remove_tiles" msgid="3361212377437088062">"拖动到此处即可移除"</string>
<string name="drag_to_remove_disabled" msgid="2390968976638993382">"您至少需要 6 个图块"</string>
<string name="qs_edit" msgid="2232596095725105230">"编辑"</string>
diff --git a/packages/SystemUI/res/values-zh-rHK/strings.xml b/packages/SystemUI/res/values-zh-rHK/strings.xml
index dace26a82725..aa19f4fb9f13 100644
--- a/packages/SystemUI/res/values-zh-rHK/strings.xml
+++ b/packages/SystemUI/res/values-zh-rHK/strings.xml
@@ -428,9 +428,11 @@
<string name="user_logout_notification_action" msgid="1195428991423425062">"登出使用者"</string>
<string name="user_add_user_title" msgid="4553596395824132638">"新增使用者?"</string>
<string name="user_add_user_message_short" msgid="2161624834066214559">"新增的使用者需要自行設定個人空間。\n\n任何使用者均可為所有其他使用者更新應用程式。"</string>
- <!-- no translation found for user_limit_reached_title (7374910700117359177) -->
- <skip />
- <!-- no translation found for user_limit_reached_message (1855040563671964242) -->
+ <string name="user_limit_reached_title" msgid="7374910700117359177">"已達到使用者上限"</string>
+ <plurals name="user_limit_reached_message" formatted="false" msgid="1855040563671964242">
+ <item quantity="other">您可以加入多達 <xliff:g id="COUNT">%d</xliff:g> 個使用者。</item>
+ <item quantity="one">只可以建立一個使用者。</item>
+ </plurals>
<string name="user_remove_user_title" msgid="4681256956076895559">"移除使用者?"</string>
<string name="user_remove_user_message" msgid="1453218013959498039">"系統將會刪除這個使用者的所有應用程式和資料。"</string>
<string name="user_remove_user_remove" msgid="7479275741742178297">"移除"</string>
@@ -734,8 +736,7 @@
<string name="left_icon" msgid="3096287125959387541">"向左圖示"</string>
<string name="right_icon" msgid="3952104823293824311">"向右圖示"</string>
<string name="drag_to_add_tiles" msgid="230586591689084925">"按住並拖曳即可新增圖塊"</string>
- <!-- no translation found for drag_to_rearrange_tiles (4566074720193667473) -->
- <skip />
+ <string name="drag_to_rearrange_tiles" msgid="4566074720193667473">"按住並拖曳即可重新排列圖塊"</string>
<string name="drag_to_remove_tiles" msgid="3361212377437088062">"拖曳這裡即可移除"</string>
<string name="drag_to_remove_disabled" msgid="2390968976638993382">"您必須至少有 6 個圖塊"</string>
<string name="qs_edit" msgid="2232596095725105230">"編輯"</string>
diff --git a/packages/SystemUI/res/values-zh-rTW/strings.xml b/packages/SystemUI/res/values-zh-rTW/strings.xml
index c1be1fbaf4a1..363c61045319 100644
--- a/packages/SystemUI/res/values-zh-rTW/strings.xml
+++ b/packages/SystemUI/res/values-zh-rTW/strings.xml
@@ -426,9 +426,11 @@
<string name="user_logout_notification_action" msgid="1195428991423425062">"登出使用者"</string>
<string name="user_add_user_title" msgid="4553596395824132638">"新增使用者?"</string>
<string name="user_add_user_message_short" msgid="2161624834066214559">"新增的使用者需要自行設定個人空間。\n\n任何使用者皆可為其他所有使用者更新應用程式。"</string>
- <!-- no translation found for user_limit_reached_title (7374910700117359177) -->
- <skip />
- <!-- no translation found for user_limit_reached_message (1855040563671964242) -->
+ <string name="user_limit_reached_title" msgid="7374910700117359177">"已達使用者數量上限"</string>
+ <plurals name="user_limit_reached_message" formatted="false" msgid="1855040563671964242">
+ <item quantity="other">最多可新增 <xliff:g id="COUNT">%d</xliff:g> 位使用者。</item>
+ <item quantity="one">只能建立 1 位使用者。</item>
+ </plurals>
<string name="user_remove_user_title" msgid="4681256956076895559">"要移除使用者嗎?"</string>
<string name="user_remove_user_message" msgid="1453218013959498039">"系統將刪除這個使用者的所有應用程式和資料。"</string>
<string name="user_remove_user_remove" msgid="7479275741742178297">"移除"</string>
@@ -732,8 +734,7 @@
<string name="left_icon" msgid="3096287125959387541">"向左圖示"</string>
<string name="right_icon" msgid="3952104823293824311">"向右圖示"</string>
<string name="drag_to_add_tiles" msgid="230586591689084925">"按住並拖曳即可新增圖塊"</string>
- <!-- no translation found for drag_to_rearrange_tiles (4566074720193667473) -->
- <skip />
+ <string name="drag_to_rearrange_tiles" msgid="4566074720193667473">"按住並拖曳即可重新排列圖塊"</string>
<string name="drag_to_remove_tiles" msgid="3361212377437088062">"拖曳到這裡即可移除"</string>
<string name="drag_to_remove_disabled" msgid="2390968976638993382">"你至少必須要有 6 個圖塊"</string>
<string name="qs_edit" msgid="2232596095725105230">"編輯"</string>
diff --git a/packages/SystemUI/res/values-zu/strings.xml b/packages/SystemUI/res/values-zu/strings.xml
index 5be16e3114d7..0e4729bcbac9 100644
--- a/packages/SystemUI/res/values-zu/strings.xml
+++ b/packages/SystemUI/res/values-zu/strings.xml
@@ -426,9 +426,11 @@
<string name="user_logout_notification_action" msgid="1195428991423425062">"KHIPHA UMSEBENZISI"</string>
<string name="user_add_user_title" msgid="4553596395824132638">"Engeza umsebenzisi omusha?"</string>
<string name="user_add_user_message_short" msgid="2161624834066214559">"Uma ungeza umsebenzisi omusha, loyo muntu udinga ukusetha isikhala sakhe.\n\nNoma yimuphi umsebenzisi angabuyekeza izinhlelo zokusebenza kubo bonke abasebenzisi."</string>
- <!-- no translation found for user_limit_reached_title (7374910700117359177) -->
- <skip />
- <!-- no translation found for user_limit_reached_message (1855040563671964242) -->
+ <string name="user_limit_reached_title" msgid="7374910700117359177">"Kufinyelelwe kumkhawulo womsebenzisi"</string>
+ <plurals name="user_limit_reached_message" formatted="false" msgid="1855040563671964242">
+ <item quantity="one">Ungangeza kufikela kubasebenzisi abangu-<xliff:g id="COUNT">%d</xliff:g>.</item>
+ <item quantity="other">Ungangeza kufikela kubasebenzisi abangu-<xliff:g id="COUNT">%d</xliff:g>.</item>
+ </plurals>
<string name="user_remove_user_title" msgid="4681256956076895559">"Susa umsebenzisi?"</string>
<string name="user_remove_user_message" msgid="1453218013959498039">"Zonke izinhlelo zokusebenza nedatha yalo msebenzisi kuzosuswa."</string>
<string name="user_remove_user_remove" msgid="7479275741742178297">"Susa"</string>
@@ -732,8 +734,7 @@
<string name="left_icon" msgid="3096287125959387541">"Isithonjana esingakwesokunxele"</string>
<string name="right_icon" msgid="3952104823293824311">"Isithonjana sangakwesokudla"</string>
<string name="drag_to_add_tiles" msgid="230586591689084925">"Bamba uphinde uhudule ukuze ungeze amathayela"</string>
- <!-- no translation found for drag_to_rearrange_tiles (4566074720193667473) -->
- <skip />
+ <string name="drag_to_rearrange_tiles" msgid="4566074720193667473">"Bamba uphinde uhudule ukuze uphinde ulungise amathayela"</string>
<string name="drag_to_remove_tiles" msgid="3361212377437088062">"Hudulela lapha ukuze ususe"</string>
<string name="drag_to_remove_disabled" msgid="2390968976638993382">"Udinga okungenani amathayela angu-6"</string>
<string name="qs_edit" msgid="2232596095725105230">"Hlela"</string>
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSAnimator.java b/packages/SystemUI/src/com/android/systemui/qs/QSAnimator.java
index 3744d7dc7bde..f6073671dd60 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSAnimator.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSAnimator.java
@@ -155,7 +155,6 @@ public class QSAnimator implements Callback, PageListener, Listener, OnLayoutCha
TouchAnimator.Builder translationYBuilder = new Builder();
if (mQsPanel.getHost() == null) return;
- if (mQuickQsPanel.getTileLayout().getNumVisibleTiles() < 1) return;
Collection<QSTile> tiles = mQsPanel.getHost().getTiles();
int count = 0;
int[] loc1 = new int[2];
@@ -230,9 +229,10 @@ public class QSAnimator implements Callback, PageListener, Listener, OnLayoutCha
final int xDiff = loc2[0] - loc1[0];
final int yDiff = loc2[1] - loc1[1];
- firstPageBuilder.addFloat(tileView, "translationY", -heightDiff, 0);
- translationYBuilder.addFloat(tileView, "translationY", -yDiff, 0);
+ firstPageBuilder.addFloat(tileView, "translationY", heightDiff, 0);
translationXBuilder.addFloat(tileView, "translationX", -xDiff, 0);
+ translationYBuilder.addFloat(tileView, "translationY", -yDiff, 0);
+ translationYBuilder.addFloat(tileIcon, "translationY", -yDiff, 0);
mAllViews.add(tileIcon);
} else {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java b/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java
index 03febda3f4c5..c36cdf6ac262 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java
@@ -288,6 +288,7 @@ public class QSFragment extends Fragment implements QS, CommandQueue.Callbacks {
mHeader.setListening(listening);
mFooter.setListening(listening);
mQSPanel.setListening(mListening && mQsExpanded);
+ mQSPanel.getFooter().setListening(listening);
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
index 762fd75f48dc..7a57fdde6712 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
@@ -350,7 +350,6 @@ public class QSPanel extends LinearLayout implements Tunable, Callback, Brightne
if (mTileLayout != null) {
mTileLayout.setListening(listening);
}
- mFooter.setListening(mListening);
if (mListening) {
refreshAllTiles();
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSSecurityFooter.java b/packages/SystemUI/src/com/android/systemui/qs/QSSecurityFooter.java
index 6418c8075b1e..8f3a7b3c04e9 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSSecurityFooter.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSSecurityFooter.java
@@ -96,6 +96,7 @@ public class QSSecurityFooter implements OnClickListener, DialogInterface.OnClic
public void setListening(boolean listening) {
if (listening) {
mSecurityController.addCallback(mCallback);
+ refreshState();
} else {
mSecurityController.removeCallback(mCallback);
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java
index fb4fcd43a3c5..9e341e298821 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java
@@ -168,12 +168,12 @@ public class CellularTile extends QSTileImpl<SignalState> {
}
final Resources r = mContext.getResources();
- state.activityIn = cb.enabled && cb.activityIn;
- state.activityOut = cb.enabled && cb.activityOut;
state.label = r.getString(R.string.mobile_data);
boolean mobileDataEnabled = mDataController.isMobileDataSupported()
&& mDataController.isMobileDataEnabled();
state.value = mobileDataEnabled;
+ state.activityIn = mobileDataEnabled && cb.activityIn;
+ state.activityOut = mobileDataEnabled && cb.activityOut;
state.expandedAccessibilityClassName = Switch.class.getName();
if (cb.noSim) {
state.icon = ResourceIcon.get(R.drawable.ic_qs_no_sim);
@@ -231,7 +231,6 @@ public class CellularTile extends QSTileImpl<SignalState> {
}
private static final class CallbackInfo {
- boolean enabled;
boolean airplaneModeEnabled;
String dataContentDescription;
boolean activityIn;
@@ -251,7 +250,6 @@ public class CellularTile extends QSTileImpl<SignalState> {
// Not data sim, don't display.
return;
}
- mInfo.enabled = qsIcon.visible;
mInfo.dataContentDescription = typeContentDescription;
mInfo.activityIn = activityIn;
mInfo.activityOut = activityOut;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/AlertingNotificationManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/AlertingNotificationManager.java
index 35e9d55c83b6..45165180e93a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/AlertingNotificationManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/AlertingNotificationManager.java
@@ -248,7 +248,7 @@ public abstract class AlertingNotificationManager implements NotificationLifetim
}
@Override
- public void setShouldExtendLifetime(NotificationData.Entry entry, boolean shouldExtend) {
+ public void setShouldManageLifetime(NotificationData.Entry entry, boolean shouldExtend) {
if (shouldExtend) {
mExtendedLifetimeAlertEntries.add(entry);
} else {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLifetimeExtender.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLifetimeExtender.java
index 42e380f9b076..62c21dc17386 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLifetimeExtender.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLifetimeExtender.java
@@ -27,17 +27,17 @@ public interface NotificationLifetimeExtender {
boolean shouldExtendLifetime(@NonNull NotificationData.Entry entry);
/**
- * Sets whether or not the lifetime should be extended. In practice, if shouldExtend is
- * true, this is where the extender starts managing the entry internally and is now
- * responsible for calling {@link NotificationSafeToRemoveCallback#onSafeToRemove(String)} when
- * the entry is safe to remove. If shouldExtend is false, the extender no longer needs to
+ * Sets whether or not the lifetime should be managed by the extender. In practice, if
+ * shouldManage is true, this is where the extender starts managing the entry internally and is
+ * now responsible for calling {@link NotificationSafeToRemoveCallback#onSafeToRemove(String)}
+ * when the entry is safe to remove. If shouldManage is false, the extender no longer needs to
* worry about it (either because we will be removing it anyway or the entry is no longer
* removed due to an update).
*
- * @param entry the entry to mark as having an extended lifetime
- * @param shouldExtend true if the extender should manage the entry now, false otherwise
+ * @param entry the entry that needs an extended lifetime
+ * @param shouldManage true if the extender should manage the entry now, false otherwise
*/
- void setShouldExtendLifetime(@NonNull NotificationData.Entry entry, boolean shouldExtend);
+ void setShouldManageLifetime(@NonNull NotificationData.Entry entry, boolean shouldManage);
/**
* The callback for when the notification is now safe to remove (i.e. its lifetime has ended).
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationRemoteInputManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationRemoteInputManager.java
index 1a3e812a1368..ea7e03e686b5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationRemoteInputManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationRemoteInputManager.java
@@ -502,7 +502,7 @@ public class NotificationRemoteInputManager implements Dumpable {
}
@Override
- public void setShouldExtendLifetime(NotificationData.Entry entry,
+ public void setShouldManageLifetime(NotificationData.Entry entry,
boolean shouldExtend) {
if (shouldExtend) {
CharSequence remoteInputText = entry.remoteInputText;
@@ -548,7 +548,7 @@ public class NotificationRemoteInputManager implements Dumpable {
}
@Override
- public void setShouldExtendLifetime(NotificationData.Entry entry,
+ public void setShouldManageLifetime(NotificationData.Entry entry,
boolean shouldExtend) {
if (shouldExtend) {
StatusBarNotification newSbn = rebuildNotificationForCanceledSmartReplies(entry);
@@ -589,7 +589,7 @@ public class NotificationRemoteInputManager implements Dumpable {
}
@Override
- public void setShouldExtendLifetime(NotificationData.Entry entry,
+ public void setShouldManageLifetime(NotificationData.Entry entry,
boolean shouldExtend) {
if (shouldExtend) {
if (Log.isLoggable(TAG, Log.DEBUG)) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java
index ed067525ed61..304a00fbba4a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java
@@ -495,32 +495,37 @@ public class CarStatusBar extends StatusBar implements
}
@Override
- public void onUserSwitched(int newUserId) {
- super.onUserSwitched(newUserId);
- if (mFullscreenUserSwitcher != null) {
- mFullscreenUserSwitcher.onUserSwitched(newUserId);
- }
- }
-
- @Override
public void onStateChanged(int newState) {
super.onStateChanged(newState);
- CarUserManagerHelper helper = new CarUserManagerHelper(mContext);
- if (!helper.isHeadlessSystemUser()) {
- showUserSwitcher();
+ if (newState == StatusBarState.FULLSCREEN_USER_SWITCHER) {
+ if (!mFullscreenUserSwitcher.isVisible()) {
+ // Current execution path continues to set state after this, thus we deffer the
+ // dismissal to the next execution cycle.
+ postDismissKeyguard(); // Dismiss the keyguard if switcher is not visible.
+ }
+ } else {
+ mFullscreenUserSwitcher.hide();
}
}
public void showUserSwitcher() {
- if (mFullscreenUserSwitcher != null) {
- if (mState == StatusBarState.FULLSCREEN_USER_SWITCHER) {
- mFullscreenUserSwitcher.show();
- } else {
- mFullscreenUserSwitcher.hide();
- }
+ if (mFullscreenUserSwitcher != null && mState == StatusBarState.FULLSCREEN_USER_SWITCHER) {
+ mFullscreenUserSwitcher.show(); // Makes the switcher visible.
}
}
+ public void postDismissKeyguard() {
+ mHandler.post(this::dismissKeyguard);
+ }
+
+ /**
+ * Dismisses the keyguard and shows bouncer if authentication is necessary.
+ */
+ public void dismissKeyguard() {
+ executeRunnableDismissingKeyguard(null/* runnable */, null /* cancelAction */,
+ true /* dismissShade */, true /* afterKeyguardGone */, true /* deferred */);
+ }
+
@Override
public void updateMediaMetaData(boolean metaDataChanged, boolean allowEnterAnimation) {
// Do nothing, we don't want to display media art in the lock screen for a car.
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/car/FullscreenUserSwitcher.java b/packages/SystemUI/src/com/android/systemui/statusbar/car/FullscreenUserSwitcher.java
index 67a76fd86ba7..2ebf5eb39bf6 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/car/FullscreenUserSwitcher.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/car/FullscreenUserSwitcher.java
@@ -18,7 +18,6 @@ package com.android.systemui.statusbar.car;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
-import android.car.user.CarUserManagerHelper;
import android.content.Context;
import android.view.View;
import android.view.ViewStub;
@@ -26,115 +25,87 @@ import android.view.ViewStub;
import androidx.recyclerview.widget.GridLayoutManager;
import com.android.systemui.R;
-import com.android.systemui.statusbar.phone.StatusBar;
/**
* Manages the fullscreen user switcher.
*/
public class FullscreenUserSwitcher {
- private final View mContainer;
- private final View mParent;
private final UserGridRecyclerView mUserGridView;
+ private final View mParent;
private final int mShortAnimDuration;
- private final StatusBar mStatusBar;
- private final CarUserManagerHelper mCarUserManagerHelper;
- private boolean mShowing;
+ private final CarStatusBar mStatusBar;
- public FullscreenUserSwitcher(StatusBar statusBar, ViewStub containerStub, Context context) {
+ public FullscreenUserSwitcher(CarStatusBar statusBar, ViewStub containerStub, Context context) {
mStatusBar = statusBar;
mParent = containerStub.inflate();
- mContainer = mParent.findViewById(R.id.container);
- mUserGridView = mContainer.findViewById(R.id.user_grid);
+ mParent.setVisibility(View.VISIBLE);
+ View container = mParent.findViewById(R.id.container);
+
+ // Initialize user grid.
+ mUserGridView = container.findViewById(R.id.user_grid);
GridLayoutManager layoutManager = new GridLayoutManager(context,
- context.getResources().getInteger(R.integer.user_fullscreen_switcher_num_col));
+ context.getResources().getInteger(R.integer.user_fullscreen_switcher_num_col));
mUserGridView.getRecyclerView().setLayoutManager(layoutManager);
mUserGridView.buildAdapter();
mUserGridView.setUserSelectionListener(this::onUserSelected);
- mCarUserManagerHelper = new CarUserManagerHelper(context);
+ // Hide the user grid by default. It will only be made visible by clicking on a cancel
+ // button in a bouncer.
+ hide();
- mShortAnimDuration = mContainer.getResources()
+ mShortAnimDuration = container.getResources()
.getInteger(android.R.integer.config_shortAnimTime);
}
+ /**
+ * Makes user grid visible.
+ */
public void show() {
- if (mCarUserManagerHelper.isHeadlessSystemUser()) {
- showUserGrid();
- }
- if (mShowing) {
- return;
- }
- mShowing = true;
- mParent.setVisibility(View.VISIBLE);
+ mUserGridView.setVisibility(View.VISIBLE);
}
+ /**
+ * Hides the user grid.
+ */
public void hide() {
- mShowing = false;
- mParent.setVisibility(View.GONE);
+ mUserGridView.setVisibility(View.INVISIBLE);
}
- public void onUserSwitched(int newUserId) {
- toggleSwitchInProgress(false);
- mParent.post(this::dismissKeyguard);
+ /**
+ * @return {@code true} if user grid is visible, {@code false} otherwise.
+ */
+ public boolean isVisible() {
+ return mUserGridView.getVisibility() == View.VISIBLE;
}
+ /**
+ * Every time user clicks on an item in the switcher, we hide the switcher, either
+ * gradually or immediately.
+ *
+ * We dismiss the entire keyguard if user clicked on the foreground user (user we're already
+ * logged in as).
+ */
private void onUserSelected(UserGridRecyclerView.UserRecord record) {
- if (mCarUserManagerHelper.isHeadlessSystemUser()) {
- hideUserGrid();
- }
-
- if (record.mIsForeground || (record.mIsStartGuestSession
- && mCarUserManagerHelper.isForegroundUserGuest())) {
- dismissKeyguard();
+ if (record.mIsForeground) {
+ hide();
+ mStatusBar.dismissKeyguard();
return;
}
- toggleSwitchInProgress(true);
- }
-
- private void showUserGrid() {
- mUserGridView.setVisibility(View.VISIBLE);
+ // Switching is about to happen, since it takes time, fade out the switcher gradually.
+ fadeOut();
}
- private void hideUserGrid() {
- mUserGridView.setVisibility(View.INVISIBLE);
- }
-
- // Dismisses the keyguard and shows bouncer if authentication is necessary.
- private void dismissKeyguard() {
- mStatusBar.executeRunnableDismissingKeyguard(null/* runnable */, null /* cancelAction */,
- true /* dismissShade */, true /* afterKeyguardGone */, true /* deferred */);
- }
-
- private void toggleSwitchInProgress(boolean inProgress) {
- if (inProgress) {
- fadeOut(mContainer);
- } else {
- fadeIn(mContainer);
- }
- }
-
- private void fadeOut(View view) {
- view.animate()
+ private void fadeOut() {
+ mUserGridView.animate()
.alpha(0.0f)
.setDuration(mShortAnimDuration)
.setListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
- view.setVisibility(View.GONE);
+ hide();
+ mUserGridView.setAlpha(1.0f);
}
});
- }
- private void fadeIn(View view) {
- view.animate()
- .alpha(1.0f)
- .setDuration(mShortAnimDuration)
- .setListener(new AnimatorListenerAdapter() {
- @Override
- public void onAnimationStart(Animator animator) {
- view.setAlpha(0.0f);
- view.setVisibility(View.VISIBLE);
- }
- });
}
-}
+} \ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java
index 906bbb9cdd88..ac01fa32c902 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java
@@ -491,7 +491,7 @@ public class NotificationEntryManager implements Dumpable, NotificationInflater.
for (NotificationLifetimeExtender extender : mNotificationLifetimeExtenders) {
if (extender.shouldExtendLifetime(entry)) {
mLatestRankingMap = ranking;
- extender.setShouldExtendLifetime(entry, true /* shouldExtend */);
+ extender.setShouldManageLifetime(entry, true /* shouldManage */);
return;
}
}
@@ -501,7 +501,7 @@ public class NotificationEntryManager implements Dumpable, NotificationInflater.
// Ensure any managers keeping the lifetime extended stop managing the entry
for (NotificationLifetimeExtender extender: mNotificationLifetimeExtenders) {
- extender.setShouldExtendLifetime(entry, false /* shouldExtend */);
+ extender.setShouldManageLifetime(entry, false /* shouldManage */);
}
mMediaManager.onNotificationRemoved(key);
@@ -745,9 +745,9 @@ public class NotificationEntryManager implements Dumpable, NotificationInflater.
}
// Notification is updated so it is essentially re-added and thus alive again. Don't need
- // to keep it's lifetime extended.
+ // to keep its lifetime extended.
for (NotificationLifetimeExtender extender : mNotificationLifetimeExtenders) {
- extender.setShouldExtendLifetime(entry, false /* shouldExtend */);
+ extender.setShouldManageLifetime(entry, false /* shouldManage */);
}
Notification n = notification.getNotification();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/ShadeViewRefactor.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/ShadeViewRefactor.java
new file mode 100644
index 000000000000..f204c42a6324
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/ShadeViewRefactor.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package java.lang.annotation;
+
+@Retention(RetentionPolicy.SOURCE)
+public @interface ShadeViewRefactor {
+ /**
+ * Returns the refactor component.
+ * @return the refactor component.
+ */
+ RefactorComponent value();
+
+ public enum RefactorComponent {
+ ADAPTER,
+ LAYOUT_ALGORITHM,
+ STATE_RESOLVER,
+ DECORATOR,
+ INPUT,
+ COORDINATOR,
+ SHADE_VIEW
+ }
+}
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 a096baa2df9d..f4ef0f865a76 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
@@ -418,7 +418,7 @@ public class NotificationGutsManager implements Dumpable, NotificationLifetimeEx
}
@Override
- public void setShouldExtendLifetime(NotificationData.Entry entry, boolean shouldExtend) {
+ public void setShouldManageLifetime(NotificationData.Entry entry, boolean shouldExtend) {
if (shouldExtend) {
mKeyToRemoveOnGutsClosed = entry.key;
if (Log.isLoggable(TAG, Log.DEBUG)) {
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 1883aa7e7845..52844fe0a54a 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
@@ -134,6 +134,8 @@ import com.android.systemui.statusbar.policy.ScrollAdapter;
import java.io.FileDescriptor;
import java.io.PrintWriter;
+import java.lang.annotation.ShadeViewRefactor;
+import java.lang.annotation.ShadeViewRefactor.RefactorComponent;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
@@ -465,18 +467,22 @@ public class NotificationStackScrollLayout extends ViewGroup
private Interpolator mDarkXInterpolator = Interpolators.FAST_OUT_SLOW_IN;
private NotificationPanelView mNotificationPanel;
+ @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
public NotificationStackScrollLayout(Context context) {
this(context, null);
}
+ @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
public NotificationStackScrollLayout(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
+ @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
public NotificationStackScrollLayout(Context context, AttributeSet attrs, int defStyleAttr) {
this(context, attrs, defStyleAttr, 0);
}
+ @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
public NotificationStackScrollLayout(Context context, AttributeSet attrs, int defStyleAttr,
int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
@@ -524,6 +530,7 @@ public class NotificationStackScrollLayout extends ViewGroup
}
@Override
+ @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
protected void onFinishInflate() {
super.onFinishInflate();
@@ -534,6 +541,7 @@ public class NotificationStackScrollLayout extends ViewGroup
}
@Override
+ @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
public void onDensityOrFontScaleChanged() {
inflateFooterView();
inflateEmptyShadeView();
@@ -541,6 +549,7 @@ public class NotificationStackScrollLayout extends ViewGroup
}
@Override
+ @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
public void onThemeChanged() {
int which;
if (mStatusBarState == StatusBarState.KEYGUARD
@@ -557,6 +566,7 @@ public class NotificationStackScrollLayout extends ViewGroup
}
@VisibleForTesting
+ @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
public void updateFooter() {
boolean showDismissView = mClearAllEnabled && hasActiveClearableNotifications();
boolean showFooterView = (showDismissView ||
@@ -570,6 +580,7 @@ public class NotificationStackScrollLayout extends ViewGroup
/**
* Return whether there are any clearable notifications
*/
+ @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
public boolean hasActiveClearableNotifications() {
int childCount = getChildCount();
for (int i = 0; i < childCount; i++) {
@@ -584,7 +595,8 @@ public class NotificationStackScrollLayout extends ViewGroup
return false;
}
- public RemoteInputController.Delegate createDelegate() {
+ @ShadeViewRefactor(RefactorComponent.INPUT)
+ public RemoteInputController.Delegate createDelegate() {
return new RemoteInputController.Delegate() {
public void setRemoteInputActive(NotificationData.Entry entry,
boolean remoteInputActive) {
@@ -605,6 +617,7 @@ public class NotificationStackScrollLayout extends ViewGroup
}
@Override
+ @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
protected void onAttachedToWindow() {
super.onAttachedToWindow();
Dependency.get(StatusBarStateController.class).addListener(mStateListener);
@@ -612,6 +625,7 @@ public class NotificationStackScrollLayout extends ViewGroup
}
@Override
+ @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
protected void onDetachedFromWindow() {
super.onDetachedFromWindow();
Dependency.get(StatusBarStateController.class).removeListener(mStateListener);
@@ -619,11 +633,13 @@ public class NotificationStackScrollLayout extends ViewGroup
}
@Override
+ @ShadeViewRefactor(RefactorComponent.INPUT)
public NotificationSwipeActionHelper getSwipeActionHelper() {
return mSwipeHelper;
}
@Override
+ @ShadeViewRefactor(RefactorComponent.INPUT)
public void onMenuClicked(View view, int x, int y, MenuItem item) {
if (mLongPressListener == null) {
return;
@@ -637,6 +653,7 @@ public class NotificationStackScrollLayout extends ViewGroup
}
@Override
+ @ShadeViewRefactor(RefactorComponent.INPUT)
public void onMenuReset(View row) {
if (mTranslatingParentView != null && row == mTranslatingParentView) {
mMenuExposedView = null;
@@ -645,6 +662,7 @@ public class NotificationStackScrollLayout extends ViewGroup
}
@Override
+ @ShadeViewRefactor(RefactorComponent.INPUT)
public void onMenuShown(View row) {
mMenuExposedView = mTranslatingParentView;
if (row instanceof ExpandableNotificationRow) {
@@ -656,6 +674,7 @@ public class NotificationStackScrollLayout extends ViewGroup
}
@Override
+ @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
public void onUiModeChanged() {
mBgColor = mContext.getColor(R.color.notification_shade_background_color);
updateBackgroundDimming();
@@ -670,6 +689,7 @@ public class NotificationStackScrollLayout extends ViewGroup
}
}
+ @ShadeViewRefactor(RefactorComponent.DECORATOR)
protected void onDraw(Canvas canvas) {
if (mShouldDrawNotificationBackground
&& (mCurrentBounds.top < mCurrentBounds.bottom || mAmbientState.isDark())) {
@@ -686,6 +706,7 @@ public class NotificationStackScrollLayout extends ViewGroup
}
}
+ @ShadeViewRefactor(RefactorComponent.DECORATOR)
private void drawBackground(Canvas canvas) {
final int lockScreenLeft = mSidePaddings;
final int lockScreenRight = getWidth() - mSidePaddings;
@@ -729,6 +750,7 @@ public class NotificationStackScrollLayout extends ViewGroup
updateClipping();
}
+ @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
private void updateBackgroundDimming() {
// No need to update the background color if it's not being drawn.
if (!mShouldDrawNotificationBackground) {
@@ -755,6 +777,7 @@ public class NotificationStackScrollLayout extends ViewGroup
}
}
+ @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
private void initView(Context context) {
mScroller = new OverScroller(getContext());
setDescendantFocusability(FOCUS_AFTER_DESCENDANTS);
@@ -786,10 +809,12 @@ public class NotificationStackScrollLayout extends ViewGroup
R.dimen.heads_up_status_bar_padding);
}
+ @ShadeViewRefactor(RefactorComponent.COORDINATOR)
private void notifyHeightChangeListener(ExpandableView view) {
notifyHeightChangeListener(view, false /* needsAnimation */);
}
+ @ShadeViewRefactor(RefactorComponent.COORDINATOR)
private void notifyHeightChangeListener(ExpandableView view, boolean needsAnimation) {
if (mOnHeightChangedListener != null) {
mOnHeightChangedListener.onHeightChanged(view, needsAnimation);
@@ -797,6 +822,7 @@ public class NotificationStackScrollLayout extends ViewGroup
}
@Override
+ @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
@@ -816,6 +842,7 @@ public class NotificationStackScrollLayout extends ViewGroup
}
@Override
+ @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
protected void onLayout(boolean changed, int l, int t, int r, int b) {
// we layout all our children centered on the top
float centerX = getWidth() / 2.0f;
@@ -838,6 +865,7 @@ public class NotificationStackScrollLayout extends ViewGroup
updateAlgorithmLayoutMinHeight();
}
+ @ShadeViewRefactor(RefactorComponent.STATE_RESOLVER)
private void requestAnimationOnViewResize(ExpandableNotificationRow row) {
if (mAnimationsEnabled && (mIsExpanded || row != null && row.isPinned())) {
mNeedViewResizeAnimation = true;
@@ -845,18 +873,21 @@ public class NotificationStackScrollLayout extends ViewGroup
}
}
+ @ShadeViewRefactor(RefactorComponent.ADAPTER)
public void updateSpeedBumpIndex(int newIndex, boolean noAmbient) {
mAmbientState.setSpeedBumpIndex(newIndex);
mNoAmbient = noAmbient;
}
@Override
+ @ShadeViewRefactor(RefactorComponent.STATE_RESOLVER)
public void setChildLocationsChangedListener(
NotificationLogger.OnChildLocationsChangedListener listener) {
mListener = listener;
}
@Override
+ @ShadeViewRefactor(RefactorComponent.LAYOUT_ALGORITHM)
public boolean isInVisibleLocation(ExpandableNotificationRow row) {
ExpandableViewState childViewState = mCurrentStackScrollState.getViewStateForView(row);
if (childViewState == null) {
@@ -871,12 +902,14 @@ public class NotificationStackScrollLayout extends ViewGroup
return true;
}
+ @ShadeViewRefactor(RefactorComponent.LAYOUT_ALGORITHM)
private void setMaxLayoutHeight(int maxLayoutHeight) {
mMaxLayoutHeight = maxLayoutHeight;
mShelf.setMaxLayoutHeight(maxLayoutHeight);
updateAlgorithmHeightAndPadding();
}
+ @ShadeViewRefactor(RefactorComponent.LAYOUT_ALGORITHM)
private void updateAlgorithmHeightAndPadding() {
mTopPadding = (int) MathUtils.lerp(mRegularTopPadding, mDarkTopPadding,
mInterpolatedDarkAmount);
@@ -885,6 +918,7 @@ public class NotificationStackScrollLayout extends ViewGroup
mAmbientState.setTopPadding(mTopPadding);
}
+ @ShadeViewRefactor(RefactorComponent.LAYOUT_ALGORITHM)
private void updateAlgorithmLayoutMinHeight() {
mAmbientState.setLayoutMinHeight(mQsExpanded || isHeadsUpTransition()
? getLayoutMinHeight() : 0);
@@ -894,6 +928,7 @@ public class NotificationStackScrollLayout extends ViewGroup
* Updates the children views according to the stack scroll algorithm. Call this whenever
* modifications to {@link #mOwnScrollY} are performed to reflect it in the view layout.
*/
+ @ShadeViewRefactor(RefactorComponent.STATE_RESOLVER)
private void updateChildren() {
updateScrollStateForAddedChildren();
mAmbientState.setCurrentScrollVelocity(mScroller.isFinished()
@@ -908,6 +943,7 @@ public class NotificationStackScrollLayout extends ViewGroup
}
}
+ @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
private void onPreDrawDuringAnimation() {
mShelf.updateAppearance();
updateClippingToTopRoundedCorner();
@@ -916,6 +952,7 @@ public class NotificationStackScrollLayout extends ViewGroup
}
}
+ @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
private void updateClippingToTopRoundedCorner() {
Float clipStart = (float) mTopPadding
+ mStackTranslation
@@ -938,6 +975,7 @@ public class NotificationStackScrollLayout extends ViewGroup
}
}
+ @ShadeViewRefactor(RefactorComponent.STATE_RESOLVER)
private void updateScrollStateForAddedChildren() {
if (mChildrenToAddAnimated.isEmpty()) {
return;
@@ -961,6 +999,7 @@ public class NotificationStackScrollLayout extends ViewGroup
clampScrollPosition();
}
+ @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
private void updateForcedScroll() {
if (mForcedScroll != null && (!mForcedScroll.hasFocus()
|| !mForcedScroll.isAttachedToWindow())) {
@@ -982,6 +1021,7 @@ public class NotificationStackScrollLayout extends ViewGroup
}
}
+ @ShadeViewRefactor(RefactorComponent.STATE_RESOLVER)
private void requestChildrenUpdate() {
if (!mChildrenUpdateRequested) {
getViewTreeObserver().addOnPreDrawListener(mChildrenUpdater);
@@ -990,10 +1030,12 @@ public class NotificationStackScrollLayout extends ViewGroup
}
}
+ @ShadeViewRefactor(RefactorComponent.STATE_RESOLVER)
private boolean isCurrentlyAnimating() {
return mStateAnimator.isRunning();
}
+ @ShadeViewRefactor(RefactorComponent.COORDINATOR)
private void clampScrollPosition() {
int scrollRange = getScrollRange();
if (scrollRange < mOwnScrollY) {
@@ -1001,10 +1043,12 @@ public class NotificationStackScrollLayout extends ViewGroup
}
}
+ @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
public int getTopPadding() {
return mTopPadding;
}
+ @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
private void setTopPadding(int topPadding, boolean animate) {
if (mRegularTopPadding != topPadding) {
mRegularTopPadding = topPadding;
@@ -1026,6 +1070,7 @@ public class NotificationStackScrollLayout extends ViewGroup
*
* @param height the expanded height of the panel
*/
+ @ShadeViewRefactor(RefactorComponent.COORDINATOR)
public void setExpandedHeight(float height) {
mExpandedHeight = height;
setIsExpanded(height > 0);
@@ -1092,6 +1137,7 @@ public class NotificationStackScrollLayout extends ViewGroup
}
}
+ @ShadeViewRefactor(RefactorComponent.COORDINATOR)
private void setRequestedClipBounds(Rect clipRect) {
mRequestedClipBounds = clipRect;
updateClipping();
@@ -1100,10 +1146,12 @@ public class NotificationStackScrollLayout extends ViewGroup
/**
* Return the height of the content ignoring the footer.
*/
+ @ShadeViewRefactor(RefactorComponent.COORDINATOR)
public int getIntrinsicContentHeight() {
return mIntrinsicContentHeight;
}
+ @ShadeViewRefactor(RefactorComponent.STATE_RESOLVER)
public void updateClipping() {
boolean animatingClipping = mInterpolatedDarkAmount > 0 && mInterpolatedDarkAmount < 1;
boolean clipped = mRequestedClipBounds != null && !mInHeadsUpPinnedMode
@@ -1125,6 +1173,7 @@ public class NotificationStackScrollLayout extends ViewGroup
* @return The translation at the beginning when expanding.
* Measured relative to the resting position.
*/
+ @ShadeViewRefactor(RefactorComponent.COORDINATOR)
private float getExpandTranslationStart() {
return -mTopPadding + getMinExpansionHeight();
}
@@ -1133,6 +1182,7 @@ public class NotificationStackScrollLayout extends ViewGroup
* @return the position from where the appear transition starts when expanding.
* Measured in absolute height.
*/
+ @ShadeViewRefactor(RefactorComponent.COORDINATOR)
private float getAppearStartPosition() {
if (isHeadsUpTransition()) {
return mHeadsUpInset + mFirstVisibleBackgroundChild.getPinnedHeadsUpHeight();
@@ -1145,6 +1195,7 @@ public class NotificationStackScrollLayout extends ViewGroup
* intrinsic height, which also includes whether the notification is system expanded and
* is mainly used when dragging down from a heads up notification.
*/
+ @ShadeViewRefactor(RefactorComponent.COORDINATOR)
private int getTopHeadsUpPinnedHeight() {
NotificationData.Entry topEntry = mHeadsUpManager.getTopEntry();
if (topEntry == null) {
@@ -1165,6 +1216,7 @@ public class NotificationStackScrollLayout extends ViewGroup
* @return the position from where the appear transition ends when expanding.
* Measured in absolute height.
*/
+ @ShadeViewRefactor(RefactorComponent.COORDINATOR)
private float getAppearEndPosition() {
int appearPosition;
int notGoneChildCount = getNotGoneChildCount();
@@ -1184,6 +1236,7 @@ public class NotificationStackScrollLayout extends ViewGroup
return appearPosition + (onKeyguard() ? mTopPadding : mIntrinsicPadding);
}
+ @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
private boolean isHeadsUpTransition() {
return mTrackingHeadsUp && mFirstVisibleBackgroundChild != null
&& mAmbientState.isAboveShelf(mFirstVisibleBackgroundChild);
@@ -1193,6 +1246,7 @@ public class NotificationStackScrollLayout extends ViewGroup
* @param height the height of the panel
* @return the fraction of the appear animation that has been performed
*/
+ @ShadeViewRefactor(RefactorComponent.COORDINATOR)
public float getAppearFraction(float height) {
float appearEndPosition = getAppearEndPosition();
float appearStartPosition = getAppearStartPosition();
@@ -1200,10 +1254,12 @@ public class NotificationStackScrollLayout extends ViewGroup
/ (appearEndPosition - appearStartPosition);
}
+ @ShadeViewRefactor(RefactorComponent.COORDINATOR)
public float getStackTranslation() {
return mStackTranslation;
}
+ @ShadeViewRefactor(RefactorComponent.COORDINATOR)
private void setStackTranslation(float stackTranslation) {
if (stackTranslation != mStackTranslation) {
mStackTranslation = stackTranslation;
@@ -1218,19 +1274,23 @@ public class NotificationStackScrollLayout extends ViewGroup
*
* @return either the layout height or the externally defined height, whichever is smaller
*/
+ @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
private int getLayoutHeight() {
return Math.min(mMaxLayoutHeight, mCurrentStackHeight);
}
+ @ShadeViewRefactor(RefactorComponent.ADAPTER)
public int getFirstItemMinHeight() {
final ExpandableView firstChild = getFirstChildNotGone();
return firstChild != null ? firstChild.getMinHeight() : mCollapsedSize;
}
+ @ShadeViewRefactor(RefactorComponent.INPUT)
public void setLongPressListener(ExpandableNotificationRow.LongPressListener listener) {
mLongPressListener = listener;
}
+ @ShadeViewRefactor(RefactorComponent.ADAPTER)
public void setQsContainer(ViewGroup qsContainer) {
mQsContainer = qsContainer;
}
@@ -1240,6 +1300,7 @@ public class NotificationStackScrollLayout extends ViewGroup
* re-invoking dismiss logic in case the notification has not made its way out yet).
*/
@Override
+ @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
public void onChildDismissed(View view) {
ExpandableNotificationRow row = (ExpandableNotificationRow) view;
if (!row.isDismissed()) {
@@ -1257,6 +1318,8 @@ public class NotificationStackScrollLayout extends ViewGroup
*
* @param view view (e.g. notification) to dismiss from the layout
*/
+
+ @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
private void handleChildViewDismissed(View view) {
if (mDismissAllInProgress) {
return;
@@ -1296,6 +1359,7 @@ public class NotificationStackScrollLayout extends ViewGroup
}
@Override
+ @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
public void onChildSnappedBack(View animView, float targetLeft) {
mAmbientState.onDragFinished(animView);
updateContinuousShadowDrawing();
@@ -1316,12 +1380,14 @@ public class NotificationStackScrollLayout extends ViewGroup
}
@Override
+ @ShadeViewRefactor(RefactorComponent.INPUT)
public boolean updateSwipeProgress(View animView, boolean dismissable, float swipeProgress) {
// Returning true prevents alpha fading.
return !mFadeNotificationsOnDismiss;
}
@Override
+ @ShadeViewRefactor(RefactorComponent.INPUT)
public void onBeginDrag(View v) {
mFalsingManager.onNotificatonStartDismissing();
setSwipingInProgress(true);
@@ -1334,6 +1400,7 @@ public class NotificationStackScrollLayout extends ViewGroup
requestChildrenUpdate();
}
+ @ShadeViewRefactor(RefactorComponent.ADAPTER)
public static boolean isPinnedHeadsUp(View v) {
if (v instanceof ExpandableNotificationRow) {
ExpandableNotificationRow row = (ExpandableNotificationRow) v;
@@ -1342,6 +1409,7 @@ public class NotificationStackScrollLayout extends ViewGroup
return false;
}
+ @ShadeViewRefactor(RefactorComponent.ADAPTER)
private boolean isHeadsUp(View v) {
if (v instanceof ExpandableNotificationRow) {
ExpandableNotificationRow row = (ExpandableNotificationRow) v;
@@ -1351,17 +1419,20 @@ public class NotificationStackScrollLayout extends ViewGroup
}
@Override
+ @ShadeViewRefactor(RefactorComponent.INPUT)
public void onDragCancelled(View v) {
mFalsingManager.onNotificatonStopDismissing();
setSwipingInProgress(false);
}
@Override
+ @ShadeViewRefactor(RefactorComponent.INPUT)
public float getFalsingThresholdFactor() {
return mStatusBar.isWakeUpComingFromTouch() ? 1.5f : 1.0f;
}
@Override
+ @ShadeViewRefactor(RefactorComponent.INPUT)
public View getChildAtPosition(MotionEvent ev) {
View child = getChildAtPosition(ev.getX(), ev.getY());
if (child instanceof ExpandableNotificationRow) {
@@ -1382,6 +1453,7 @@ public class NotificationStackScrollLayout extends ViewGroup
return child;
}
+ @ShadeViewRefactor(RefactorComponent.INPUT)
public ExpandableView getClosestChildAtRawPosition(float touchX, float touchY) {
getLocationOnScreen(mTempInt2);
float localTouchY = touchY - mTempInt2[1];
@@ -1412,12 +1484,14 @@ public class NotificationStackScrollLayout extends ViewGroup
}
@Override
+ @ShadeViewRefactor(RefactorComponent.INPUT)
public ExpandableView getChildAtRawPosition(float touchX, float touchY) {
getLocationOnScreen(mTempInt2);
return getChildAtPosition(touchX - mTempInt2[0], touchY - mTempInt2[1]);
}
@Override
+ @ShadeViewRefactor(RefactorComponent.INPUT)
public ExpandableView getChildAtPosition(float touchX, float touchY) {
return getChildAtPosition(touchX, touchY, true /* requireMinHeight */);
@@ -1431,6 +1505,7 @@ public class NotificationStackScrollLayout extends ViewGroup
* @param requireMinHeight Whether a minimum height is required for a child to be returned.
* @return the child at the given location.
*/
+ @ShadeViewRefactor(RefactorComponent.INPUT)
private ExpandableView getChildAtPosition(float touchX, float touchY,
boolean requireMinHeight) {
// find the view under the pointer, accounting for GONE views
@@ -1471,6 +1546,7 @@ public class NotificationStackScrollLayout extends ViewGroup
}
@Override
+ @ShadeViewRefactor(RefactorComponent.ADAPTER)
public boolean canChildBeExpanded(View v) {
return v instanceof ExpandableNotificationRow
&& ((ExpandableNotificationRow) v).isExpandable()
@@ -1480,6 +1556,7 @@ public class NotificationStackScrollLayout extends ViewGroup
/* Only ever called as a consequence of an expansion gesture in the shade. */
@Override
+ @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
public void setUserExpandedChild(View v, boolean userExpanded) {
if (v instanceof ExpandableNotificationRow) {
ExpandableNotificationRow row = (ExpandableNotificationRow) v;
@@ -1502,6 +1579,7 @@ public class NotificationStackScrollLayout extends ViewGroup
}
@Override
+ @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
public void setExpansionCancelled(View v) {
if (v instanceof ExpandableNotificationRow) {
((ExpandableNotificationRow) v).setGroupExpansionChanging(false);
@@ -1509,6 +1587,7 @@ public class NotificationStackScrollLayout extends ViewGroup
}
@Override
+ @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
public void setUserLockedChild(View v, boolean userLocked) {
if (v instanceof ExpandableNotificationRow) {
((ExpandableNotificationRow) v).setUserLocked(userLocked);
@@ -1518,6 +1597,7 @@ public class NotificationStackScrollLayout extends ViewGroup
}
@Override
+ @ShadeViewRefactor(RefactorComponent.STATE_RESOLVER)
public void expansionStateChanged(boolean isExpanding) {
mExpandingNotification = isExpanding;
if (!mExpandedInThisMotion) {
@@ -1527,14 +1607,17 @@ public class NotificationStackScrollLayout extends ViewGroup
}
@Override
+ @ShadeViewRefactor(RefactorComponent.COORDINATOR)
public int getMaxExpandHeight(ExpandableView view) {
return view.getMaxContentHeight();
}
+ @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
public void setScrollingEnabled(boolean enable) {
mScrollingEnabled = enable;
}
+ @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
public void lockScrollTo(View v) {
if (mForcedScroll == v) {
return;
@@ -1543,6 +1626,7 @@ public class NotificationStackScrollLayout extends ViewGroup
scrollTo(v);
}
+ @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
public boolean scrollTo(View v) {
ExpandableView expandableView = (ExpandableView) v;
int positionInLinearLayout = getPositionInLinearLayout(v);
@@ -1564,6 +1648,7 @@ public class NotificationStackScrollLayout extends ViewGroup
* @return the scroll necessary to make the bottom edge of {@param v} align with the top of
* the IME.
*/
+ @ShadeViewRefactor(RefactorComponent.COORDINATOR)
private int targetScrollForView(ExpandableView v, int positionInLinearLayout) {
return positionInLinearLayout + v.getIntrinsicHeight() +
getImeInset() - getHeight()
@@ -1571,6 +1656,7 @@ public class NotificationStackScrollLayout extends ViewGroup
}
@Override
+ @ShadeViewRefactor(RefactorComponent.COORDINATOR)
public WindowInsets onApplyWindowInsets(WindowInsets insets) {
mBottomInset = insets.getSystemWindowInsetBottom();
@@ -1588,6 +1674,7 @@ public class NotificationStackScrollLayout extends ViewGroup
return insets;
}
+ @ShadeViewRefactor(RefactorComponent.STATE_RESOLVER)
private Runnable mReclamp = new Runnable() {
@Override
public void run() {
@@ -1599,28 +1686,34 @@ public class NotificationStackScrollLayout extends ViewGroup
}
};
- private void setExpandingEnabled(boolean enable) {
+ @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
+ public void setExpandingEnabled(boolean enable) {
mExpandHelper.setEnabled(enable);
}
+ @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
private boolean isScrollingEnabled() {
return mScrollingEnabled;
}
@Override
+ @ShadeViewRefactor(RefactorComponent.ADAPTER)
public boolean canChildBeDismissed(View v) {
return StackScrollAlgorithm.canChildBeDismissed(v);
}
@Override
+ @ShadeViewRefactor(RefactorComponent.INPUT)
public boolean isAntiFalsingNeeded() {
return onKeyguard();
}
+ @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
private boolean onKeyguard() {
return mStatusBarState == StatusBarState.KEYGUARD;
}
+ @ShadeViewRefactor(RefactorComponent.INPUT)
private void setSwipingInProgress(boolean isSwiped) {
mSwipingInProgress = isSwiped;
if (isSwiped) {
@@ -1629,6 +1722,7 @@ public class NotificationStackScrollLayout extends ViewGroup
}
@Override
+ @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
protected void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
mStatusBarHeight = getResources().getDimensionPixelOffset(R.dimen.status_bar_height);
@@ -1639,12 +1733,14 @@ public class NotificationStackScrollLayout extends ViewGroup
initView(getContext());
}
+ @ShadeViewRefactor(RefactorComponent.STATE_RESOLVER)
public void dismissViewAnimated(View child, Runnable endRunnable, int delay, long duration) {
mSwipeHelper.dismissChild(child, 0, endRunnable, delay, true, duration,
true /* isDismissAll */);
}
@Override
+ @ShadeViewRefactor(RefactorComponent.STATE_RESOLVER)
public void snapViewIfNeeded(ExpandableNotificationRow child) {
boolean animate = mIsExpanded || isPinnedHeadsUp(child);
// If the child is showing the notification menu snap to that
@@ -1653,11 +1749,13 @@ public class NotificationStackScrollLayout extends ViewGroup
}
@Override
+ @ShadeViewRefactor(RefactorComponent.ADAPTER)
public ViewGroup getViewParentForNotification(NotificationData.Entry entry) {
return this;
}
@Override
+ @ShadeViewRefactor(RefactorComponent.INPUT)
public boolean onTouchEvent(MotionEvent ev) {
boolean isCancelOrUp = ev.getActionMasked() == MotionEvent.ACTION_CANCEL
|| ev.getActionMasked() == MotionEvent.ACTION_UP;
@@ -1706,6 +1804,7 @@ public class NotificationStackScrollLayout extends ViewGroup
return horizontalSwipeWantsIt || scrollerWantsIt || expandWantsIt || super.onTouchEvent(ev);
}
+ @ShadeViewRefactor(RefactorComponent.INPUT)
private void dispatchDownEventToScroller(MotionEvent ev) {
MotionEvent downEvent = MotionEvent.obtain(ev);
downEvent.setAction(MotionEvent.ACTION_DOWN);
@@ -1714,6 +1813,7 @@ public class NotificationStackScrollLayout extends ViewGroup
}
@Override
+ @ShadeViewRefactor(RefactorComponent.INPUT)
public boolean onGenericMotionEvent(MotionEvent event) {
if (!isScrollingEnabled() || !mIsExpanded || mSwipingInProgress || mExpandingNotification
|| mDisallowScrollingInThisMotion) {
@@ -1746,6 +1846,7 @@ public class NotificationStackScrollLayout extends ViewGroup
return super.onGenericMotionEvent(event);
}
+ @ShadeViewRefactor(RefactorComponent.INPUT)
private boolean onScrollTouch(MotionEvent ev) {
if (!isScrollingEnabled()) {
return false;
@@ -1882,10 +1983,12 @@ public class NotificationStackScrollLayout extends ViewGroup
return true;
}
+ @ShadeViewRefactor(RefactorComponent.INPUT)
protected boolean isInsideQsContainer(MotionEvent ev) {
return ev.getY() < mQsContainer.getBottom();
}
+ @ShadeViewRefactor(RefactorComponent.INPUT)
private void onOverScrollFling(boolean open, int initialVelocity) {
if (mOverscrollTopChangedListener != null) {
mOverscrollTopChangedListener.flingTopOverscroll(initialVelocity, open);
@@ -1901,6 +2004,7 @@ public class NotificationStackScrollLayout extends ViewGroup
* @return The amount of scrolling to be performed by the scroller,
* not handled by the overScroll amount.
*/
+ @ShadeViewRefactor(RefactorComponent.INPUT)
private float overScrollUp(int deltaY, int range) {
deltaY = Math.max(deltaY, 0);
float currentTopAmount = getCurrentOverScrollAmount(true);
@@ -1934,6 +2038,7 @@ public class NotificationStackScrollLayout extends ViewGroup
* @return The amount of scrolling to be performed by the scroller,
* not handled by the overScroll amount.
*/
+ @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
private float overScrollDown(int deltaY) {
deltaY = Math.min(deltaY, 0);
float currentBottomAmount = getCurrentOverScrollAmount(false);
@@ -1958,6 +2063,7 @@ public class NotificationStackScrollLayout extends ViewGroup
return scrollAmount;
}
+ @ShadeViewRefactor(RefactorComponent.INPUT)
private void onSecondaryPointerUp(MotionEvent ev) {
final int pointerIndex = (ev.getAction() & MotionEvent.ACTION_POINTER_INDEX_MASK) >>
MotionEvent.ACTION_POINTER_INDEX_SHIFT;
@@ -1975,12 +2081,14 @@ public class NotificationStackScrollLayout extends ViewGroup
}
}
+ @ShadeViewRefactor(RefactorComponent.STATE_RESOLVER)
private void initVelocityTrackerIfNotExists() {
if (mVelocityTracker == null) {
mVelocityTracker = VelocityTracker.obtain();
}
}
+ @ShadeViewRefactor(RefactorComponent.STATE_RESOLVER)
private void recycleVelocityTracker() {
if (mVelocityTracker != null) {
mVelocityTracker.recycle();
@@ -1988,6 +2096,7 @@ public class NotificationStackScrollLayout extends ViewGroup
}
}
+ @ShadeViewRefactor(RefactorComponent.STATE_RESOLVER)
private void initOrResetVelocityTracker() {
if (mVelocityTracker == null) {
mVelocityTracker = VelocityTracker.obtain();
@@ -1996,10 +2105,12 @@ public class NotificationStackScrollLayout extends ViewGroup
}
}
+ @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
public void setFinishScrollingCallback(Runnable runnable) {
mFinishScrollingCallback = runnable;
}
+ @ShadeViewRefactor(RefactorComponent.STATE_RESOLVER)
private void animateScroll() {
if (mScroller.computeScrollOffset()) {
int oldY = mOwnScrollY;
@@ -2030,6 +2141,7 @@ public class NotificationStackScrollLayout extends ViewGroup
}
}
+ @ShadeViewRefactor(RefactorComponent.STATE_RESOLVER)
private boolean customOverScrollBy(int deltaY, int scrollY, int scrollRangeY,
int maxOverScrollY) {
@@ -2061,6 +2173,7 @@ public class NotificationStackScrollLayout extends ViewGroup
* @param onTop Should the effect be applied on top of the scroller.
* @param animate Should an animation be performed.
*/
+ @ShadeViewRefactor(RefactorComponent.STATE_RESOLVER)
public void setOverScrolledPixels(float numPixels, boolean onTop, boolean animate) {
setOverScrollAmount(numPixels * getRubberBandFactor(onTop), onTop, animate, true);
}
@@ -2073,6 +2186,8 @@ public class NotificationStackScrollLayout extends ViewGroup
* @param onTop Should the effect be applied on top of the scroller.
* @param animate Should an animation be performed.
*/
+
+ @ShadeViewRefactor(RefactorComponent.STATE_RESOLVER)
public void setOverScrollAmount(float amount, boolean onTop, boolean animate) {
setOverScrollAmount(amount, onTop, animate, true);
}
@@ -2085,6 +2200,7 @@ public class NotificationStackScrollLayout extends ViewGroup
* @param animate Should an animation be performed.
* @param cancelAnimators Should running animations be cancelled.
*/
+ @ShadeViewRefactor(RefactorComponent.STATE_RESOLVER)
public void setOverScrollAmount(float amount, boolean onTop, boolean animate,
boolean cancelAnimators) {
setOverScrollAmount(amount, onTop, animate, cancelAnimators, isRubberbanded(onTop));
@@ -2100,6 +2216,7 @@ public class NotificationStackScrollLayout extends ViewGroup
* @param isRubberbanded The value which will be passed to
* {@link OnOverscrollTopChangedListener#onOverscrollTopChanged}
*/
+ @ShadeViewRefactor(RefactorComponent.STATE_RESOLVER)
public void setOverScrollAmount(float amount, boolean onTop, boolean animate,
boolean cancelAnimators, boolean isRubberbanded) {
if (cancelAnimators) {
@@ -2108,6 +2225,7 @@ public class NotificationStackScrollLayout extends ViewGroup
setOverScrollAmountInternal(amount, onTop, animate, isRubberbanded);
}
+ @ShadeViewRefactor(RefactorComponent.STATE_RESOLVER)
private void setOverScrollAmountInternal(float amount, boolean onTop, boolean animate,
boolean isRubberbanded) {
amount = Math.max(0, amount);
@@ -2123,6 +2241,7 @@ public class NotificationStackScrollLayout extends ViewGroup
}
}
+ @ShadeViewRefactor(RefactorComponent.COORDINATOR)
private void notifyOverscrollTopListener(float amount, boolean isRubberbanded) {
mExpandHelper.onlyObserveMovements(amount > 1.0f);
if (mDontReportNextOverScroll) {
@@ -2134,19 +2253,23 @@ public class NotificationStackScrollLayout extends ViewGroup
}
}
+ @ShadeViewRefactor(RefactorComponent.COORDINATOR)
public void setOverscrollTopChangedListener(
OnOverscrollTopChangedListener overscrollTopChangedListener) {
mOverscrollTopChangedListener = overscrollTopChangedListener;
}
+ @ShadeViewRefactor(RefactorComponent.COORDINATOR)
public float getCurrentOverScrollAmount(boolean top) {
return mAmbientState.getOverScrollAmount(top);
}
+ @ShadeViewRefactor(RefactorComponent.COORDINATOR)
public float getCurrentOverScrolledPixels(boolean top) {
return top ? mOverScrolledTopPixels : mOverScrolledBottomPixels;
}
+ @ShadeViewRefactor(RefactorComponent.COORDINATOR)
private void setOverScrolledPixels(float amount, boolean onTop) {
if (onTop) {
mOverScrolledTopPixels = amount;
@@ -2155,6 +2278,7 @@ public class NotificationStackScrollLayout extends ViewGroup
}
}
+ @ShadeViewRefactor(RefactorComponent.COORDINATOR)
private void onCustomOverScrolled(int scrollY, boolean clampedY) {
// Treat animating scrolls differently; see #computeScroll() for why.
if (!mScroller.isFinished()) {
@@ -2174,6 +2298,7 @@ public class NotificationStackScrollLayout extends ViewGroup
}
}
+ @ShadeViewRefactor(RefactorComponent.STATE_RESOLVER)
private void springBack() {
int scrollRange = getScrollRange();
boolean overScrolledTop = mOwnScrollY <= 0;
@@ -2197,6 +2322,7 @@ public class NotificationStackScrollLayout extends ViewGroup
}
}
+ @ShadeViewRefactor(RefactorComponent.COORDINATOR)
private int getScrollRange() {
// In current design, it only use the top HUN to treat all of HUNs
// although there are more than one HUNs
@@ -2210,6 +2336,7 @@ public class NotificationStackScrollLayout extends ViewGroup
return scrollRange;
}
+ @ShadeViewRefactor(RefactorComponent.COORDINATOR)
private int getImeInset() {
return Math.max(0, mBottomInset - (getRootView().getHeight() - getHeight()));
}
@@ -2217,6 +2344,7 @@ public class NotificationStackScrollLayout extends ViewGroup
/**
* @return the first child which has visibility unequal to GONE
*/
+ @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
public ExpandableView getFirstChildNotGone() {
int childCount = getChildCount();
for (int i = 0; i < childCount; i++) {
@@ -2231,6 +2359,7 @@ public class NotificationStackScrollLayout extends ViewGroup
/**
* @return the child before the given view which has visibility unequal to GONE
*/
+ @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
public ExpandableView getViewBeforeView(ExpandableView view) {
ExpandableView previousView = null;
int childCount = getChildCount();
@@ -2250,6 +2379,7 @@ public class NotificationStackScrollLayout extends ViewGroup
* @return The first child which has visibility unequal to GONE which is currently below the
* given translationY or equal to it.
*/
+ @ShadeViewRefactor(RefactorComponent.COORDINATOR)
private View getFirstChildBelowTranlsationY(float translationY, boolean ignoreChildren) {
int childCount = getChildCount();
for (int i = 0; i < childCount; i++) {
@@ -2281,6 +2411,7 @@ public class NotificationStackScrollLayout extends ViewGroup
/**
* @return the last child which has visibility unequal to GONE
*/
+ @ShadeViewRefactor(RefactorComponent.COORDINATOR)
public View getLastChildNotGone() {
int childCount = getChildCount();
for (int i = childCount - 1; i >= 0; i--) {
@@ -2295,6 +2426,7 @@ public class NotificationStackScrollLayout extends ViewGroup
/**
* @return the number of children which have visibility unequal to GONE
*/
+ @ShadeViewRefactor(RefactorComponent.COORDINATOR)
public int getNotGoneChildCount() {
int childCount = getChildCount();
int count = 0;
@@ -2307,6 +2439,7 @@ public class NotificationStackScrollLayout extends ViewGroup
return count;
}
+ @ShadeViewRefactor(RefactorComponent.STATE_RESOLVER)
private void updateContentHeight() {
int height = 0;
float previousPaddingRequest = mPaddingBetweenElements;
@@ -2380,15 +2513,18 @@ public class NotificationStackScrollLayout extends ViewGroup
mAmbientState.setLayoutMaxHeight(mContentHeight);
}
+ @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
private boolean isPulsing(NotificationData.Entry entry) {
return mAmbientState.isPulsing(entry);
}
@Override
+ @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
public boolean hasPulsingNotifications() {
return mPulsing;
}
+ @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
private void updateScrollability() {
boolean scrollable = !mQsExpanded && getScrollRange() > 0;
if (scrollable != mScrollable) {
@@ -2398,6 +2534,7 @@ public class NotificationStackScrollLayout extends ViewGroup
}
}
+ @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
private void updateForwardAndBackwardScrollability() {
boolean forwardScrollable = mScrollable && mOwnScrollY < getScrollRange();
boolean backwardsScrollable = mScrollable && mOwnScrollY > 0;
@@ -2410,6 +2547,7 @@ public class NotificationStackScrollLayout extends ViewGroup
}
}
+ @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
private void updateBackground() {
// No need to update the background color if it's not being drawn.
if (!mShouldDrawNotificationBackground || mAmbientState.isFullyDark()) {
@@ -2437,6 +2575,7 @@ public class NotificationStackScrollLayout extends ViewGroup
mAnimateNextBackgroundTop = false;
}
+ @ShadeViewRefactor(RefactorComponent.STATE_RESOLVER)
private void abortBackgroundAnimators() {
if (mBottomAnimator != null) {
mBottomAnimator.cancel();
@@ -2446,10 +2585,12 @@ public class NotificationStackScrollLayout extends ViewGroup
}
}
+ @ShadeViewRefactor(RefactorComponent.STATE_RESOLVER)
private boolean areBoundsAnimating() {
return mBottomAnimator != null || mTopAnimator != null;
}
+ @ShadeViewRefactor(RefactorComponent.STATE_RESOLVER)
private void startBackgroundAnimation() {
// left and right are always instantly applied
mCurrentBounds.left = mBackgroundBounds.left;
@@ -2458,6 +2599,7 @@ public class NotificationStackScrollLayout extends ViewGroup
startTopAnimation();
}
+ @ShadeViewRefactor(RefactorComponent.STATE_RESOLVER)
private void startTopAnimation() {
int previousEndValue = mEndAnimationRect.top;
int newEndValue = mBackgroundBounds.top;
@@ -2506,6 +2648,7 @@ public class NotificationStackScrollLayout extends ViewGroup
mTopAnimator = animator;
}
+ @ShadeViewRefactor(RefactorComponent.STATE_RESOLVER)
private void startBottomAnimation() {
int previousStartValue = mStartAnimationRect.bottom;
int previousEndValue = mEndAnimationRect.bottom;
@@ -2554,11 +2697,13 @@ public class NotificationStackScrollLayout extends ViewGroup
mBottomAnimator = animator;
}
+ @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
private void setBackgroundTop(int top) {
mCurrentBounds.top = top;
invalidate();
}
+ @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
public void setBackgroundBottom(int bottom) {
mCurrentBounds.bottom = bottom;
invalidate();
@@ -2567,6 +2712,7 @@ public class NotificationStackScrollLayout extends ViewGroup
/**
* Update the background bounds to the new desired bounds
*/
+ @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
private void updateBackgroundBounds() {
getLocationInWindow(mTempInt2);
mBackgroundBounds.left = mTempInt2[0] + mSidePaddings;
@@ -2628,6 +2774,7 @@ public class NotificationStackScrollLayout extends ViewGroup
mBackgroundBounds.bottom = Math.max(bottom, top);
}
+ @ShadeViewRefactor(RefactorComponent.COORDINATOR)
private ActivatableNotificationView getFirstPinnedHeadsUp() {
int childCount = getChildCount();
for (int i = 0; i < childCount; i++) {
@@ -2643,6 +2790,7 @@ public class NotificationStackScrollLayout extends ViewGroup
return null;
}
+ @ShadeViewRefactor(RefactorComponent.COORDINATOR)
private ActivatableNotificationView getLastChildWithBackground() {
int childCount = getChildCount();
for (int i = childCount - 1; i >= 0; i--) {
@@ -2655,6 +2803,7 @@ public class NotificationStackScrollLayout extends ViewGroup
return null;
}
+ @ShadeViewRefactor(RefactorComponent.COORDINATOR)
private ActivatableNotificationView getFirstChildWithBackground() {
int childCount = getChildCount();
for (int i = 0; i < childCount; i++) {
@@ -2674,6 +2823,7 @@ public class NotificationStackScrollLayout extends ViewGroup
* numbers mean that the finger/cursor is moving down the screen,
* which means we want to scroll towards the top.
*/
+ @ShadeViewRefactor(RefactorComponent.INPUT)
protected void fling(int velocityY) {
if (getChildCount() > 0) {
int scrollRange = getScrollRange();
@@ -2711,6 +2861,7 @@ public class NotificationStackScrollLayout extends ViewGroup
* @return Whether a fling performed on the top overscroll edge lead to the expanded
* overScroll view (i.e QS).
*/
+ @ShadeViewRefactor(RefactorComponent.INPUT)
private boolean shouldOverScrollFling(int initialVelocity) {
float topOverScroll = getCurrentOverScrollAmount(true);
return mScrolledToTopOnFirstDown
@@ -2728,6 +2879,7 @@ public class NotificationStackScrollLayout extends ViewGroup
* @param ignoreIntrinsicPadding if true, {@link #getIntrinsicPadding()} is ignored and
* {@code qsHeight} is the final top padding
*/
+ @ShadeViewRefactor(RefactorComponent.COORDINATOR)
public void updateTopPadding(float qsHeight, boolean animate,
boolean ignoreIntrinsicPadding) {
int topPadding = (int) qsHeight;
@@ -2742,10 +2894,12 @@ public class NotificationStackScrollLayout extends ViewGroup
setExpandedHeight(mExpandedHeight);
}
+ @ShadeViewRefactor(RefactorComponent.COORDINATOR)
public void setMaxTopPadding(int maxTopPadding) {
mMaxTopPadding = maxTopPadding;
}
+ @ShadeViewRefactor(RefactorComponent.COORDINATOR)
public int getLayoutMinHeight() {
if (isHeadsUpTransition()) {
return getTopHeadsUpPinnedHeight();
@@ -2753,6 +2907,7 @@ public class NotificationStackScrollLayout extends ViewGroup
return mShelf.getVisibility() == GONE ? 0 : mShelf.getIntrinsicHeight();
}
+ @ShadeViewRefactor(RefactorComponent.COORDINATOR)
public int getFirstChildIntrinsicHeight() {
final ExpandableView firstChild = getFirstChildNotGone();
int firstChildMinHeight = firstChild != null
@@ -2766,10 +2921,13 @@ public class NotificationStackScrollLayout extends ViewGroup
return firstChildMinHeight;
}
+ @ShadeViewRefactor(RefactorComponent.COORDINATOR)
public float getTopPaddingOverflow() {
return mTopPaddingOverflow;
}
+
+ @ShadeViewRefactor(RefactorComponent.COORDINATOR)
public int getPeekHeight() {
final ExpandableView firstChild = getFirstChildNotGone();
final int firstChildMinHeight = firstChild != null ? firstChild.getCollapsedHeight()
@@ -2781,10 +2939,12 @@ public class NotificationStackScrollLayout extends ViewGroup
return mIntrinsicPadding + firstChildMinHeight + shelfHeight;
}
+ @ShadeViewRefactor(RefactorComponent.COORDINATOR)
private int clampPadding(int desiredPadding) {
return Math.max(desiredPadding, mIntrinsicPadding);
}
+ @ShadeViewRefactor(RefactorComponent.INPUT)
private float getRubberBandFactor(boolean onTop) {
if (!onTop) {
return RUBBER_BAND_FACTOR_NORMAL;
@@ -2804,11 +2964,13 @@ public class NotificationStackScrollLayout extends ViewGroup
* rubberbanded, false if it is technically an overscroll but rather a motion to expand the
* overscroll view (e.g. expand QS).
*/
+ @ShadeViewRefactor(RefactorComponent.INPUT)
private boolean isRubberbanded(boolean onTop) {
return !onTop || mExpandedInThisMotion || mIsExpansionChanging || mPanelTracking
|| !mScrolledToTopOnFirstDown;
}
+ @ShadeViewRefactor(RefactorComponent.INPUT)
private void endDrag() {
setIsBeingDragged(false);
@@ -2822,12 +2984,14 @@ public class NotificationStackScrollLayout extends ViewGroup
}
}
+ @ShadeViewRefactor(RefactorComponent.INPUT)
private void transformTouchEvent(MotionEvent ev, View sourceView, View targetView) {
ev.offsetLocation(sourceView.getX(), sourceView.getY());
ev.offsetLocation(-targetView.getX(), -targetView.getY());
}
@Override
+ @ShadeViewRefactor(RefactorComponent.INPUT)
public boolean onInterceptTouchEvent(MotionEvent ev) {
initDownStates(ev);
handleEmptySpaceClick(ev);
@@ -2863,6 +3027,7 @@ public class NotificationStackScrollLayout extends ViewGroup
return swipeWantsIt || scrollWantsIt || expandWantsIt || super.onInterceptTouchEvent(ev);
}
+ @ShadeViewRefactor(RefactorComponent.INPUT)
private void handleEmptySpaceClick(MotionEvent ev) {
switch (ev.getActionMasked()) {
case MotionEvent.ACTION_MOVE:
@@ -2880,6 +3045,7 @@ public class NotificationStackScrollLayout extends ViewGroup
}
}
+ @ShadeViewRefactor(RefactorComponent.INPUT)
private void initDownStates(MotionEvent ev) {
if (ev.getAction() == MotionEvent.ACTION_DOWN) {
mExpandedInThisMotion = false;
@@ -2892,10 +3058,12 @@ public class NotificationStackScrollLayout extends ViewGroup
}
}
+ @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
public void setChildTransferInProgress(boolean childTransferInProgress) {
mChildTransferInProgress = childTransferInProgress;
}
+ @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
@Override
public void onViewRemoved(View child) {
super.onViewRemoved(child);
@@ -2906,6 +3074,7 @@ public class NotificationStackScrollLayout extends ViewGroup
}
}
+ @ShadeViewRefactor(RefactorComponent.STATE_RESOLVER)
@Override
public void cleanUpViewState(View child) {
if (child == mTranslatingParentView) {
@@ -2915,6 +3084,7 @@ public class NotificationStackScrollLayout extends ViewGroup
}
@Override
+ @ShadeViewRefactor(RefactorComponent.INPUT)
public void requestDisallowInterceptTouchEvent(boolean disallowIntercept) {
super.requestDisallowInterceptTouchEvent(disallowIntercept);
if (disallowIntercept) {
@@ -2922,6 +3092,7 @@ public class NotificationStackScrollLayout extends ViewGroup
}
}
+ @ShadeViewRefactor(RefactorComponent.COORDINATOR)
private void onViewRemovedInternal(View child, ViewGroup container) {
if (mChangePositionInProgress) {
// This is only a position change, don't do anything special
@@ -2946,6 +3117,7 @@ public class NotificationStackScrollLayout extends ViewGroup
focusNextViewIfFocused(child);
}
+ @ShadeViewRefactor(RefactorComponent.STATE_RESOLVER)
private void focusNextViewIfFocused(View view) {
if (view instanceof ExpandableNotificationRow) {
ExpandableNotificationRow row = (ExpandableNotificationRow) view;
@@ -2965,6 +3137,7 @@ public class NotificationStackScrollLayout extends ViewGroup
}
+ @ShadeViewRefactor(RefactorComponent.ADAPTER)
private boolean isChildInGroup(View child) {
return child instanceof ExpandableNotificationRow
&& mGroupManager.isChildInGroupWithSummary(
@@ -2977,6 +3150,7 @@ public class NotificationStackScrollLayout extends ViewGroup
* @param child The view to generate the remove animation for.
* @return Whether an animation was generated.
*/
+ @ShadeViewRefactor(RefactorComponent.STATE_RESOLVER)
private boolean generateRemoveAnimation(View child) {
if (removeRemovedChildFromHeadsUpChangeAnimations(child)) {
mAddedHeadsUpChildren.remove(child);
@@ -3002,6 +3176,7 @@ public class NotificationStackScrollLayout extends ViewGroup
return false;
}
+ @ShadeViewRefactor(RefactorComponent.ADAPTER)
private boolean isClickedHeadsUp(View child) {
return HeadsUpUtil.isClickedHeadsUpNotification(child);
}
@@ -3011,6 +3186,7 @@ public class NotificationStackScrollLayout extends ViewGroup
*
* @return whether any child was removed from the list to animate
*/
+ @ShadeViewRefactor(RefactorComponent.STATE_RESOLVER)
private boolean removeRemovedChildFromHeadsUpChangeAnimations(View child) {
boolean hasAddEvent = false;
for (Pair<ExpandableNotificationRow, Boolean> eventPair : mHeadsUpChangeAnimations) {
@@ -3035,6 +3211,7 @@ public class NotificationStackScrollLayout extends ViewGroup
* @return whether a view is not a top level child but a child notification and that group is
* not expanded
*/
+ @ShadeViewRefactor(RefactorComponent.ADAPTER)
private boolean isChildInInvisibleGroup(View child) {
if (child instanceof ExpandableNotificationRow) {
ExpandableNotificationRow row = (ExpandableNotificationRow) child;
@@ -3052,6 +3229,7 @@ public class NotificationStackScrollLayout extends ViewGroup
*
* @param removedChild the removed child
*/
+ @ShadeViewRefactor(RefactorComponent.STATE_RESOLVER)
private void updateScrollStateForRemovedChild(ExpandableView removedChild) {
int startingPosition = getPositionInLinearLayout(removedChild);
float increasedPaddingAmount = removedChild.getIncreasedPaddingAmount();
@@ -3080,6 +3258,7 @@ public class NotificationStackScrollLayout extends ViewGroup
}
}
+ @ShadeViewRefactor(RefactorComponent.COORDINATOR)
private int getIntrinsicHeight(View view) {
if (view instanceof ExpandableView) {
ExpandableView expandableView = (ExpandableView) view;
@@ -3088,6 +3267,7 @@ public class NotificationStackScrollLayout extends ViewGroup
return view.getHeight();
}
+ @ShadeViewRefactor(RefactorComponent.COORDINATOR)
public int getPositionInLinearLayout(View requestedView) {
ExpandableNotificationRow childInGroup = null;
ExpandableNotificationRow requestedRow = null;
@@ -3149,11 +3329,13 @@ public class NotificationStackScrollLayout extends ViewGroup
}
@Override
+ @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
public void onViewAdded(View child) {
super.onViewAdded(child);
onViewAddedInternal(child);
}
+ @ShadeViewRefactor(RefactorComponent.STATE_RESOLVER)
private void updateFirstAndLastBackgroundViews() {
ActivatableNotificationView firstChild = getFirstChildWithBackground();
ActivatableNotificationView lastChild = getLastChildWithBackground();
@@ -3172,6 +3354,7 @@ public class NotificationStackScrollLayout extends ViewGroup
invalidate();
}
+ @ShadeViewRefactor(RefactorComponent.COORDINATOR)
private void onViewAddedInternal(View child) {
updateHideSensitiveForChild(child);
((ExpandableView) child).setOnHeightChangedListener(this);
@@ -3180,6 +3363,7 @@ public class NotificationStackScrollLayout extends ViewGroup
updateChronometerForChild(child);
}
+ @ShadeViewRefactor(RefactorComponent.COORDINATOR)
private void updateHideSensitiveForChild(View child) {
if (child instanceof ExpandableView) {
ExpandableView expandableView = (ExpandableView) child;
@@ -3188,15 +3372,18 @@ public class NotificationStackScrollLayout extends ViewGroup
}
@Override
+ @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
public void notifyGroupChildRemoved(View row, ViewGroup childrenContainer) {
onViewRemovedInternal(row, childrenContainer);
}
@Override
+ @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
public void notifyGroupChildAdded(View row) {
onViewAddedInternal(row);
}
+ @ShadeViewRefactor(RefactorComponent.STATE_RESOLVER)
public void setAnimationsEnabled(boolean animationsEnabled) {
mAnimationsEnabled = animationsEnabled;
updateNotificationAnimationStates();
@@ -3207,6 +3394,7 @@ public class NotificationStackScrollLayout extends ViewGroup
}
}
+ @ShadeViewRefactor(RefactorComponent.STATE_RESOLVER)
private void updateNotificationAnimationStates() {
boolean running = mAnimationsEnabled || hasPulsingNotifications();
mShelf.setAnimationsEnabled(running);
@@ -3218,18 +3406,21 @@ public class NotificationStackScrollLayout extends ViewGroup
}
}
+ @ShadeViewRefactor(RefactorComponent.STATE_RESOLVER)
private void updateAnimationState(View child) {
updateAnimationState((mAnimationsEnabled || hasPulsingNotifications())
&& (mIsExpanded || isPinnedHeadsUp(child)), child);
}
@Override
+ @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
public void setExpandingNotification(ExpandableNotificationRow row) {
mAmbientState.setExpandingNotification(row);
requestChildrenUpdate();
}
@Override
+ @ShadeViewRefactor(RefactorComponent.ADAPTER)
public void bindRow(ExpandableNotificationRow row) {
row.setHeadsUpAnimatingAwayListener(animatingAway -> {
mRoundnessManager.onHeadsupAnimatingAwayChanged(row, animatingAway);
@@ -3238,11 +3429,13 @@ public class NotificationStackScrollLayout extends ViewGroup
}
@Override
+ @ShadeViewRefactor(RefactorComponent.STATE_RESOLVER)
public void applyExpandAnimationParams(ExpandAnimationParameters params) {
mAmbientState.setExpandAnimationTopChange(params == null ? 0 : params.getTopChange());
requestChildrenUpdate();
}
+ @ShadeViewRefactor(RefactorComponent.STATE_RESOLVER)
private void updateAnimationState(boolean running, View child) {
if (child instanceof ExpandableNotificationRow) {
ExpandableNotificationRow row = (ExpandableNotificationRow) child;
@@ -3250,12 +3443,14 @@ public class NotificationStackScrollLayout extends ViewGroup
}
}
+ @ShadeViewRefactor(RefactorComponent.STATE_RESOLVER)
public boolean isAddOrRemoveAnimationPending() {
return mNeedsAnimation
&& (!mChildrenToAddAnimated.isEmpty() || !mChildrenToRemoveAnimated.isEmpty());
}
@Override
+ @ShadeViewRefactor(RefactorComponent.STATE_RESOLVER)
public void generateAddAnimation(View child, boolean fromMoreCard) {
if (mIsExpanded && mAnimationsEnabled && !mChangePositionInProgress) {
// Generate Animations
@@ -3272,6 +3467,7 @@ public class NotificationStackScrollLayout extends ViewGroup
}
@Override
+ @ShadeViewRefactor(RefactorComponent.STATE_RESOLVER)
public void changeViewPosition(View child, int newIndex) {
int currentIndex = indexOfChild(child);
@@ -3303,6 +3499,7 @@ public class NotificationStackScrollLayout extends ViewGroup
}
}
+ @ShadeViewRefactor(RefactorComponent.STATE_RESOLVER)
private void startAnimationToState() {
if (mNeedsAnimation) {
generateAllAnimationEvents();
@@ -3322,6 +3519,7 @@ public class NotificationStackScrollLayout extends ViewGroup
mGoToFullShadeDelay = 0;
}
+ @ShadeViewRefactor(RefactorComponent.STATE_RESOLVER)
private void generateAllAnimationEvents() {
generateHeadsUpAnimationEvents();
generateChildRemovalEvents();
@@ -3341,6 +3539,7 @@ public class NotificationStackScrollLayout extends ViewGroup
generatePulsingAnimationEvent();
}
+ @ShadeViewRefactor(RefactorComponent.STATE_RESOLVER)
private void generateHeadsUpAnimationEvents() {
for (Pair<ExpandableNotificationRow, Boolean> eventPair : mHeadsUpChangeAnimations) {
ExpandableNotificationRow row = eventPair.first;
@@ -3383,6 +3582,7 @@ public class NotificationStackScrollLayout extends ViewGroup
mAddedHeadsUpChildren.clear();
}
+ @ShadeViewRefactor(RefactorComponent.COORDINATOR)
private boolean shouldHunAppearFromBottom(ExpandableViewState viewState) {
if (viewState.yTranslation + viewState.height < mAmbientState.getMaxHeadsUpTranslation()) {
return false;
@@ -3390,6 +3590,7 @@ public class NotificationStackScrollLayout extends ViewGroup
return true;
}
+ @ShadeViewRefactor(RefactorComponent.STATE_RESOLVER)
private void generateGroupExpansionEvent() {
// Generate a group expansion/collapsing event if there is such a group at all
if (mExpandedGroupView != null) {
@@ -3399,6 +3600,7 @@ public class NotificationStackScrollLayout extends ViewGroup
}
}
+ @ShadeViewRefactor(RefactorComponent.STATE_RESOLVER)
private void generateViewResizeEvent() {
if (mNeedViewResizeAnimation) {
boolean hasDisappearAnimation = false;
@@ -3419,6 +3621,7 @@ public class NotificationStackScrollLayout extends ViewGroup
mNeedViewResizeAnimation = false;
}
+ @ShadeViewRefactor(RefactorComponent.STATE_RESOLVER)
private void generateSnapBackEvents() {
for (View child : mSnappedBackChildren) {
mAnimationEvents.add(new AnimationEvent(child,
@@ -3427,6 +3630,7 @@ public class NotificationStackScrollLayout extends ViewGroup
mSnappedBackChildren.clear();
}
+ @ShadeViewRefactor(RefactorComponent.STATE_RESOLVER)
private void generateDragEvents() {
for (View child : mDragAnimPendingChildren) {
mAnimationEvents.add(new AnimationEvent(child,
@@ -3435,6 +3639,7 @@ public class NotificationStackScrollLayout extends ViewGroup
mDragAnimPendingChildren.clear();
}
+ @ShadeViewRefactor(RefactorComponent.STATE_RESOLVER)
private void generateChildRemovalEvents() {
for (View child : mChildrenToRemoveAnimated) {
boolean childWasSwipedOut = mSwipedOutViews.contains(child);
@@ -3476,6 +3681,7 @@ public class NotificationStackScrollLayout extends ViewGroup
mChildrenToRemoveAnimated.clear();
}
+ @ShadeViewRefactor(RefactorComponent.STATE_RESOLVER)
private void generatePositionChangeEvents() {
for (View child : mChildrenChangingPositions) {
mAnimationEvents.add(new AnimationEvent(child,
@@ -3489,6 +3695,7 @@ public class NotificationStackScrollLayout extends ViewGroup
}
}
+ @ShadeViewRefactor(RefactorComponent.STATE_RESOLVER)
private void generateChildAdditionEvents() {
for (View child : mChildrenToAddAnimated) {
if (mFromMoreCardAdditions.contains(child)) {
@@ -3504,6 +3711,7 @@ public class NotificationStackScrollLayout extends ViewGroup
mFromMoreCardAdditions.clear();
}
+ @ShadeViewRefactor(RefactorComponent.STATE_RESOLVER)
private void generateTopPaddingEvent() {
if (mTopPaddingNeedsAnimation) {
AnimationEvent event;
@@ -3520,6 +3728,7 @@ public class NotificationStackScrollLayout extends ViewGroup
mTopPaddingNeedsAnimation = false;
}
+ @ShadeViewRefactor(RefactorComponent.STATE_RESOLVER)
private void generateActivateEvent() {
if (mActivateNeedsAnimation) {
mAnimationEvents.add(
@@ -3528,6 +3737,7 @@ public class NotificationStackScrollLayout extends ViewGroup
mActivateNeedsAnimation = false;
}
+ @ShadeViewRefactor(RefactorComponent.STATE_RESOLVER)
private void generateAnimateEverythingEvent() {
if (mEverythingNeedsAnimation) {
mAnimationEvents.add(
@@ -3536,6 +3746,7 @@ public class NotificationStackScrollLayout extends ViewGroup
mEverythingNeedsAnimation = false;
}
+ @ShadeViewRefactor(RefactorComponent.STATE_RESOLVER)
private void generateDimmedEvent() {
if (mDimmedNeedsAnimation) {
mAnimationEvents.add(
@@ -3544,6 +3755,7 @@ public class NotificationStackScrollLayout extends ViewGroup
mDimmedNeedsAnimation = false;
}
+ @ShadeViewRefactor(RefactorComponent.STATE_RESOLVER)
private void generateHideSensitiveEvent() {
if (mHideSensitiveNeedsAnimation) {
mAnimationEvents.add(
@@ -3552,6 +3764,7 @@ public class NotificationStackScrollLayout extends ViewGroup
mHideSensitiveNeedsAnimation = false;
}
+ @ShadeViewRefactor(RefactorComponent.STATE_RESOLVER)
private void generateDarkEvent() {
if (mDarkNeedsAnimation) {
AnimationEvent ev = new AnimationEvent(null,
@@ -3565,6 +3778,7 @@ public class NotificationStackScrollLayout extends ViewGroup
mDarkNeedsAnimation = false;
}
+ @ShadeViewRefactor(RefactorComponent.STATE_RESOLVER)
private void generateGoToFullShadeEvent() {
if (mGoToFullShadeNeedsAnimation) {
mAnimationEvents.add(
@@ -3573,6 +3787,7 @@ public class NotificationStackScrollLayout extends ViewGroup
mGoToFullShadeNeedsAnimation = false;
}
+ @ShadeViewRefactor(RefactorComponent.INPUT)
private boolean onInterceptTouchEventScroll(MotionEvent ev) {
if (!isScrollingEnabled()) {
return false;
@@ -3682,6 +3897,7 @@ public class NotificationStackScrollLayout extends ViewGroup
return mIsBeingDragged;
}
+ @ShadeViewRefactor(RefactorComponent.LAYOUT_ALGORITHM)
protected StackScrollAlgorithm createStackScrollAlgorithm(Context context) {
return new StackScrollAlgorithm(context);
}
@@ -3689,6 +3905,7 @@ public class NotificationStackScrollLayout extends ViewGroup
/**
* @return Whether the specified motion event is actually happening over the content.
*/
+ @ShadeViewRefactor(RefactorComponent.INPUT)
private boolean isInContentBounds(MotionEvent event) {
return isInContentBounds(event.getY());
}
@@ -3696,10 +3913,12 @@ public class NotificationStackScrollLayout extends ViewGroup
/**
* @return Whether a y coordinate is inside the content.
*/
+ @ShadeViewRefactor(RefactorComponent.INPUT)
public boolean isInContentBounds(float y) {
return y < getHeight() - getEmptyBottomMargin();
}
+ @ShadeViewRefactor(RefactorComponent.INPUT)
private void setIsBeingDragged(boolean isDragged) {
mIsBeingDragged = isDragged;
if (isDragged) {
@@ -3709,6 +3928,7 @@ public class NotificationStackScrollLayout extends ViewGroup
}
@Override
+ @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
public void onWindowFocusChanged(boolean hasWindowFocus) {
super.onWindowFocusChanged(hasWindowFocus);
if (!hasWindowFocus) {
@@ -3717,6 +3937,7 @@ public class NotificationStackScrollLayout extends ViewGroup
}
@Override
+ @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
public void clearChildFocus(View child) {
super.clearChildFocus(child);
if (mForcedScroll == child) {
@@ -3724,37 +3945,45 @@ public class NotificationStackScrollLayout extends ViewGroup
}
}
+ @ShadeViewRefactor(RefactorComponent.INPUT)
public void requestDisallowLongPress() {
cancelLongPress();
}
+ @ShadeViewRefactor(RefactorComponent.INPUT)
public void requestDisallowDismiss() {
mDisallowDismissInThisMotion = true;
}
+ @ShadeViewRefactor(RefactorComponent.INPUT)
public void cancelLongPress() {
mSwipeHelper.cancelLongPress();
}
@Override
+ @ShadeViewRefactor(RefactorComponent.COORDINATOR)
public boolean isScrolledToTop() {
return mOwnScrollY == 0;
}
@Override
+ @ShadeViewRefactor(RefactorComponent.COORDINATOR)
public boolean isScrolledToBottom() {
return mOwnScrollY >= getScrollRange();
}
@Override
+ @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
public View getHostView() {
return this;
}
+ @ShadeViewRefactor(RefactorComponent.COORDINATOR)
public int getEmptyBottomMargin() {
return Math.max(mMaxLayoutHeight - mContentHeight, 0);
}
+ @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
public void checkSnoozeLeavebehind() {
if (mCheckForLeavebehind) {
mStatusBar.getGutsManager().closeAndSaveGuts(true /* removeLeavebehind */,
@@ -3764,16 +3993,19 @@ public class NotificationStackScrollLayout extends ViewGroup
}
}
+ @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
public void resetCheckSnoozeLeavebehind() {
mCheckForLeavebehind = true;
}
+ @ShadeViewRefactor(RefactorComponent.STATE_RESOLVER)
public void onExpansionStarted() {
mIsExpansionChanging = true;
mAmbientState.setExpansionChanging(true);
checkSnoozeLeavebehind();
}
+ @ShadeViewRefactor(RefactorComponent.STATE_RESOLVER)
public void onExpansionStopped() {
mIsExpansionChanging = false;
resetCheckSnoozeLeavebehind();
@@ -3786,6 +4018,7 @@ public class NotificationStackScrollLayout extends ViewGroup
}
}
+ @ShadeViewRefactor(RefactorComponent.STATE_RESOLVER)
private void clearUserLockedViews() {
for (int i = 0; i < getChildCount(); i++) {
ExpandableView child = (ExpandableView) getChildAt(i);
@@ -3796,6 +4029,7 @@ public class NotificationStackScrollLayout extends ViewGroup
}
}
+ @ShadeViewRefactor(RefactorComponent.STATE_RESOLVER)
private void clearTemporaryViews() {
// lets make sure nothing is transient anymore
clearTemporaryViewsInGroup(this);
@@ -3808,27 +4042,32 @@ public class NotificationStackScrollLayout extends ViewGroup
}
}
+ @ShadeViewRefactor(RefactorComponent.STATE_RESOLVER)
private void clearTemporaryViewsInGroup(ViewGroup viewGroup) {
while (viewGroup != null && viewGroup.getTransientViewCount() != 0) {
viewGroup.removeTransientView(viewGroup.getTransientView(0));
}
}
+ @ShadeViewRefactor(RefactorComponent.STATE_RESOLVER)
public void onPanelTrackingStarted() {
mPanelTracking = true;
mAmbientState.setPanelTracking(true);
}
+ @ShadeViewRefactor(RefactorComponent.STATE_RESOLVER)
public void onPanelTrackingStopped() {
mPanelTracking = false;
mAmbientState.setPanelTracking(false);
}
+ @ShadeViewRefactor(RefactorComponent.STATE_RESOLVER)
public void resetScrollPosition() {
mScroller.abortAnimation();
setOwnScrollY(0);
}
+ @ShadeViewRefactor(RefactorComponent.COORDINATOR)
private void setIsExpanded(boolean isExpanded) {
boolean changed = isExpanded != mIsExpanded;
mIsExpanded = isExpanded;
@@ -3844,6 +4083,7 @@ public class NotificationStackScrollLayout extends ViewGroup
}
}
+ @ShadeViewRefactor(RefactorComponent.COORDINATOR)
private void updateChronometers() {
int childCount = getChildCount();
for (int i = 0; i < childCount; i++) {
@@ -3851,6 +4091,7 @@ public class NotificationStackScrollLayout extends ViewGroup
}
}
+ @ShadeViewRefactor(RefactorComponent.COORDINATOR)
private void updateChronometerForChild(View child) {
if (child instanceof ExpandableNotificationRow) {
ExpandableNotificationRow row = (ExpandableNotificationRow) child;
@@ -3859,6 +4100,7 @@ public class NotificationStackScrollLayout extends ViewGroup
}
@Override
+ @ShadeViewRefactor(RefactorComponent.STATE_RESOLVER)
public void onHeightChanged(ExpandableView view, boolean needsAnimation) {
updateContentHeight();
updateScrollPositionOnExpandInBottom(view);
@@ -3878,11 +4120,13 @@ public class NotificationStackScrollLayout extends ViewGroup
}
@Override
+ @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
public void onReset(ExpandableView view) {
updateAnimationState(view);
updateChronometerForChild(view);
}
+ @ShadeViewRefactor(RefactorComponent.STATE_RESOLVER)
private void updateScrollPositionOnExpandInBottom(ExpandableView view) {
if (view instanceof ExpandableNotificationRow && !onKeyguard()) {
ExpandableNotificationRow row = (ExpandableNotificationRow) view;
@@ -3907,15 +4151,18 @@ public class NotificationStackScrollLayout extends ViewGroup
}
}
+ @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
public void setOnHeightChangedListener(
ExpandableView.OnHeightChangedListener mOnHeightChangedListener) {
this.mOnHeightChangedListener = mOnHeightChangedListener;
}
+ @ShadeViewRefactor(RefactorComponent.INPUT)
public void setOnEmptySpaceClickListener(OnEmptySpaceClickListener listener) {
mOnEmptySpaceClickListener = listener;
}
+ @ShadeViewRefactor(RefactorComponent.STATE_RESOLVER)
public void onChildAnimationFinished() {
setAnimationRunning(false);
requestChildrenUpdate();
@@ -3924,6 +4171,7 @@ public class NotificationStackScrollLayout extends ViewGroup
clearHeadsUpDisappearRunning();
}
+ @ShadeViewRefactor(RefactorComponent.STATE_RESOLVER)
private void clearHeadsUpDisappearRunning() {
for (int i = 0; i < getChildCount(); i++) {
View view = getChildAt(i);
@@ -3939,6 +4187,7 @@ public class NotificationStackScrollLayout extends ViewGroup
}
}
+ @ShadeViewRefactor(RefactorComponent.STATE_RESOLVER)
private void clearTransient() {
for (ExpandableView view : mClearTransientViewsWhenFinished) {
StackStateAnimator.removeTransientView(view);
@@ -3946,6 +4195,7 @@ public class NotificationStackScrollLayout extends ViewGroup
mClearTransientViewsWhenFinished.clear();
}
+ @ShadeViewRefactor(RefactorComponent.STATE_RESOLVER)
private void runAnimationFinishedRunnables() {
for (Runnable runnable : mAnimationFinishedRunnables) {
runnable.run();
@@ -3956,6 +4206,7 @@ public class NotificationStackScrollLayout extends ViewGroup
/**
* See {@link AmbientState#setDimmed}.
*/
+ @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
public void setDimmed(boolean dimmed, boolean animate) {
dimmed &= onKeyguard();
mAmbientState.setDimmed(dimmed);
@@ -3970,15 +4221,18 @@ public class NotificationStackScrollLayout extends ViewGroup
}
@VisibleForTesting
+ @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
boolean isDimmed() {
return mAmbientState.isDimmed();
}
+ @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
private void setDimAmount(float dimAmount) {
mDimAmount = dimAmount;
updateBackgroundDimming();
}
+ @ShadeViewRefactor(RefactorComponent.STATE_RESOLVER)
private void animateDimmed(boolean dimmed) {
if (mDimAnimator != null) {
mDimAnimator.cancel();
@@ -3994,8 +4248,8 @@ public class NotificationStackScrollLayout extends ViewGroup
mDimAnimator.addUpdateListener(mDimUpdateListener);
mDimAnimator.start();
}
-
- private void setHideSensitive(boolean hideSensitive, boolean animate) {
+ @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
+ public void setHideSensitive(boolean hideSensitive, boolean animate) {
if (hideSensitive != mAmbientState.isHideSensitive()) {
int childCount = getChildCount();
for (int i = 0; i < childCount; i++) {
@@ -4015,6 +4269,7 @@ public class NotificationStackScrollLayout extends ViewGroup
/**
* See {@link AmbientState#setActivatedChild}.
*/
+ @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
public void setActivatedChild(ActivatableNotificationView activatedChild) {
mAmbientState.setActivatedChild(activatedChild);
if (mAnimationsEnabled) {
@@ -4024,10 +4279,12 @@ public class NotificationStackScrollLayout extends ViewGroup
requestChildrenUpdate();
}
+ @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
public ActivatableNotificationView getActivatedChild() {
return mAmbientState.getActivatedChild();
}
+ @ShadeViewRefactor(RefactorComponent.STATE_RESOLVER)
private void applyCurrentState() {
mCurrentStackScrollState.apply();
if (mListener != null) {
@@ -4040,6 +4297,7 @@ public class NotificationStackScrollLayout extends ViewGroup
updateClippingToTopRoundedCorner();
}
+ @ShadeViewRefactor(RefactorComponent.STATE_RESOLVER)
private void updateViewShadows() {
// we need to work around an issue where the shadow would not cast between siblings when
// their z difference is between 0 and 0.1
@@ -4082,6 +4340,7 @@ public class NotificationStackScrollLayout extends ViewGroup
*
* @param lightTheme True if light theme should be used.
*/
+ @ShadeViewRefactor(RefactorComponent.DECORATOR)
public void updateDecorViews(boolean lightTheme) {
if (lightTheme == mUsingLightTheme) {
return;
@@ -4094,6 +4353,7 @@ public class NotificationStackScrollLayout extends ViewGroup
mEmptyShadeView.setTextColor(textColor);
}
+ @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
public void goToFullShade(long delay) {
mGoToFullShadeNeedsAnimation = true;
mGoToFullShadeDelay = delay;
@@ -4101,15 +4361,18 @@ public class NotificationStackScrollLayout extends ViewGroup
requestChildrenUpdate();
}
+ @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
public void cancelExpandHelper() {
mExpandHelper.cancel();
}
+ @ShadeViewRefactor(RefactorComponent.COORDINATOR)
public void setIntrinsicPadding(int intrinsicPadding) {
mIntrinsicPadding = intrinsicPadding;
mAmbientState.setIntrinsicPadding(intrinsicPadding);
}
+ @ShadeViewRefactor(RefactorComponent.COORDINATOR)
public int getIntrinsicPadding() {
return mIntrinsicPadding;
}
@@ -4117,11 +4380,13 @@ public class NotificationStackScrollLayout extends ViewGroup
/**
* @return the y position of the first notification
*/
+ @ShadeViewRefactor(RefactorComponent.COORDINATOR)
public float getNotificationsTopY() {
return mTopPadding + getStackTranslation();
}
@Override
+ @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
public boolean shouldDelayChildPressedState() {
return true;
}
@@ -4129,6 +4394,7 @@ public class NotificationStackScrollLayout extends ViewGroup
/**
* See {@link AmbientState#setDark}.
*/
+ @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
public void setDark(boolean dark, boolean animate, @Nullable PointF touchWakeUpScreenLocation) {
if (mAmbientState.isDark() == dark) {
return;
@@ -4147,10 +4413,12 @@ public class NotificationStackScrollLayout extends ViewGroup
notifyHeightChangeListener(mShelf);
}
+ @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
private void updatePanelTranslation() {
setTranslationX(mVerticalPanelTranslation + mAntiBurnInOffsetX * mInterpolatedDarkAmount);
}
+ @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
public void setVerticalPanelTranslation(float verticalPanelTranslation) {
mVerticalPanelTranslation = verticalPanelTranslation;
updatePanelTranslation();
@@ -4161,11 +4429,13 @@ public class NotificationStackScrollLayout extends ViewGroup
* not {@link #onDraw(Canvas)} is called). This method should be called whenever the
* {@link #mAmbientState}'s dark mode is toggled.
*/
+ @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
private void updateWillNotDraw() {
boolean willDraw = mShouldDrawNotificationBackground || DEBUG;
setWillNotDraw(!willDraw);
}
+ @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
private void setDarkAmount(float darkAmount) {
setDarkAmount(darkAmount, darkAmount);
}
@@ -4179,6 +4449,7 @@ public class NotificationStackScrollLayout extends ViewGroup
* @param interpolatedDarkAmount The dark amount that follows the actual interpolation of the
* animation curve.
*/
+ @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
public void setDarkAmount(float linearDarkAmount, float interpolatedDarkAmount) {
mLinearDarkAmount = linearDarkAmount;
mInterpolatedDarkAmount = interpolatedDarkAmount;
@@ -4201,6 +4472,7 @@ public class NotificationStackScrollLayout extends ViewGroup
requestChildrenUpdate();
}
+ @ShadeViewRefactor(RefactorComponent.STATE_RESOLVER)
public void notifyDarkAnimationStart(boolean dark) {
// We only swap the scaling factor if we're fully dark or fully awake to avoid
// interpolation issues when playing with the power button.
@@ -4212,6 +4484,7 @@ public class NotificationStackScrollLayout extends ViewGroup
}
}
+ @ShadeViewRefactor(RefactorComponent.STATE_RESOLVER)
public long getDarkAnimationDuration(boolean dark) {
long duration = StackStateAnimator.ANIMATION_DURATION_WAKEUP;
// Longer animation when sleeping with more than 1 notification
@@ -4221,6 +4494,7 @@ public class NotificationStackScrollLayout extends ViewGroup
return duration;
}
+ @ShadeViewRefactor(RefactorComponent.STATE_RESOLVER)
private int findDarkAnimationOriginIndex(@Nullable PointF screenLocation) {
if (screenLocation == null || screenLocation.y < mTopPadding) {
return AnimationEvent.DARK_ANIMATION_ORIGIN_INDEX_ABOVE;
@@ -4236,6 +4510,7 @@ public class NotificationStackScrollLayout extends ViewGroup
}
}
+ @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
private int getNotGoneIndex(View child) {
int count = getChildCount();
int notGoneIndex = 0;
@@ -4251,6 +4526,7 @@ public class NotificationStackScrollLayout extends ViewGroup
return -1;
}
+ @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
public void setFooterView(@NonNull FooterView footerView) {
int index = -1;
if (mFooterView != null) {
@@ -4261,6 +4537,7 @@ public class NotificationStackScrollLayout extends ViewGroup
addView(mFooterView, index);
}
+ @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
public void setEmptyShadeView(EmptyShadeView emptyShadeView) {
int index = -1;
if (mEmptyShadeView != null) {
@@ -4271,6 +4548,7 @@ public class NotificationStackScrollLayout extends ViewGroup
addView(mEmptyShadeView, index);
}
+ @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
public void updateEmptyShadeView(boolean visible) {
mEmptyShadeView.setVisible(visible, mIsExpanded && mAnimationsEnabled);
@@ -4282,6 +4560,7 @@ public class NotificationStackScrollLayout extends ViewGroup
}
}
+ @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
public void updateFooterView(boolean visible, boolean showDismissView) {
if (mFooterView == null) {
return;
@@ -4291,12 +4570,14 @@ public class NotificationStackScrollLayout extends ViewGroup
mFooterView.setSecondaryVisible(showDismissView, animate);
}
+ @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
public void setDismissAllInProgress(boolean dismissAllInProgress) {
mDismissAllInProgress = dismissAllInProgress;
mAmbientState.setDismissAllInProgress(dismissAllInProgress);
handleDismissAllClipping();
}
+ @ShadeViewRefactor(RefactorComponent.ADAPTER)
private void handleDismissAllClipping() {
final int count = getChildCount();
boolean previousChildWillBeDismissed = false;
@@ -4314,24 +4595,29 @@ public class NotificationStackScrollLayout extends ViewGroup
}
}
+ @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
public boolean isFooterViewNotGone() {
return mFooterView != null
&& mFooterView.getVisibility() != View.GONE
&& !mFooterView.willBeGone();
}
+ @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
public boolean isFooterViewContentVisible() {
return mFooterView != null && mFooterView.isContentVisible();
}
+ @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
public int getFooterViewHeight() {
return mFooterView == null ? 0 : mFooterView.getHeight() + mPaddingBetweenElements;
}
+ @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
public int getEmptyShadeViewHeight() {
return mEmptyShadeView.getHeight();
}
+ @ShadeViewRefactor(RefactorComponent.COORDINATOR)
public float getBottomMostNotificationBottom() {
final int count = getChildCount();
float max = 0;
@@ -4349,15 +4635,18 @@ public class NotificationStackScrollLayout extends ViewGroup
return max + getStackTranslation();
}
+ @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
public void setStatusBar(StatusBar statusBar) {
this.mStatusBar = statusBar;
}
+ @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
public void setGroupManager(NotificationGroupManager groupManager) {
this.mGroupManager = groupManager;
mGroupManager.setOnGroupChangeListener(this);
}
+ @ShadeViewRefactor(RefactorComponent.STATE_RESOLVER)
private void requestAnimateEverything() {
if (mIsExpanded && mAnimationsEnabled) {
mEverythingNeedsAnimation = true;
@@ -4366,6 +4655,7 @@ public class NotificationStackScrollLayout extends ViewGroup
}
}
+ @ShadeViewRefactor(RefactorComponent.COORDINATOR)
public boolean isBelowLastNotification(float touchX, float touchY) {
int childCount = getChildCount();
for (int i = childCount - 1; i >= 0; i--) {
@@ -4397,6 +4687,7 @@ public class NotificationStackScrollLayout extends ViewGroup
}
@Override
+ @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
public void onGroupExpansionChanged(ExpandableNotificationRow changedRow, boolean expanded) {
boolean animated = !mGroupExpandedForMeasure && mAnimationsEnabled
&& (mIsExpanded || changedRow.isPinned());
@@ -4417,12 +4708,14 @@ public class NotificationStackScrollLayout extends ViewGroup
}
@Override
+ @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
public void onGroupCreatedFromChildren(NotificationGroupManager.NotificationGroup group) {
mStatusBar.requestNotificationUpdate();
}
/** @hide */
@Override
+ @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
public void onInitializeAccessibilityEventInternal(AccessibilityEvent event) {
super.onInitializeAccessibilityEventInternal(event);
event.setScrollable(mScrollable);
@@ -4433,6 +4726,7 @@ public class NotificationStackScrollLayout extends ViewGroup
}
@Override
+ @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
public void onInitializeAccessibilityNodeInfoInternal(AccessibilityNodeInfo info) {
super.onInitializeAccessibilityNodeInfoInternal(info);
if (mScrollable) {
@@ -4453,6 +4747,7 @@ public class NotificationStackScrollLayout extends ViewGroup
/** @hide */
@Override
+ @ShadeViewRefactor(RefactorComponent.INPUT)
public boolean performAccessibilityActionInternal(int action, Bundle arguments) {
if (super.performAccessibilityActionInternal(action, arguments)) {
return true;
@@ -4485,10 +4780,12 @@ public class NotificationStackScrollLayout extends ViewGroup
}
@Override
+ @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
public void onGroupsChanged() {
mStatusBar.requestNotificationUpdate();
}
+ @ShadeViewRefactor(RefactorComponent.COORDINATOR)
public void generateChildOrderChangedEvent() {
if (mIsExpanded && mAnimationsEnabled) {
mGenerateChildOrderChangedEvent = true;
@@ -4498,29 +4795,35 @@ public class NotificationStackScrollLayout extends ViewGroup
}
@Override
+ @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
public int getContainerChildCount() {
return getChildCount();
}
@Override
+ @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
public View getContainerChildAt(int i) {
return getChildAt(i);
}
@Override
+ @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
public void removeContainerView(View v) {
removeView(v);
}
@Override
+ @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
public void addContainerView(View v) {
addView(v);
}
+ @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
public void runAfterAnimationFinished(Runnable runnable) {
mAnimationFinishedRunnables.add(runnable);
}
+ @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
public void setHeadsUpManager(HeadsUpManagerPhone headsUpManager) {
mHeadsUpManager = headsUpManager;
mAmbientState.setHeadsUpManager(headsUpManager);
@@ -4528,6 +4831,7 @@ public class NotificationStackScrollLayout extends ViewGroup
mHeadsUpManager.setAnimationStateHandler(this);
}
+ @ShadeViewRefactor(RefactorComponent.STATE_RESOLVER)
public void generateHeadsUpAnimation(ExpandableNotificationRow row, boolean isHeadsUp) {
if (mAnimationsEnabled && (isHeadsUp || mHeadsUpGoingAwayAnimationsAllowed)) {
mHeadsUpChangeAnimations.add(new Pair<>(row, isHeadsUp));
@@ -4539,6 +4843,7 @@ public class NotificationStackScrollLayout extends ViewGroup
}
}
+ @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
public void setShadeExpanded(boolean shadeExpanded) {
mAmbientState.setShadeExpanded(shadeExpanded);
mStateAnimator.setShadeExpanded(shadeExpanded);
@@ -4551,31 +4856,37 @@ public class NotificationStackScrollLayout extends ViewGroup
* @param height the height of the screen
* @param bottomBarHeight the height of the bar on the bottom
*/
+ @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
public void setHeadsUpBoundaries(int height, int bottomBarHeight) {
mAmbientState.setMaxHeadsUpTranslation(height - bottomBarHeight);
mStateAnimator.setHeadsUpAppearHeightBottom(height);
requestChildrenUpdate();
}
+ @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
public void setTrackingHeadsUp(ExpandableNotificationRow row) {
mTrackingHeadsUp = row != null;
mRoundnessManager.setTrackingHeadsUp(row);
}
+ @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
public void setScrimController(ScrimController scrimController) {
mScrimController = scrimController;
mScrimController.setScrimBehindChangeRunnable(this::updateBackgroundDimming);
}
+ @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
public void forceNoOverlappingRendering(boolean force) {
mForceNoOverlappingRendering = force;
}
@Override
+ @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
public boolean hasOverlappingRendering() {
return !mForceNoOverlappingRendering && super.hasOverlappingRendering();
}
+ @ShadeViewRefactor(RefactorComponent.STATE_RESOLVER)
public void setAnimationRunning(boolean animationRunning) {
if (animationRunning != mAnimationRunning) {
if (animationRunning) {
@@ -4588,10 +4899,12 @@ public class NotificationStackScrollLayout extends ViewGroup
}
}
+ @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
public boolean isExpanded() {
return mIsExpanded;
}
+ @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
public void setPulsing(boolean pulsing, boolean animated) {
if (!mPulsing && !pulsing) {
return;
@@ -4607,6 +4920,7 @@ public class NotificationStackScrollLayout extends ViewGroup
mNeedsAnimation |= animated;
}
+ @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
private void generatePulsingAnimationEvent() {
if (mNeedingPulseAnimation != null) {
int type = mPulsing ? AnimationEvent.ANIMATION_TYPE_PULSE_APPEAR
@@ -4616,16 +4930,19 @@ public class NotificationStackScrollLayout extends ViewGroup
}
}
+ @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
public void setQsExpanded(boolean qsExpanded) {
mQsExpanded = qsExpanded;
updateAlgorithmLayoutMinHeight();
updateScrollability();
}
+ @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
public void setQsExpansionFraction(float qsExpansionFraction) {
mQsExpansionFraction = qsExpansionFraction;
}
+ @ShadeViewRefactor(RefactorComponent.COORDINATOR)
public void setOwnScrollY(int ownScrollY) {
if (ownScrollY != mOwnScrollY) {
// We still want to call the normal scrolled changed for accessibility reasons
@@ -4636,6 +4953,7 @@ public class NotificationStackScrollLayout extends ViewGroup
}
}
+ @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
public void setShelf(NotificationShelf shelf) {
int index = -1;
if (mShelf != null) {
@@ -4649,10 +4967,12 @@ public class NotificationStackScrollLayout extends ViewGroup
shelf.bind(mAmbientState, this);
}
+ @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
public NotificationShelf getNotificationShelf() {
return mShelf;
}
+ @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
public void setMaxDisplayedNotifications(int maxDisplayedNotifications) {
if (mMaxDisplayedNotifications != maxDisplayedNotifications) {
mMaxDisplayedNotifications = maxDisplayedNotifications;
@@ -4661,25 +4981,30 @@ public class NotificationStackScrollLayout extends ViewGroup
}
}
+ @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
public void setShouldShowShelfOnly(boolean shouldShowShelfOnly) {
mShouldShowShelfOnly = shouldShowShelfOnly;
updateAlgorithmLayoutMinHeight();
}
+ @ShadeViewRefactor(RefactorComponent.COORDINATOR)
public int getMinExpansionHeight() {
return mShelf.getIntrinsicHeight() - (mShelf.getIntrinsicHeight() - mStatusBarHeight) / 2;
}
+ @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
public void setInHeadsUpPinnedMode(boolean inHeadsUpPinnedMode) {
mInHeadsUpPinnedMode = inHeadsUpPinnedMode;
updateClipping();
}
+ @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
public void setHeadsUpAnimatingAway(boolean headsUpAnimatingAway) {
mHeadsUpAnimatingAway = headsUpAnimatingAway;
updateClipping();
}
+ @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
private void setStatusBarState(int statusBarState) {
mStatusBarState = statusBarState;
mAmbientState.setStatusBarState(statusBarState);
@@ -4703,10 +5028,12 @@ public class NotificationStackScrollLayout extends ViewGroup
onUpdateRowStates();
}
+ @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
public void setExpandingVelocity(float expandingVelocity) {
mAmbientState.setExpandingVelocity(expandingVelocity);
}
+ @ShadeViewRefactor(RefactorComponent.COORDINATOR)
public float getOpeningHeight() {
if (mEmptyShadeView.getVisibility() == GONE) {
return getMinExpansionHeight();
@@ -4715,29 +5042,34 @@ public class NotificationStackScrollLayout extends ViewGroup
}
}
+ @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
public void setIsFullWidth(boolean isFullWidth) {
mAmbientState.setPanelFullWidth(isFullWidth);
}
+ @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
public void setUnlockHintRunning(boolean running) {
mAmbientState.setUnlockHintRunning(running);
}
+ @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
public void setQsCustomizerShowing(boolean isShowing) {
mAmbientState.setQsCustomizerShowing(isShowing);
requestChildrenUpdate();
}
- @Override
+ @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
public void setHeadsUpGoingAwayAnimationsAllowed(boolean headsUpGoingAwayAnimationsAllowed) {
mHeadsUpGoingAwayAnimationsAllowed = headsUpGoingAwayAnimationsAllowed;
}
+ @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
public void setAntiBurnInOffsetX(int antiBurnInOffsetX) {
mAntiBurnInOffsetX = antiBurnInOffsetX;
updatePanelTranslation();
}
+ @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
pw.println(String.format("[%s: pulsing=%s qsCustomizerShowing=%s visibility=%s"
+ " alpha:%f scrollY:%d maxTopPadding:%d showShelfOnly=%s"
@@ -4755,6 +5087,7 @@ public class NotificationStackScrollLayout extends ViewGroup
mQsExpansionFraction));
}
+ @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
public boolean isFullyDark() {
return mAmbientState.isFullyDark();
}
@@ -4765,6 +5098,7 @@ public class NotificationStackScrollLayout extends ViewGroup
*
* @param listener the listener to notify.
*/
+ @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
public void addOnExpandedHeightListener(BiConsumer<Float, Float> listener) {
mExpandedHeightListeners.add(listener);
}
@@ -4772,24 +5106,29 @@ public class NotificationStackScrollLayout extends ViewGroup
/**
* Stop a listener from listening to the expandedHeight.
*/
+ @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
public void removeOnExpandedHeightListener(BiConsumer<Float, Float> listener) {
mExpandedHeightListeners.remove(listener);
}
+ @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
public void setHeadsUpAppearanceController(
HeadsUpAppearanceController headsUpAppearanceController) {
mHeadsUpAppearanceController = headsUpAppearanceController;
}
+ @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
public void setIconAreaController(NotificationIconAreaController controller) {
mIconAreaController = controller;
}
+ @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
public void manageNotifications(View v) {
Intent intent = new Intent(Settings.ACTION_ALL_APPS_NOTIFICATION_SETTINGS);
mStatusBar.startActivity(intent, true, true, Intent.FLAG_ACTIVITY_SINGLE_TOP);
}
+ @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
public void clearAllNotifications() {
// animate-swipe all dismissable notifications, then animate the shade closed
int numChildren = getChildCount();
@@ -4852,6 +5191,7 @@ public class NotificationStackScrollLayout extends ViewGroup
performDismissAllAnimations(viewsToHide);
}
+ @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
public void performDismissAllAnimations(ArrayList<View> hideAnimatedList) {
Runnable animationFinishAction = () -> {
mStatusBar.animateCollapsePanels(CommandQueue.FLAG_EXCLUDE_NONE);
@@ -4884,6 +5224,7 @@ public class NotificationStackScrollLayout extends ViewGroup
}
@VisibleForTesting
+ @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
protected void inflateFooterView() {
FooterView footerView = (FooterView) LayoutInflater.from(mContext).inflate(
R.layout.status_bar_notification_footer, this, false);
@@ -4895,7 +5236,8 @@ public class NotificationStackScrollLayout extends ViewGroup
setFooterView(footerView);
}
- private void inflateEmptyShadeView() {
+ @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
+ private void inflateEmptyShadeView() {
EmptyShadeView view = (EmptyShadeView) LayoutInflater.from(mContext).inflate(
R.layout.status_bar_no_notifications, this, false);
view.setText(R.string.empty_shade_text);
@@ -4905,6 +5247,7 @@ public class NotificationStackScrollLayout extends ViewGroup
/**
* Updates expanded, dimmed and locked states of notification rows.
*/
+ @ShadeViewRefactor(RefactorComponent.STATE_RESOLVER)
public void onUpdateRowStates() {
changeViewPosition(mFooterView, -1);
@@ -4925,13 +5268,15 @@ public class NotificationStackScrollLayout extends ViewGroup
mScrimController.setNotificationCount(getNotGoneChildCount());
}
- public void setNotificationPanel(NotificationPanelView notificationPanelView) {
+ @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
+ public void setNotificationPanel(NotificationPanelView notificationPanelView) {
mNotificationPanel = notificationPanelView;
}
/**
* A listener that is notified when the empty space below the notifications is clicked on
*/
+ @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
public interface OnEmptySpaceClickListener {
void onEmptySpaceClicked(float x, float y);
}
@@ -4939,6 +5284,7 @@ public class NotificationStackScrollLayout extends ViewGroup
/**
* A listener that gets notified when the overscroll at the top has changed.
*/
+ @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
public interface OnOverscrollTopChangedListener {
/**
@@ -4962,7 +5308,8 @@ public class NotificationStackScrollLayout extends ViewGroup
void flingTopOverscroll(float velocity, boolean open);
}
- private class NotificationSwipeHelper extends SwipeHelper
+ @ShadeViewRefactor(RefactorComponent.INPUT)
+ private class NotificationSwipeHelper extends SwipeHelper
implements NotificationSwipeActionHelper {
private static final long COVER_MENU_DELAY = 4000;
private Runnable mFalsingCheck;
@@ -5158,7 +5505,8 @@ public class NotificationStackScrollLayout extends ViewGroup
}
}
- public boolean hasActiveNotifications() {
+ @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
+ public boolean hasActiveNotifications() {
return !mEntryManager.getNotificationData().getActiveNotifications().isEmpty();
}
@@ -5167,6 +5515,7 @@ public class NotificationStackScrollLayout extends ViewGroup
/* Only ever called as a consequence of a lockscreen expansion gesture. */
@Override
+ @ShadeViewRefactor(RefactorComponent.INPUT)
public boolean onDraggedDown(View startingChild, int dragLengthY) {
if (mStatusBarState == StatusBarState.KEYGUARD
&& hasActiveNotifications() && (!mStatusBar.isDozing() || mStatusBar.isPulsing())) {
@@ -5189,6 +5538,7 @@ public class NotificationStackScrollLayout extends ViewGroup
}
@Override
+ @ShadeViewRefactor(RefactorComponent.INPUT)
public void onDragDownReset() {
setDimmed(true /* dimmed */, true /* animated */);
resetScrollPosition();
@@ -5196,27 +5546,32 @@ public class NotificationStackScrollLayout extends ViewGroup
}
@Override
+ @ShadeViewRefactor(RefactorComponent.INPUT)
public void onCrossedThreshold(boolean above) {
setDimmed(!above /* dimmed */, true /* animate */);
}
@Override
+ @ShadeViewRefactor(RefactorComponent.INPUT)
public void onTouchSlopExceeded() {
cancelLongPress();
checkSnoozeLeavebehind();
}
@Override
+ @ShadeViewRefactor(RefactorComponent.INPUT)
public void setEmptyDragAmount(float amount) {
mNotificationPanel.setEmptyDragAmount(amount);
}
@Override
+ @ShadeViewRefactor(RefactorComponent.INPUT)
public boolean isFalsingCheckNeeded() {
return mStatusBarState == StatusBarState.KEYGUARD;
}
- public void updateSpeedBumpIndex() {
+ @ShadeViewRefactor(RefactorComponent.INPUT)
+ public void updateSpeedBumpIndex() {
int speedBumpIndex = 0;
int currentIndex = 0;
final int N = getChildCount();
@@ -5236,6 +5591,7 @@ public class NotificationStackScrollLayout extends ViewGroup
updateSpeedBumpIndex(speedBumpIndex, noAmbient);
}
+ @ShadeViewRefactor(RefactorComponent.INPUT)
private boolean isTouchInView(MotionEvent ev, View view) {
if (view == null) {
return false;
@@ -5253,6 +5609,7 @@ public class NotificationStackScrollLayout extends ViewGroup
return ret;
}
+ @ShadeViewRefactor(RefactorComponent.STATE_RESOLVER)
private void updateContinuousShadowDrawing() {
boolean continuousShadowUpdate = mAnimationRunning
|| !mAmbientState.getDraggedViews().isEmpty();
@@ -5267,15 +5624,19 @@ public class NotificationStackScrollLayout extends ViewGroup
}
@Override
+ @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
public void resetExposedMenuView(boolean animate, boolean force) {
mSwipeHelper.resetExposedMenuView(animate, force);
}
+
+ @ShadeViewRefactor(RefactorComponent.INPUT)
public void closeControlsIfOutsideTouch(MotionEvent ev) {
mSwipeHelper.closeControlsIfOutsideTouch(ev);
}
- static class AnimationEvent {
+ @ShadeViewRefactor(RefactorComponent.STATE_RESOLVER)
+ static class AnimationEvent {
static AnimationFilter[] FILTERS = new AnimationFilter[]{
@@ -5575,7 +5936,8 @@ public class NotificationStackScrollLayout extends ViewGroup
}
}
- private final StateListener mStateListener = new StateListener() {
+ @ShadeViewRefactor(RefactorComponent.STATE_RESOLVER)
+ private final StateListener mStateListener = new StateListener() {
@Override
public void onStatePreChange(int oldState, int newState) {
if (oldState == StatusBarState.SHADE_LOCKED && newState == StatusBarState.KEYGUARD) {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/AlertingNotificationManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/AlertingNotificationManagerTest.java
index 32c972cbd188..f21ce2780d40 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/AlertingNotificationManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/AlertingNotificationManagerTest.java
@@ -34,7 +34,6 @@ import android.testing.TestableLooper;
import com.android.systemui.R;
import com.android.systemui.SysuiTestCase;
-import com.android.systemui.statusbar.AlertingNotificationManager;
import com.android.systemui.statusbar.notification.NotificationData;
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
@@ -183,19 +182,19 @@ public class AlertingNotificationManagerTest extends SysuiTestCase {
}
@Test
- public void testSetShouldExtendLifetime_setShouldExtend() {
+ public void testSetShouldManageLifetime_setShouldManage() {
mAlertingNotificationManager.showNotification(mEntry);
- mAlertingNotificationManager.setShouldExtendLifetime(mEntry, true /* shouldExtend */);
+ mAlertingNotificationManager.setShouldManageLifetime(mEntry, true /* shouldManage */);
assertTrue(mAlertingNotificationManager.mExtendedLifetimeAlertEntries.contains(mEntry));
}
@Test
- public void testSetShouldExtendLifetime_setShouldNotExtend() {
+ public void testSetShouldManageLifetime_setShouldNotManage() {
mAlertingNotificationManager.mExtendedLifetimeAlertEntries.add(mEntry);
- mAlertingNotificationManager.setShouldExtendLifetime(mEntry, false /* shouldExtend */);
+ mAlertingNotificationManager.setShouldManageLifetime(mEntry, false /* shouldManage */);
assertFalse(mAlertingNotificationManager.mExtendedLifetimeAlertEntries.contains(mEntry));
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationRemoteInputManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationRemoteInputManagerTest.java
index b2493b37327b..8a59e968d16e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationRemoteInputManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationRemoteInputManagerTest.java
@@ -31,8 +31,6 @@ import com.android.systemui.statusbar.NotificationRemoteInputManager.SmartReplyH
import com.google.android.collect.Sets;
-import junit.framework.Assert;
-
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -130,7 +128,7 @@ public class NotificationRemoteInputManagerTest extends SysuiTestCase {
@Test
public void testNotificationWithRemoteInputActiveIsRemovedOnCollapse() {
- mRemoteInputActiveExtender.setShouldExtendLifetime(mEntry, true);
+ mRemoteInputActiveExtender.setShouldManageLifetime(mEntry, true /* shouldManage */);
assertEquals(mRemoteInputManager.getEntriesKeptForRemoteInputActive(),
Sets.newArraySet(mEntry));
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationEntryManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationEntryManagerTest.java
index dacf59c584ad..4e16b7f94283 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationEntryManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationEntryManagerTest.java
@@ -330,7 +330,7 @@ public class NotificationEntryManagerTest extends SysuiTestCase {
mEntryManager.removeNotification(mSbn.getKey(), mRankingMap);
assertNotNull(mEntryManager.getNotificationData().get(mSbn.getKey()));
- verify(extender).setShouldExtendLifetime(mEntry, true);
+ verify(extender).setShouldManageLifetime(mEntry, true /* shouldManage */);
}
@Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationGutsManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationGutsManagerTest.java
index 6656fdd42e92..8edbf176215a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationGutsManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationGutsManagerTest.java
@@ -363,18 +363,18 @@ public class NotificationGutsManagerTest extends SysuiTestCase {
}
@Test
- public void testSetShouldExtendLifetime_setShouldExtend() {
+ public void testSetShouldManageLifetime_setShouldManage() {
NotificationData.Entry entry = createTestNotificationRow().getEntry();
- mGutsManager.setShouldExtendLifetime(entry, true /* shouldExtend */);
+ mGutsManager.setShouldManageLifetime(entry, true /* shouldManage */);
assertTrue(entry.key.equals(mGutsManager.mKeyToRemoveOnGutsClosed));
}
@Test
- public void testSetShouldExtendLifetime_setShouldNotExtend() {
+ public void testSetShouldManageLifetime_setShouldNotManage() {
NotificationData.Entry entry = createTestNotificationRow().getEntry();
mGutsManager.mKeyToRemoveOnGutsClosed = entry.key;
- mGutsManager.setShouldExtendLifetime(entry, false /* shouldExtend */);
+ mGutsManager.setShouldManageLifetime(entry, false /* shouldManage */);
assertNull(mGutsManager.mKeyToRemoveOnGutsClosed);
}
diff --git a/packages/VpnDialogs/res/values-ru/strings.xml b/packages/VpnDialogs/res/values-ru/strings.xml
index 0543937a39fc..f8fcfb83aa9a 100644
--- a/packages/VpnDialogs/res/values-ru/strings.xml
+++ b/packages/VpnDialogs/res/values-ru/strings.xml
@@ -17,7 +17,7 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="prompt" msgid="3183836924226407828">"Запрос на подключение"</string>
- <string name="warning" msgid="809658604548412033">"Приложение \"<xliff:g id="APP">%s</xliff:g>\" пытается подключиться к сети VPN, чтобы отслеживать трафик. Этот запрос следует принимать, только если вы доверяете источнику. <br/><br/>Когда подключение к сети VPN активно, в верхней части экрана появляется значок &lt;img src=vpn_icon /&gt;."</string>
+ <string name="warning" msgid="809658604548412033">"Приложение \"<xliff:g id="APP">%s</xliff:g>\" пытается подключиться к сети VPN, чтобы отслеживать трафик. Этот запрос следует принимать, только если вы доверяете источнику. <br /><br />Когда подключение к сети VPN активно, в верхней части экрана появляется значок &lt;img src=vpn_icon /&gt;."</string>
<string name="legacy_title" msgid="192936250066580964">"VPN-подключение установлено"</string>
<string name="session" msgid="6470628549473641030">"Сеанс:"</string>
<string name="duration" msgid="3584782459928719435">"Продолжительность:"</string>
diff --git a/packages/VpnDialogs/res/values-vi/strings.xml b/packages/VpnDialogs/res/values-vi/strings.xml
index 097c9aeee013..fa5e11478493 100644
--- a/packages/VpnDialogs/res/values-vi/strings.xml
+++ b/packages/VpnDialogs/res/values-vi/strings.xml
@@ -17,7 +17,7 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="prompt" msgid="3183836924226407828">"Yêu cầu kết nối"</string>
- <string name="warning" msgid="809658604548412033">"<xliff:g id="APP">%s</xliff:g> muốn thiết lập kết nối VPN cho phép ứng dụng giám sát lưu lượng truy cập mạng. Chỉ chấp nhận nếu bạn tin tưởng nguồn. &lt;br /&gt; &lt;br /&gt; Biểu tượng &lt;img src=vpn_icon /&gt; xuất hiện ở đầu màn hình của bạn khi VPN đang hoạt động."</string>
+ <string name="warning" msgid="809658604548412033">"<xliff:g id="APP">%s</xliff:g> muốn thiết lập kết nối VPN cho phép ứng dụng giám sát lưu lượng truy cập mạng. Chỉ chấp nhận nếu bạn tin tưởng nguồn. Biểu tượng &lt;br /&gt; &lt;br /&gt; &lt;img src=vpn_icon /&gt; xuất hiện ở đầu màn hình của bạn khi VPN đang hoạt động."</string>
<string name="legacy_title" msgid="192936250066580964">"VPN được kết nối"</string>
<string name="session" msgid="6470628549473641030">"Phiên"</string>
<string name="duration" msgid="3584782459928719435">"Thời lượng:"</string>
diff --git a/packages/overlays/DisplayCutoutEmulationCornerOverlay/res/values-bn/strings.xml b/packages/overlays/DisplayCutoutEmulationCornerOverlay/res/values-bn/strings.xml
new file mode 100644
index 000000000000..41aa8045b4cf
--- /dev/null
+++ b/packages/overlays/DisplayCutoutEmulationCornerOverlay/res/values-bn/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ Copyright (C) 2018 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="display_cutout_emulation_overlay" msgid="1677693377327336341">"কর্নার কাট-আউট"</string>
+</resources>
diff --git a/packages/overlays/DisplayCutoutEmulationCornerOverlay/res/values-hi/strings.xml b/packages/overlays/DisplayCutoutEmulationCornerOverlay/res/values-hi/strings.xml
new file mode 100644
index 000000000000..435b6646e5ef
--- /dev/null
+++ b/packages/overlays/DisplayCutoutEmulationCornerOverlay/res/values-hi/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ Copyright (C) 2018 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="display_cutout_emulation_overlay" msgid="1677693377327336341">"कॉर्नर कटआउट"</string>
+</resources>
diff --git a/packages/overlays/DisplayCutoutEmulationCornerOverlay/res/values-te/strings.xml b/packages/overlays/DisplayCutoutEmulationCornerOverlay/res/values-te/strings.xml
new file mode 100644
index 000000000000..4a310063ee87
--- /dev/null
+++ b/packages/overlays/DisplayCutoutEmulationCornerOverlay/res/values-te/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ Copyright (C) 2018 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="display_cutout_emulation_overlay" msgid="1677693377327336341">"మూల కట్అవుట్‌"</string>
+</resources>
diff --git a/packages/overlays/DisplayCutoutEmulationDoubleOverlay/res/values-bn/strings.xml b/packages/overlays/DisplayCutoutEmulationDoubleOverlay/res/values-bn/strings.xml
new file mode 100644
index 000000000000..d08874c3565f
--- /dev/null
+++ b/packages/overlays/DisplayCutoutEmulationDoubleOverlay/res/values-bn/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ Copyright (C) 2018 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="display_cutout_emulation_overlay" msgid="5323179900047630217">"ডবল কাট-আউট"</string>
+</resources>
diff --git a/packages/overlays/DisplayCutoutEmulationDoubleOverlay/res/values-hi/strings.xml b/packages/overlays/DisplayCutoutEmulationDoubleOverlay/res/values-hi/strings.xml
new file mode 100644
index 000000000000..d574f6c37890
--- /dev/null
+++ b/packages/overlays/DisplayCutoutEmulationDoubleOverlay/res/values-hi/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ Copyright (C) 2018 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="display_cutout_emulation_overlay" msgid="5323179900047630217">"डबल कटआउट"</string>
+</resources>
diff --git a/packages/overlays/DisplayCutoutEmulationDoubleOverlay/res/values-te/strings.xml b/packages/overlays/DisplayCutoutEmulationDoubleOverlay/res/values-te/strings.xml
new file mode 100644
index 000000000000..e32415c6216b
--- /dev/null
+++ b/packages/overlays/DisplayCutoutEmulationDoubleOverlay/res/values-te/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ Copyright (C) 2018 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="display_cutout_emulation_overlay" msgid="5323179900047630217">"డబుల్ కట్అవుట్‌"</string>
+</resources>
diff --git a/packages/overlays/DisplayCutoutEmulationDoubleOverlay/res/values-uz/strings.xml b/packages/overlays/DisplayCutoutEmulationDoubleOverlay/res/values-uz/strings.xml
index d585d7e7865c..b307ac7bbe9c 100644
--- a/packages/overlays/DisplayCutoutEmulationDoubleOverlay/res/values-uz/strings.xml
+++ b/packages/overlays/DisplayCutoutEmulationDoubleOverlay/res/values-uz/strings.xml
@@ -17,5 +17,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="display_cutout_emulation_overlay" msgid="5323179900047630217">"Kesimni ikki marta kattalashtirish"</string>
+ <string name="display_cutout_emulation_overlay" msgid="5323179900047630217">"Kesimni ikkilantirish"</string>
</resources>
diff --git a/packages/overlays/DisplayCutoutEmulationNarrowOverlay/res/values-bn/strings.xml b/packages/overlays/DisplayCutoutEmulationNarrowOverlay/res/values-bn/strings.xml
new file mode 100644
index 000000000000..27f8290b4fd9
--- /dev/null
+++ b/packages/overlays/DisplayCutoutEmulationNarrowOverlay/res/values-bn/strings.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+/**
+ * Copyright (c) 2017, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="display_cutout_emulation_overlay" msgid="3947428012427075896">"ন্যারো কাট-আউট"</string>
+</resources>
diff --git a/packages/overlays/DisplayCutoutEmulationNarrowOverlay/res/values-fr/strings.xml b/packages/overlays/DisplayCutoutEmulationNarrowOverlay/res/values-fr/strings.xml
index 551aa19b0030..577a9488e668 100644
--- a/packages/overlays/DisplayCutoutEmulationNarrowOverlay/res/values-fr/strings.xml
+++ b/packages/overlays/DisplayCutoutEmulationNarrowOverlay/res/values-fr/strings.xml
@@ -19,5 +19,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="display_cutout_emulation_overlay" msgid="3947428012427075896">"Encoche pour écran étroit"</string>
+ <string name="display_cutout_emulation_overlay" msgid="3947428012427075896">"Encoche étroite"</string>
</resources>
diff --git a/packages/overlays/DisplayCutoutEmulationNarrowOverlay/res/values-hi/strings.xml b/packages/overlays/DisplayCutoutEmulationNarrowOverlay/res/values-hi/strings.xml
new file mode 100644
index 000000000000..39747d1ab525
--- /dev/null
+++ b/packages/overlays/DisplayCutoutEmulationNarrowOverlay/res/values-hi/strings.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+/**
+ * Copyright (c) 2017, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="display_cutout_emulation_overlay" msgid="3947428012427075896">"नैराे कटआउट"</string>
+</resources>
diff --git a/packages/overlays/DisplayCutoutEmulationNarrowOverlay/res/values-te/strings.xml b/packages/overlays/DisplayCutoutEmulationNarrowOverlay/res/values-te/strings.xml
new file mode 100644
index 000000000000..9bde419541f7
--- /dev/null
+++ b/packages/overlays/DisplayCutoutEmulationNarrowOverlay/res/values-te/strings.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+/**
+ * Copyright (c) 2017, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="display_cutout_emulation_overlay" msgid="3947428012427075896">"సన్నని కట్అవుట్‌"</string>
+</resources>
diff --git a/packages/overlays/DisplayCutoutEmulationTallOverlay/res/values-bn/strings.xml b/packages/overlays/DisplayCutoutEmulationTallOverlay/res/values-bn/strings.xml
new file mode 100644
index 000000000000..a2825df8e872
--- /dev/null
+++ b/packages/overlays/DisplayCutoutEmulationTallOverlay/res/values-bn/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ Copyright (C) 2018 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="display_cutout_emulation_overlay" msgid="6424539415439220018">"টল কাট-আউট"</string>
+</resources>
diff --git a/packages/overlays/DisplayCutoutEmulationTallOverlay/res/values-fr/strings.xml b/packages/overlays/DisplayCutoutEmulationTallOverlay/res/values-fr/strings.xml
index 58c42b4c6c0f..5f4d72994f2c 100644
--- a/packages/overlays/DisplayCutoutEmulationTallOverlay/res/values-fr/strings.xml
+++ b/packages/overlays/DisplayCutoutEmulationTallOverlay/res/values-fr/strings.xml
@@ -17,5 +17,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="display_cutout_emulation_overlay" msgid="6424539415439220018">"Encoche pour écran haut"</string>
+ <string name="display_cutout_emulation_overlay" msgid="6424539415439220018">"Encoche haute"</string>
</resources>
diff --git a/packages/overlays/DisplayCutoutEmulationTallOverlay/res/values-hi/strings.xml b/packages/overlays/DisplayCutoutEmulationTallOverlay/res/values-hi/strings.xml
new file mode 100644
index 000000000000..a8bdf0528723
--- /dev/null
+++ b/packages/overlays/DisplayCutoutEmulationTallOverlay/res/values-hi/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ Copyright (C) 2018 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="display_cutout_emulation_overlay" msgid="6424539415439220018">"टॉल कटआउट"</string>
+</resources>
diff --git a/packages/overlays/DisplayCutoutEmulationTallOverlay/res/values-te/strings.xml b/packages/overlays/DisplayCutoutEmulationTallOverlay/res/values-te/strings.xml
new file mode 100644
index 000000000000..2e6233da0c6b
--- /dev/null
+++ b/packages/overlays/DisplayCutoutEmulationTallOverlay/res/values-te/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ Copyright (C) 2018 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="display_cutout_emulation_overlay" msgid="6424539415439220018">"పొడవైన కట్అవుట్‌"</string>
+</resources>
diff --git a/packages/overlays/DisplayCutoutEmulationTallOverlay/res/values-uz/strings.xml b/packages/overlays/DisplayCutoutEmulationTallOverlay/res/values-uz/strings.xml
index 5efafd5a0ce8..f2e080aa9f35 100644
--- a/packages/overlays/DisplayCutoutEmulationTallOverlay/res/values-uz/strings.xml
+++ b/packages/overlays/DisplayCutoutEmulationTallOverlay/res/values-uz/strings.xml
@@ -17,5 +17,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="display_cutout_emulation_overlay" msgid="6424539415439220018">"Kesimni balandroq qilish"</string>
+ <string name="display_cutout_emulation_overlay" msgid="6424539415439220018">"Kesimni balandlatish"</string>
</resources>
diff --git a/packages/overlays/DisplayCutoutEmulationWideOverlay/res/values-bn/strings.xml b/packages/overlays/DisplayCutoutEmulationWideOverlay/res/values-bn/strings.xml
new file mode 100644
index 000000000000..4492290afe26
--- /dev/null
+++ b/packages/overlays/DisplayCutoutEmulationWideOverlay/res/values-bn/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ Copyright (C) 2018 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="display_cutout_emulation_overlay" msgid="4043478945358357737">"ওয়াইড কাট-আউট"</string>
+</resources>
diff --git a/packages/overlays/DisplayCutoutEmulationWideOverlay/res/values-fr/strings.xml b/packages/overlays/DisplayCutoutEmulationWideOverlay/res/values-fr/strings.xml
index ce8e13168477..f9b15cf5d26d 100644
--- a/packages/overlays/DisplayCutoutEmulationWideOverlay/res/values-fr/strings.xml
+++ b/packages/overlays/DisplayCutoutEmulationWideOverlay/res/values-fr/strings.xml
@@ -17,5 +17,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="display_cutout_emulation_overlay" msgid="4043478945358357737">"Encoche pour écran large"</string>
+ <string name="display_cutout_emulation_overlay" msgid="4043478945358357737">"Encoche large"</string>
</resources>
diff --git a/packages/overlays/DisplayCutoutEmulationWideOverlay/res/values-hi/strings.xml b/packages/overlays/DisplayCutoutEmulationWideOverlay/res/values-hi/strings.xml
new file mode 100644
index 000000000000..8f97495f9d28
--- /dev/null
+++ b/packages/overlays/DisplayCutoutEmulationWideOverlay/res/values-hi/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ Copyright (C) 2018 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="display_cutout_emulation_overlay" msgid="4043478945358357737">"वाइड कटआउट"</string>
+</resources>
diff --git a/packages/overlays/DisplayCutoutEmulationWideOverlay/res/values-te/strings.xml b/packages/overlays/DisplayCutoutEmulationWideOverlay/res/values-te/strings.xml
new file mode 100644
index 000000000000..4da4f951604a
--- /dev/null
+++ b/packages/overlays/DisplayCutoutEmulationWideOverlay/res/values-te/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ Copyright (C) 2018 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="display_cutout_emulation_overlay" msgid="4043478945358357737">"వెడల్పైన కట్అవుట్‌"</string>
+</resources>
diff --git a/proto/src/metrics_constants.proto b/proto/src/metrics_constants.proto
index 7edcdcbb5623..41b3febef31f 100644
--- a/proto/src/metrics_constants.proto
+++ b/proto/src/metrics_constants.proto
@@ -6512,6 +6512,11 @@ message MetricsEvent {
// OS: Q
SETTINGS_GESTURE_WAKE_SCREEN = 1570;
+ // OPEN: Settings > Network & internet > Mobile network
+ // CATEGORY: SETTINGS
+ // OS: Q
+ MOBILE_NETWORK = 1571;
+
// ---- End Q Constants, all Q constants go above this line ----
// Add new aosp constants above this line.
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
index 6be95500adcb..b2e06f9b8c10 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
@@ -25,7 +25,7 @@ import static com.android.internal.util.FunctionalUtils.ignoreRemoteException;
import static com.android.internal.util.function.pooled.PooledLambda.obtainMessage;
import static android.accessibilityservice.AccessibilityService.SHOW_MODE_AUTO;
import static android.accessibilityservice.AccessibilityService.SHOW_MODE_HIDDEN;
-import static android.accessibilityservice.AccessibilityService.SHOW_MODE_WITH_HARD_KEYBOARD;
+import static android.accessibilityservice.AccessibilityService.SHOW_MODE_IGNORE_HARD_KEYBOARD;
import static android.accessibilityservice.AccessibilityService.SHOW_MODE_HARD_KEYBOARD_ORIGINAL_VALUE;
import static android.accessibilityservice.AccessibilityService.SHOW_MODE_HARD_KEYBOARD_OVERRIDDEN;
@@ -3796,14 +3796,14 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
*/
public boolean setSoftKeyboardModeLocked(int newMode, @Nullable ComponentName requester) {
if ((newMode != SHOW_MODE_AUTO) && (newMode != SHOW_MODE_HIDDEN)
- && (newMode != SHOW_MODE_WITH_HARD_KEYBOARD))
+ && (newMode != SHOW_MODE_IGNORE_HARD_KEYBOARD))
{
Slog.w(LOG_TAG, "Invalid soft keyboard mode");
return false;
}
if (mSoftKeyboardShowMode == newMode) return true;
- if (newMode == SHOW_MODE_WITH_HARD_KEYBOARD) {
+ if (newMode == SHOW_MODE_IGNORE_HARD_KEYBOARD) {
if (hasUserOverriddenHardKeyboardSettingLocked()) {
// The user has specified a default for this setting
return false;
@@ -3811,13 +3811,13 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
// Save the original value. But don't do this if the value in settings is already
// the new mode. That happens when we start up after a reboot, and we don't want
// to overwrite the value we had from when we first started controlling the setting.
- if (getSoftKeyboardValueFromSettings() != SHOW_MODE_WITH_HARD_KEYBOARD) {
+ if (getSoftKeyboardValueFromSettings() != SHOW_MODE_IGNORE_HARD_KEYBOARD) {
setOriginalHardKeyboardValue(
Settings.Secure.getInt(mContext.getContentResolver(),
Settings.Secure.SHOW_IME_WITH_HARD_KEYBOARD, 0) != 0);
}
putSecureIntForUser(Settings.Secure.SHOW_IME_WITH_HARD_KEYBOARD, 1, mUserId);
- } else if (mSoftKeyboardShowMode == SHOW_MODE_WITH_HARD_KEYBOARD) {
+ } else if (mSoftKeyboardShowMode == SHOW_MODE_IGNORE_HARD_KEYBOARD) {
putSecureIntForUser(Settings.Secure.SHOW_IME_WITH_HARD_KEYBOARD,
getOriginalHardKeyboardValue() ? 1 : 0, mUserId);
}
@@ -3837,7 +3837,7 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
final ContentResolver cr = mContext.getContentResolver();
final boolean showWithHardKeyboardSettings =
Settings.Secure.getInt(cr, Settings.Secure.SHOW_IME_WITH_HARD_KEYBOARD, 0) != 0;
- if (mSoftKeyboardShowMode == SHOW_MODE_WITH_HARD_KEYBOARD) {
+ if (mSoftKeyboardShowMode == SHOW_MODE_IGNORE_HARD_KEYBOARD) {
if (!showWithHardKeyboardSettings) {
// The user has overridden the setting. Respect that and prevent further changes
// to this behavior.
diff --git a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
index 8c8352f81df5..c612c888d733 100644
--- a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
+++ b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
@@ -378,6 +378,7 @@ final class AutofillManagerServiceImpl {
if (newSession == null) {
return NO_SESSION;
}
+ autofillId.setSessionId(newSession.id);
final String historyItem =
"id=" + newSession.id + " uid=" + uid + " a=" + shortComponentName
diff --git a/services/autofill/java/com/android/server/autofill/Session.java b/services/autofill/java/com/android/server/autofill/Session.java
index 5b7332d0c636..a9257f65c025 100644
--- a/services/autofill/java/com/android/server/autofill/Session.java
+++ b/services/autofill/java/com/android/server/autofill/Session.java
@@ -23,6 +23,7 @@ import static android.view.autofill.AutofillManager.ACTION_START_SESSION;
import static android.view.autofill.AutofillManager.ACTION_VALUE_CHANGED;
import static android.view.autofill.AutofillManager.ACTION_VIEW_ENTERED;
import static android.view.autofill.AutofillManager.ACTION_VIEW_EXITED;
+import static android.view.autofill.AutofillManager.NO_SESSION;
import static com.android.internal.util.function.pooled.PooledLambda.obtainMessage;
import static com.android.server.autofill.Helper.getNumericValue;
@@ -75,7 +76,6 @@ import android.service.autofill.ValueFinder;
import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.LocalLog;
-import android.util.Pair;
import android.util.Slog;
import android.util.SparseArray;
import android.util.TimeUtils;
@@ -128,7 +128,7 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
private final MetricsLogger mMetricsLogger = new MetricsLogger();
- private static AtomicInteger sIdCounter = new AtomicInteger();
+ private static AtomicInteger sIdCounter = new AtomicInteger(1);
/** ID of the session */
public final int id;
@@ -385,6 +385,7 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
@Override
public AutofillValue findRawValueByAutofillId(AutofillId id) {
+ if (id == null) return null;
synchronized (mLock) {
return findValueLocked(id);
}
@@ -395,16 +396,53 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
* or {@code null} when not found on either of them.
*/
@GuardedBy("mLock")
- private AutofillValue findValueLocked(@NonNull AutofillId id) {
- final ViewState state = mViewStates.get(id);
+ @Nullable
+ private AutofillValue findValueLocked(@NonNull AutofillId autofillId) {
+ // TODO(b/113281366): rather than explicitly look for previous session, it might be
+ // better to merge the sessions when created (see note on mergePreviousSessionLocked())
+ final int requiredId = autofillId.getSessionId();
+ Session rightSession = null;
+ if (requiredId == NO_SESSION || requiredId == id) {
+ rightSession = this;
+ } else {
+ final ArrayList<Session> previousSessions = mService.getPreviousSessionsLocked(this);
+ if (previousSessions == null) {
+ if (sVerbose) Slog.v(TAG, "findValue(): no previous sessions");
+ return null;
+ }
+ if (sDebug) {
+ Slog.d(TAG, "findValue(): looking on " + previousSessions.size()
+ + " previous sessions for autofillId " + autofillId);
+ }
+ for (int i = 0; i < previousSessions.size(); i++) {
+ final Session previousSession = previousSessions.get(i);
+ if (previousSession.id == requiredId) {
+ rightSession = previousSession;
+ break;
+ }
+ }
+ }
+ if (rightSession == null) {
+ Slog.w(TAG, "findValue(): no session with id" + requiredId);
+ return null;
+ }
+ return rightSession.findValueFromThisSessionOnlyLocked(autofillId);
+ }
+
+ @GuardedBy("mLock")
+ @Nullable
+ private AutofillValue findValueFromThisSessionOnlyLocked(@NonNull AutofillId autofillId) {
+ final ViewState state = mViewStates.get(autofillId);
if (state == null) {
- if (sDebug) Slog.d(TAG, "findValueLocked(): no view state for " + id);
+ if (sDebug) {
+ Slog.d(TAG, "findValueLocked(): no view state for " + autofillId + " on " + id);
+ }
return null;
}
AutofillValue value = state.getCurrentValue();
if (value == null) {
- if (sDebug) Slog.d(TAG, "findValueLocked(): no current value for " + id);
- value = getValueFromContextsLocked(id);
+ Slog.d(TAG, "findValueLocked(): no current value for " + autofillId + " on " + id);
+ value = getValueFromContextsLocked(autofillId);
}
return value;
}
@@ -1769,15 +1807,16 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
*/
@GuardedBy("mLock")
@Nullable
- private AutofillValue getValueFromContextsLocked(AutofillId id) {
+ private AutofillValue getValueFromContextsLocked(@NonNull AutofillId autofillId) {
final int numContexts = mContexts.size();
for (int i = numContexts - 1; i >= 0; i--) {
final FillContext context = mContexts.get(i);
- final ViewNode node = Helper.findViewNodeByAutofillId(context.getStructure(), id);
+ final ViewNode node = Helper.findViewNodeByAutofillId(context.getStructure(),
+ autofillId);
if (node != null) {
final AutofillValue value = node.getAutofillValue();
if (sDebug) {
- Slog.d(TAG, "getValueFromContexts(" + id + ") at " + i + ": " + value);
+ Slog.d(TAG, "getValueFromContexts(" + autofillId + ") at " + i + ": " + value);
}
if (value != null && !value.isEmpty()) {
return value;
@@ -2954,11 +2993,13 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
mMetricsLogger.write(newLogMaker(category));
}
+ @GuardedBy("mLock")
private void logAuthenticationStatusLocked(int requestId, int status) {
addTaggedDataToRequestLogLocked(requestId,
MetricsEvent.FIELD_AUTOFILL_AUTHENTICATION_STATUS, status);
}
+ @GuardedBy("mLock")
private void addTaggedDataToRequestLogLocked(int requestId, int tag, @Nullable Object value) {
final LogMaker requestLog = mRequestLogs.get(requestId);
if (requestLog == null) {
diff --git a/services/autofill/java/com/android/server/autofill/ViewState.java b/services/autofill/java/com/android/server/autofill/ViewState.java
index bb97e4a97c97..e6cd7e0f6ebd 100644
--- a/services/autofill/java/com/android/server/autofill/ViewState.java
+++ b/services/autofill/java/com/android/server/autofill/ViewState.java
@@ -212,20 +212,20 @@ final class ViewState {
public String toString() {
final StringBuilder builder = new StringBuilder("ViewState: [id=").append(id);
if (mDatasetId != null) {
- builder.append("datasetId:" ).append(mDatasetId);
+ builder.append(", datasetId:" ).append(mDatasetId);
}
builder.append("state:" ).append(getStateAsString());
if (mCurrentValue != null) {
- builder.append("currentValue:" ).append(mCurrentValue);
+ builder.append(", currentValue:" ).append(mCurrentValue);
}
if (mAutofilledValue != null) {
- builder.append("autofilledValue:" ).append(mAutofilledValue);
+ builder.append(", autofilledValue:" ).append(mAutofilledValue);
}
if (mSanitizedValue != null) {
- builder.append("sanitizedValue:" ).append(mSanitizedValue);
+ builder.append(", sanitizedValue:" ).append(mSanitizedValue);
}
if (mVirtualBounds != null) {
- builder.append("virtualBounds:" ).append(mVirtualBounds);
+ builder.append(", virtualBounds:" ).append(mVirtualBounds);
}
return builder.toString();
}
diff --git a/services/backup/java/com/android/server/backup/KeyValueAdbBackupEngine.java b/services/backup/java/com/android/server/backup/KeyValueAdbBackupEngine.java
index 30ec8ab711b6..125c2250d7d1 100644
--- a/services/backup/java/com/android/server/backup/KeyValueAdbBackupEngine.java
+++ b/services/backup/java/com/android/server/backup/KeyValueAdbBackupEngine.java
@@ -9,9 +9,9 @@ import static com.android.server.backup.BackupManagerService.OP_TYPE_BACKUP_WAIT
import android.app.ApplicationThreadConstants;
import android.app.IBackupAgent;
-import android.app.backup.IBackupCallback;
import android.app.backup.FullBackup;
import android.app.backup.FullBackupDataOutput;
+import android.app.backup.IBackupCallback;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
@@ -21,6 +21,7 @@ import android.os.SELinux;
import android.util.Slog;
import com.android.internal.util.Preconditions;
+import com.android.server.backup.fullbackup.AppMetadataBackupWriter;
import com.android.server.backup.remote.ServiceBackupCallback;
import com.android.server.backup.utils.FullBackupUtils;
@@ -202,16 +203,20 @@ public class KeyValueAdbBackupEngine {
public void run() {
try {
FullBackupDataOutput output = new FullBackupDataOutput(mPipe);
+ AppMetadataBackupWriter writer =
+ new AppMetadataBackupWriter(output, mPackageManager);
if (DEBUG) {
Slog.d(TAG, "Writing manifest for " + mPackage.packageName);
}
- FullBackupUtils.writeAppManifest(
- mPackage, mPackageManager, mManifestFile, false, false);
- FullBackup.backupToTar(mPackage.packageName, FullBackup.KEY_VALUE_DATA_TOKEN, null,
- mDataDir.getAbsolutePath(),
- mManifestFile.getAbsolutePath(),
- output);
+
+ writer.backupManifest(
+ mPackage,
+ mManifestFile,
+ mDataDir,
+ FullBackup.KEY_VALUE_DATA_TOKEN,
+ /* linkDomain */ null,
+ /* withApk */ false);
mManifestFile.delete();
if (DEBUG) {
diff --git a/services/backup/java/com/android/server/backup/fullbackup/AppMetadataBackupWriter.java b/services/backup/java/com/android/server/backup/fullbackup/AppMetadataBackupWriter.java
new file mode 100644
index 000000000000..94365d7dc02d
--- /dev/null
+++ b/services/backup/java/com/android/server/backup/fullbackup/AppMetadataBackupWriter.java
@@ -0,0 +1,283 @@
+package com.android.server.backup.fullbackup;
+
+import static com.android.server.backup.BackupManagerService.BACKUP_MANIFEST_VERSION;
+import static com.android.server.backup.BackupManagerService.BACKUP_METADATA_VERSION;
+import static com.android.server.backup.BackupManagerService.BACKUP_WIDGET_METADATA_TOKEN;
+import static com.android.server.backup.BackupManagerService.MORE_DEBUG;
+import static com.android.server.backup.BackupManagerService.TAG;
+
+import android.annotation.Nullable;
+import android.app.backup.FullBackup;
+import android.app.backup.FullBackupDataOutput;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.Signature;
+import android.content.pm.SigningInfo;
+import android.os.Build;
+import android.os.Environment;
+import android.os.UserHandle;
+import android.util.Log;
+import android.util.StringBuilderPrinter;
+
+import com.android.internal.util.Preconditions;
+
+import java.io.BufferedOutputStream;
+import java.io.DataOutputStream;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+
+/**
+ * Writes the backup of app-specific metadata to {@link FullBackupDataOutput}. This data is not
+ * backed up by the app's backup agent and is written before the agent writes its own data. This
+ * includes the app's:
+ *
+ * <ul>
+ * <li>manifest
+ * <li>widget data
+ * <li>apk
+ * <li>obb content
+ * </ul>
+ */
+// TODO(b/113807190): Fix or remove apk and obb implementation (only used for adb).
+public class AppMetadataBackupWriter {
+ private final FullBackupDataOutput mOutput;
+ private final PackageManager mPackageManager;
+
+ /** The destination of the backup is specified by {@code output}. */
+ public AppMetadataBackupWriter(FullBackupDataOutput output, PackageManager packageManager) {
+ mOutput = output;
+ mPackageManager = packageManager;
+ }
+
+ /**
+ * Back up the app's manifest without specifying a pseudo-directory for the TAR stream.
+ *
+ * @see #backupManifest(PackageInfo, File, File, String, String, boolean)
+ */
+ public void backupManifest(
+ PackageInfo packageInfo, File manifestFile, File filesDir, boolean withApk)
+ throws IOException {
+ backupManifest(
+ packageInfo,
+ manifestFile,
+ filesDir,
+ /* domain */ null,
+ /* linkDomain */ null,
+ withApk);
+ }
+
+ /**
+ * Back up the app's manifest.
+ *
+ * <ol>
+ * <li>Write the app's manifest data to the specified temporary file {@code manifestFile}.
+ * <li>Backup the file in TAR format to the backup destination {@link #mOutput}.
+ * </ol>
+ *
+ * <p>Note: {@code domain} and {@code linkDomain} are only used by adb to specify a
+ * pseudo-directory for the TAR stream.
+ */
+ // TODO(b/113806991): Look into streaming the backup data directly.
+ public void backupManifest(
+ PackageInfo packageInfo,
+ File manifestFile,
+ File filesDir,
+ @Nullable String domain,
+ @Nullable String linkDomain,
+ boolean withApk)
+ throws IOException {
+ byte[] manifestBytes = getManifestBytes(packageInfo, withApk);
+ FileOutputStream outputStream = new FileOutputStream(manifestFile);
+ outputStream.write(manifestBytes);
+ outputStream.close();
+
+ // We want the manifest block in the archive stream to be constant each time we generate
+ // a backup stream for the app. However, the underlying TAR mechanism sees it as a file and
+ // will propagate its last modified time. We pin the last modified time to zero to prevent
+ // the TAR header from varying.
+ manifestFile.setLastModified(0);
+
+ FullBackup.backupToTar(
+ packageInfo.packageName,
+ domain,
+ linkDomain,
+ filesDir.getAbsolutePath(),
+ manifestFile.getAbsolutePath(),
+ mOutput);
+ }
+
+ /**
+ * Gets the app's manifest as a byte array. All data are strings ending in LF.
+ *
+ * <p>The manifest format is:
+ *
+ * <pre>
+ * BACKUP_MANIFEST_VERSION
+ * package name
+ * package version code
+ * platform version code
+ * installer package name (can be empty)
+ * boolean (1 if archive includes .apk, otherwise 0)
+ * # of signatures N
+ * N* (signature byte array in ascii format per Signature.toCharsString())
+ * </pre>
+ */
+ private byte[] getManifestBytes(PackageInfo packageInfo, boolean withApk) {
+ String packageName = packageInfo.packageName;
+ StringBuilder builder = new StringBuilder(4096);
+ StringBuilderPrinter printer = new StringBuilderPrinter(builder);
+
+ printer.println(Integer.toString(BACKUP_MANIFEST_VERSION));
+ printer.println(packageName);
+ printer.println(Long.toString(packageInfo.getLongVersionCode()));
+ printer.println(Integer.toString(Build.VERSION.SDK_INT));
+
+ String installerName = mPackageManager.getInstallerPackageName(packageName);
+ printer.println((installerName != null) ? installerName : "");
+
+ printer.println(withApk ? "1" : "0");
+
+ // Write the signature block.
+ SigningInfo signingInfo = packageInfo.signingInfo;
+ if (signingInfo == null) {
+ printer.println("0");
+ } else {
+ // Retrieve the newest signatures to write.
+ // TODO (b/73988180) use entire signing history in case of rollbacks.
+ Signature[] signatures = signingInfo.getApkContentsSigners();
+ printer.println(Integer.toString(signatures.length));
+ for (Signature sig : signatures) {
+ printer.println(sig.toCharsString());
+ }
+ }
+ return builder.toString().getBytes();
+ }
+
+ /**
+ * Backup specified widget data. The widget data is prefaced by a metadata header.
+ *
+ * <ol>
+ * <li>Write a metadata header to the specified temporary file {@code metadataFile}.
+ * <li>Write widget data bytes to the same file.
+ * <li>Backup the file in TAR format to the backup destination {@link #mOutput}.
+ * </ol>
+ *
+ * @throws IllegalArgumentException if the widget data provided is empty.
+ */
+ // TODO(b/113806991): Look into streaming the backup data directly.
+ public void backupWidget(
+ PackageInfo packageInfo, File metadataFile, File filesDir, byte[] widgetData)
+ throws IOException {
+ Preconditions.checkArgument(widgetData.length > 0, "Can't backup widget with no data.");
+
+ String packageName = packageInfo.packageName;
+ FileOutputStream fileOutputStream = new FileOutputStream(metadataFile);
+ BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(fileOutputStream);
+ DataOutputStream dataOutputStream = new DataOutputStream(bufferedOutputStream);
+
+ byte[] metadata = getMetadataBytes(packageName);
+ bufferedOutputStream.write(metadata); // bypassing DataOutputStream
+ writeWidgetData(dataOutputStream, widgetData);
+ bufferedOutputStream.flush();
+ dataOutputStream.close();
+
+ // As with the manifest file, guarantee consistency of the archive metadata for the widget
+ // block by using a fixed last modified time on the metadata file.
+ metadataFile.setLastModified(0);
+
+ FullBackup.backupToTar(
+ packageName,
+ /* domain */ null,
+ /* linkDomain */ null,
+ filesDir.getAbsolutePath(),
+ metadataFile.getAbsolutePath(),
+ mOutput);
+ }
+
+ /**
+ * Gets the app's metadata as a byte array. All entries are strings ending in LF.
+ *
+ * <p>The metadata format is:
+ *
+ * <pre>
+ * BACKUP_METADATA_VERSION
+ * package name
+ * </pre>
+ */
+ private byte[] getMetadataBytes(String packageName) {
+ StringBuilder builder = new StringBuilder(512);
+ StringBuilderPrinter printer = new StringBuilderPrinter(builder);
+ printer.println(Integer.toString(BACKUP_METADATA_VERSION));
+ printer.println(packageName);
+ return builder.toString().getBytes();
+ }
+
+ /**
+ * Write a byte array of widget data to the specified output stream. All integers are binary in
+ * network byte order.
+ *
+ * <p>The widget data format:
+ *
+ * <pre>
+ * 4 : Integer token identifying the widget data blob.
+ * 4 : Integer size of the widget data.
+ * N : Raw bytes of the widget data.
+ * </pre>
+ */
+ private void writeWidgetData(DataOutputStream out, byte[] widgetData) throws IOException {
+ out.writeInt(BACKUP_WIDGET_METADATA_TOKEN);
+ out.writeInt(widgetData.length);
+ out.write(widgetData);
+ }
+
+ /**
+ * Backup the app's .apk to the backup destination {@link #mOutput}. Currently only used for
+ * 'adb backup'.
+ */
+ // TODO(b/113807190): Investigate and potentially remove.
+ public void backupApk(PackageInfo packageInfo) {
+ // TODO: handle backing up split APKs
+ String appSourceDir = packageInfo.applicationInfo.getBaseCodePath();
+ String apkDir = new File(appSourceDir).getParent();
+ FullBackup.backupToTar(
+ packageInfo.packageName,
+ FullBackup.APK_TREE_TOKEN,
+ /* linkDomain */ null,
+ apkDir,
+ appSourceDir,
+ mOutput);
+ }
+
+ /**
+ * Backup the app's .obb files to the backup destination {@link #mOutput}. Currently only used
+ * for 'adb backup'.
+ */
+ // TODO(b/113807190): Investigate and potentially remove.
+ public void backupObb(PackageInfo packageInfo) {
+ // TODO: migrate this to SharedStorageBackup, since AID_SYSTEM doesn't have access to
+ // external storage.
+ // TODO: http://b/22388012
+ Environment.UserEnvironment userEnv =
+ new Environment.UserEnvironment(UserHandle.USER_SYSTEM);
+ File obbDir = userEnv.buildExternalStorageAppObbDirs(packageInfo.packageName)[0];
+ if (obbDir != null) {
+ if (MORE_DEBUG) {
+ Log.i(TAG, "obb dir: " + obbDir.getAbsolutePath());
+ }
+ File[] obbFiles = obbDir.listFiles();
+ if (obbFiles != null) {
+ String obbDirName = obbDir.getAbsolutePath();
+ for (File obb : obbFiles) {
+ FullBackup.backupToTar(
+ packageInfo.packageName,
+ FullBackup.OBB_TREE_TOKEN,
+ /* linkDomain */ null,
+ obbDirName,
+ obb.getAbsolutePath(),
+ mOutput);
+ }
+ }
+ }
+ }
+}
diff --git a/services/backup/java/com/android/server/backup/fullbackup/FullBackupEngine.java b/services/backup/java/com/android/server/backup/fullbackup/FullBackupEngine.java
index 16906f74c8a8..c9f72181bcaf 100644
--- a/services/backup/java/com/android/server/backup/fullbackup/FullBackupEngine.java
+++ b/services/backup/java/com/android/server/backup/fullbackup/FullBackupEngine.java
@@ -18,8 +18,6 @@ package com.android.server.backup.fullbackup;
import static com.android.server.backup.BackupManagerService.BACKUP_MANIFEST_FILENAME;
import static com.android.server.backup.BackupManagerService.BACKUP_METADATA_FILENAME;
-import static com.android.server.backup.BackupManagerService.BACKUP_METADATA_VERSION;
-import static com.android.server.backup.BackupManagerService.BACKUP_WIDGET_METADATA_TOKEN;
import static com.android.server.backup.BackupManagerService.DEBUG;
import static com.android.server.backup.BackupManagerService.MORE_DEBUG;
import static com.android.server.backup.BackupManagerService.OP_TYPE_BACKUP_WAIT;
@@ -29,17 +27,14 @@ import static com.android.server.backup.BackupManagerService.TAG;
import android.app.ApplicationThreadConstants;
import android.app.IBackupAgent;
import android.app.backup.BackupTransport;
-import android.app.backup.FullBackup;
import android.app.backup.FullBackupDataOutput;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
-import android.os.Environment.UserEnvironment;
+import android.content.pm.PackageManager;
import android.os.ParcelFileDescriptor;
import android.os.RemoteException;
import android.os.UserHandle;
-import android.util.Log;
import android.util.Slog;
-import android.util.StringBuilderPrinter;
import com.android.internal.util.Preconditions;
import com.android.server.AppWidgetBackupBridge;
@@ -49,27 +44,20 @@ import com.android.server.backup.BackupRestoreTask;
import com.android.server.backup.remote.RemoteCall;
import com.android.server.backup.utils.FullBackupUtils;
-import java.io.BufferedOutputStream;
-import java.io.DataOutputStream;
import java.io.File;
-import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
/**
- * Core logic for performing one package's full backup, gathering the tarball from the
- * application and emitting it to the designated OutputStream.
+ * Core logic for performing one package's full backup, gathering the tarball from the application
+ * and emitting it to the designated OutputStream.
*/
public class FullBackupEngine {
-
private BackupManagerService backupManagerService;
OutputStream mOutput;
FullBackupPreflight mPreflightHook;
BackupRestoreTask mTimeoutMonitor;
IBackupAgent mAgent;
- File mFilesDir;
- File mManifestFile;
- File mMetadataFile;
boolean mIncludeApks;
PackageInfo mPkg;
private final long mQuota;
@@ -78,79 +66,91 @@ public class FullBackupEngine {
private final BackupAgentTimeoutParameters mAgentTimeoutParameters;
class FullBackupRunner implements Runnable {
-
- PackageInfo mPackage;
- byte[] mWidgetData;
- IBackupAgent mAgent;
- ParcelFileDescriptor mPipe;
- int mToken;
- boolean mSendApk;
- boolean mWriteManifest;
-
- FullBackupRunner(PackageInfo pack, IBackupAgent agent, ParcelFileDescriptor pipe,
- int token, boolean sendApk, boolean writeManifest, byte[] widgetData)
+ private final PackageManager mPackageManager;
+ private final PackageInfo mPackage;
+ private final IBackupAgent mAgent;
+ private final ParcelFileDescriptor mPipe;
+ private final int mToken;
+ private final boolean mIncludeApks;
+ private final File mFilesDir;
+
+ FullBackupRunner(
+ PackageInfo packageInfo,
+ IBackupAgent agent,
+ ParcelFileDescriptor pipe,
+ int token,
+ boolean includeApks)
throws IOException {
- mPackage = pack;
- mWidgetData = widgetData;
+ mPackageManager = backupManagerService.getPackageManager();
+ mPackage = packageInfo;
mAgent = agent;
mPipe = ParcelFileDescriptor.dup(pipe.getFileDescriptor());
mToken = token;
- mSendApk = sendApk;
- mWriteManifest = writeManifest;
+ mIncludeApks = includeApks;
+ mFilesDir = new File("/data/system");
}
@Override
public void run() {
try {
- FullBackupDataOutput output = new FullBackupDataOutput(
- mPipe, -1, mTransportFlags);
+ FullBackupDataOutput output =
+ new FullBackupDataOutput(mPipe, /* quota */ -1, mTransportFlags);
+ AppMetadataBackupWriter appMetadataBackupWriter =
+ new AppMetadataBackupWriter(output, mPackageManager);
+
+ String packageName = mPackage.packageName;
+ boolean isSharedStorage = SHARED_BACKUP_AGENT_PACKAGE.equals(packageName);
+ boolean writeApk =
+ shouldWriteApk(mPackage.applicationInfo, mIncludeApks, isSharedStorage);
- if (mWriteManifest) {
- final boolean writeWidgetData = mWidgetData != null;
+ if (!isSharedStorage) {
if (MORE_DEBUG) {
- Slog.d(TAG, "Writing manifest for " + mPackage.packageName);
+ Slog.d(TAG, "Writing manifest for " + packageName);
}
- FullBackupUtils
- .writeAppManifest(mPackage, backupManagerService.getPackageManager(),
- mManifestFile, mSendApk,
- writeWidgetData);
- FullBackup.backupToTar(mPackage.packageName, null, null,
- mFilesDir.getAbsolutePath(),
- mManifestFile.getAbsolutePath(),
- output);
- mManifestFile.delete();
- // We only need to write a metadata file if we have widget data to stash
- if (writeWidgetData) {
- writeMetadata(mPackage, mMetadataFile, mWidgetData);
- FullBackup.backupToTar(mPackage.packageName, null, null,
- mFilesDir.getAbsolutePath(),
- mMetadataFile.getAbsolutePath(),
- output);
- mMetadataFile.delete();
+ File manifestFile = new File(mFilesDir, BACKUP_MANIFEST_FILENAME);
+ appMetadataBackupWriter.backupManifest(
+ mPackage, manifestFile, mFilesDir, writeApk);
+ manifestFile.delete();
+
+ // Write widget data.
+ // TODO: http://b/22388012
+ byte[] widgetData =
+ AppWidgetBackupBridge.getWidgetState(
+ packageName, UserHandle.USER_SYSTEM);
+ if (widgetData != null && widgetData.length > 0) {
+ File metadataFile = new File(mFilesDir, BACKUP_METADATA_FILENAME);
+ appMetadataBackupWriter.backupWidget(
+ mPackage, metadataFile, mFilesDir, widgetData);
+ metadataFile.delete();
}
}
- if (mSendApk) {
- writeApkToBackup(mPackage, output);
+ // TODO(b/113807190): Look into removing, only used for 'adb backup'.
+ if (writeApk) {
+ appMetadataBackupWriter.backupApk(mPackage);
+ appMetadataBackupWriter.backupObb(mPackage);
}
- final boolean isSharedStorage =
- mPackage.packageName.equals(SHARED_BACKUP_AGENT_PACKAGE);
- final long timeout = isSharedStorage ?
- mAgentTimeoutParameters.getSharedBackupAgentTimeoutMillis() :
- mAgentTimeoutParameters.getFullBackupAgentTimeoutMillis();
-
if (DEBUG) {
- Slog.d(TAG, "Calling doFullBackup() on " + mPackage.packageName);
+ Slog.d(TAG, "Calling doFullBackup() on " + packageName);
}
- backupManagerService
- .prepareOperationTimeout(mToken,
- timeout,
- mTimeoutMonitor /* in parent class */,
- OP_TYPE_BACKUP_WAIT);
- mAgent.doFullBackup(mPipe, mQuota, mToken,
- backupManagerService.getBackupManagerBinder(), mTransportFlags);
+
+ long timeout =
+ isSharedStorage
+ ? mAgentTimeoutParameters.getSharedBackupAgentTimeoutMillis()
+ : mAgentTimeoutParameters.getFullBackupAgentTimeoutMillis();
+ backupManagerService.prepareOperationTimeout(
+ mToken,
+ timeout,
+ mTimeoutMonitor /* in parent class */,
+ OP_TYPE_BACKUP_WAIT);
+ mAgent.doFullBackup(
+ mPipe,
+ mQuota,
+ mToken,
+ backupManagerService.getBackupManagerBinder(),
+ mTransportFlags);
} catch (IOException e) {
Slog.e(TAG, "Error running full backup for " + mPackage.packageName);
} catch (RemoteException e) {
@@ -162,12 +162,33 @@ public class FullBackupEngine {
}
}
}
+
+ /**
+ * Don't write apks for forward-locked apps or system-bundled apps that are not upgraded.
+ */
+ private boolean shouldWriteApk(
+ ApplicationInfo applicationInfo, boolean includeApks, boolean isSharedStorage) {
+ boolean isForwardLocked =
+ (applicationInfo.privateFlags & ApplicationInfo.PRIVATE_FLAG_FORWARD_LOCK) != 0;
+ boolean isSystemApp = (applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0;
+ boolean isUpdatedSystemApp =
+ (applicationInfo.flags & ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) != 0;
+ return includeApks
+ && !isSharedStorage
+ && !isForwardLocked
+ && (!isSystemApp || isUpdatedSystemApp);
+ }
}
- public FullBackupEngine(BackupManagerService backupManagerService,
+ public FullBackupEngine(
+ BackupManagerService backupManagerService,
OutputStream output,
- FullBackupPreflight preflightHook, PackageInfo pkg,
- boolean alsoApks, BackupRestoreTask timeoutMonitor, long quota, int opToken,
+ FullBackupPreflight preflightHook,
+ PackageInfo pkg,
+ boolean alsoApks,
+ BackupRestoreTask timeoutMonitor,
+ long quota,
+ int opToken,
int transportFlags) {
this.backupManagerService = backupManagerService;
mOutput = output;
@@ -175,15 +196,13 @@ public class FullBackupEngine {
mPkg = pkg;
mIncludeApks = alsoApks;
mTimeoutMonitor = timeoutMonitor;
- mFilesDir = new File("/data/system");
- mManifestFile = new File(mFilesDir, BACKUP_MANIFEST_FILENAME);
- mMetadataFile = new File(mFilesDir, BACKUP_METADATA_FILENAME);
mQuota = quota;
mOpToken = opToken;
mTransportFlags = transportFlags;
- mAgentTimeoutParameters = Preconditions.checkNotNull(
- backupManagerService.getAgentTimeoutParameters(),
- "Timeout parameters cannot be null");
+ mAgentTimeoutParameters =
+ Preconditions.checkNotNull(
+ backupManagerService.getAgentTimeoutParameters(),
+ "Timeout parameters cannot be null");
}
public int preflightCheck() throws RemoteException {
@@ -213,27 +232,13 @@ public class FullBackupEngine {
try {
pipes = ParcelFileDescriptor.createPipe();
- ApplicationInfo app = mPkg.applicationInfo;
- final boolean isSharedStorage =
- mPkg.packageName.equals(SHARED_BACKUP_AGENT_PACKAGE);
- final boolean sendApk = mIncludeApks
- && !isSharedStorage
- && ((app.privateFlags & ApplicationInfo.PRIVATE_FLAG_FORWARD_LOCK) == 0)
- && ((app.flags & ApplicationInfo.FLAG_SYSTEM) == 0 ||
- (app.flags & ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) != 0);
-
- // TODO: http://b/22388012
- byte[] widgetBlob = AppWidgetBackupBridge.getWidgetState(mPkg.packageName,
- UserHandle.USER_SYSTEM);
-
- FullBackupRunner runner = new FullBackupRunner(mPkg, mAgent, pipes[1],
- mOpToken, sendApk, !isSharedStorage, widgetBlob);
- pipes[1].close(); // the runner has dup'd it
+ FullBackupRunner runner =
+ new FullBackupRunner(mPkg, mAgent, pipes[1], mOpToken, mIncludeApks);
+ pipes[1].close(); // the runner has dup'd it
pipes[1] = null;
Thread t = new Thread(runner, "app-data-runner");
t.start();
- // Now pull data from the app and stuff it into the output
FullBackupUtils.routeSocketDataToOutput(pipes[0], mOutput);
if (!backupManagerService.waitUntilOperationComplete(mOpToken)) {
@@ -288,84 +293,13 @@ public class FullBackupEngine {
if (MORE_DEBUG) {
Slog.d(TAG, "Binding to full backup agent : " + mPkg.packageName);
}
- mAgent = backupManagerService.bindToAgentSynchronous(mPkg.applicationInfo,
- ApplicationThreadConstants.BACKUP_MODE_FULL);
+ mAgent =
+ backupManagerService.bindToAgentSynchronous(
+ mPkg.applicationInfo, ApplicationThreadConstants.BACKUP_MODE_FULL);
}
return mAgent != null;
}
- private void writeApkToBackup(PackageInfo pkg, FullBackupDataOutput output) {
- // Forward-locked apps, system-bundled .apks, etc are filtered out before we get here
- // TODO: handle backing up split APKs
- final String appSourceDir = pkg.applicationInfo.getBaseCodePath();
- final String apkDir = new File(appSourceDir).getParent();
- FullBackup.backupToTar(pkg.packageName, FullBackup.APK_TREE_TOKEN, null,
- apkDir, appSourceDir, output);
-
- // TODO: migrate this to SharedStorageBackup, since AID_SYSTEM
- // doesn't have access to external storage.
-
- // Save associated .obb content if it exists and we did save the apk
- // check for .obb and save those too
- // TODO: http://b/22388012
- final UserEnvironment userEnv = new UserEnvironment(UserHandle.USER_SYSTEM);
- final File obbDir = userEnv.buildExternalStorageAppObbDirs(pkg.packageName)[0];
- if (obbDir != null) {
- if (MORE_DEBUG) {
- Log.i(TAG, "obb dir: " + obbDir.getAbsolutePath());
- }
- File[] obbFiles = obbDir.listFiles();
- if (obbFiles != null) {
- final String obbDirName = obbDir.getAbsolutePath();
- for (File obb : obbFiles) {
- FullBackup.backupToTar(pkg.packageName, FullBackup.OBB_TREE_TOKEN, null,
- obbDirName, obb.getAbsolutePath(), output);
- }
- }
- }
- }
-
- // Widget metadata format. All header entries are strings ending in LF:
- //
- // Version 1 header:
- // BACKUP_METADATA_VERSION, currently "1"
- // package name
- //
- // File data (all integers are binary in network byte order)
- // *N: 4 : integer token identifying which metadata blob
- // 4 : integer size of this blob = N
- // N : raw bytes of this metadata blob
- //
- // Currently understood blobs (always in network byte order):
- //
- // widgets : metadata token = 0x01FFED01 (BACKUP_WIDGET_METADATA_TOKEN)
- //
- // Unrecognized blobs are *ignored*, not errors.
- private void writeMetadata(PackageInfo pkg, File destination, byte[] widgetData)
- throws IOException {
- StringBuilder b = new StringBuilder(512);
- StringBuilderPrinter printer = new StringBuilderPrinter(b);
- printer.println(Integer.toString(BACKUP_METADATA_VERSION));
- printer.println(pkg.packageName);
-
- FileOutputStream fout = new FileOutputStream(destination);
- BufferedOutputStream bout = new BufferedOutputStream(fout);
- DataOutputStream out = new DataOutputStream(bout);
- bout.write(b.toString().getBytes()); // bypassing DataOutputStream
-
- if (widgetData != null && widgetData.length > 0) {
- out.writeInt(BACKUP_WIDGET_METADATA_TOKEN);
- out.writeInt(widgetData.length);
- out.write(widgetData);
- }
- bout.flush();
- out.close();
-
- // As with the manifest file, guarantee idempotence of the archive metadata
- // for the widget block by using a fixed mtime on the transient file.
- destination.setLastModified(0);
- }
-
private void tearDown() {
if (mPkg != null) {
backupManagerService.tearDownAgentAndKill(mPkg.applicationInfo);
diff --git a/services/backup/java/com/android/server/backup/keyvalue/KeyValueBackupTask.java b/services/backup/java/com/android/server/backup/keyvalue/KeyValueBackupTask.java
index a4cd629ff6fa..e915ce16a2ef 100644
--- a/services/backup/java/com/android/server/backup/keyvalue/KeyValueBackupTask.java
+++ b/services/backup/java/com/android/server/backup/keyvalue/KeyValueBackupTask.java
@@ -249,10 +249,10 @@ public class KeyValueBackupTask implements BackupRestoreTask, Runnable {
private final List<String> mPendingFullBackups;
private final Object mQueueLock;
@Nullable private final DataChangedJournal mJournal;
- @Nullable private PerformFullTransportBackupTask mFullBackupTask;
private int mStatus;
- @Nullable private IBackupAgent mAgentBinder;
+ @Nullable private PerformFullTransportBackupTask mFullBackupTask;
+ @Nullable private IBackupAgent mAgent;
@Nullable private PackageInfo mCurrentPackage;
@Nullable private File mSavedStateFile;
@Nullable private File mBackupDataFile;
@@ -349,24 +349,24 @@ public class KeyValueBackupTask implements BackupRestoreTask, Runnable {
// Not an explicit cancel, we need to flag it.
mCancelled = true;
mReporter.onAgentCancelled(packageInfo);
- errorCleanup();
+ cleanUpAgentForAgentError();
return false;
}
if (result == RemoteResult.FAILED_CANCELLED) {
mReporter.onAgentCancelled(packageInfo);
- errorCleanup();
+ cleanUpAgentForAgentError();
return false;
}
if (result == RemoteResult.FAILED_TIMED_OUT) {
mReporter.onAgentTimedOut(packageInfo);
- errorCleanup();
+ cleanUpAgentForAgentError();
return true;
}
Preconditions.checkState(result.isPresent());
long agentResult = result.get();
if (agentResult == BackupAgent.RESULT_ERROR) {
mReporter.onAgentResultError(packageInfo);
- errorCleanup();
+ cleanUpAgentForAgentError();
return true;
}
return sendDataToTransport();
@@ -380,37 +380,22 @@ public class KeyValueBackupTask implements BackupRestoreTask, Runnable {
/** Returns whether to consume next queue package. */
private boolean startTask() {
- synchronized (mBackupManagerService.getCurrentOpLock()) {
- if (mBackupManagerService.isBackupOperationInProgress()) {
- mReporter.onSkipBackup();
- return false;
- }
+ if (mBackupManagerService.isBackupOperationInProgress()) {
+ mReporter.onSkipBackup();
+ return false;
}
- String[] fullBackups = mPendingFullBackups.toArray(new String[mPendingFullBackups.size()]);
- mFullBackupTask =
- new PerformFullTransportBackupTask(
- mBackupManagerService,
- mTransportClient,
- /* fullBackupRestoreObserver */ null,
- fullBackups,
- /* updateSchedule */ false,
- /* runningJob */ null,
- new CountDownLatch(1),
- mReporter.getObserver(),
- mReporter.getMonitor(),
- mTaskFinishedListener,
- mUserInitiated);
+ // Unfortunately full backup task constructor registers the task with BMS, so we have to
+ // create it here instead of in our constructor.
+ mFullBackupTask = createFullBackupTask(mPendingFullBackups);
registerTask();
- mAgentBinder = null;
mStatus = BackupTransport.TRANSPORT_OK;
if (mQueue.isEmpty() && mPendingFullBackups.isEmpty()) {
mReporter.onEmptyQueueAtStart();
return false;
}
-
// We only backup PM if it was explicitly in the queue or if it's incremental.
boolean backupPm = mQueue.remove(PM_PACKAGE) || !mNonIncremental;
if (backupPm) {
@@ -446,6 +431,21 @@ public class KeyValueBackupTask implements BackupRestoreTask, Runnable {
return true;
}
+ private PerformFullTransportBackupTask createFullBackupTask(List<String> packages) {
+ return new PerformFullTransportBackupTask(
+ mBackupManagerService,
+ mTransportClient,
+ /* fullBackupRestoreObserver */ null,
+ packages.toArray(new String[packages.size()]),
+ /* updateSchedule */ false,
+ /* runningJob */ null,
+ new CountDownLatch(1),
+ mReporter.getObserver(),
+ mReporter.getMonitor(),
+ mTaskFinishedListener,
+ mUserInitiated);
+ }
+
/** Returns whether to consume next queue package. */
private boolean backupPm() {
RemoteResult agentResult = null;
@@ -455,10 +455,9 @@ public class KeyValueBackupTask implements BackupRestoreTask, Runnable {
// Since PM is running in the system process we can set up its agent directly.
BackupAgent pmAgent = mBackupManagerService.makeMetadataAgent();
- Pair<Integer, RemoteResult> statusAndResult =
- extractAgentData(
- PM_PACKAGE,
- IBackupAgent.Stub.asInterface(pmAgent.onBind()));
+ mAgent = IBackupAgent.Stub.asInterface(pmAgent.onBind());
+
+ Pair<Integer, RemoteResult> statusAndResult = extractAgentData(PM_PACKAGE, mAgent);
mStatus = statusAndResult.first;
agentResult = statusAndResult.second;
} catch (Exception e) {
@@ -467,6 +466,8 @@ public class KeyValueBackupTask implements BackupRestoreTask, Runnable {
}
if (mStatus != BackupTransport.TRANSPORT_OK) {
+ // In this case either extractAgentData() already made the agent clean-up or we haven't
+ // prepared the state for calling the agent, in either case we don't need to clean-up.
mBackupManagerService.resetBackupState(mStateDirectory);
return false;
}
@@ -512,7 +513,7 @@ public class KeyValueBackupTask implements BackupRestoreTask, Runnable {
applicationInfo,
ApplicationThreadConstants.BACKUP_MODE_INCREMENTAL);
if (agent != null) {
- mAgentBinder = agent;
+ mAgent = agent;
Pair<Integer, RemoteResult> statusAndResult =
extractAgentData(packageName, agent);
mStatus = statusAndResult.first;
@@ -532,7 +533,9 @@ public class KeyValueBackupTask implements BackupRestoreTask, Runnable {
}
if (mStatus != BackupTransport.TRANSPORT_OK) {
- mAgentBinder = null;
+ // In this case either extractAgentData() already made the agent clean-up or we haven't
+ // prepared the state for calling the agent, in either case we don't need to clean-up.
+ Preconditions.checkState(mAgent == null);
if (mStatus == BackupTransport.AGENT_ERROR) {
mReporter.onAgentError(packageName);
@@ -710,7 +713,7 @@ public class KeyValueBackupTask implements BackupRestoreTask, Runnable {
"doBackup()");
} catch (Exception e) {
mReporter.onCallAgentDoBackupError(packageName, callingAgent, e);
- errorCleanup();
+ cleanUpAgentForAgentError();
// TODO: Remove the check on callingAgent when RemoteCall supports local agent calls.
int status =
callingAgent ? BackupTransport.AGENT_ERROR : BackupTransport.TRANSPORT_ERROR;
@@ -808,7 +811,7 @@ public class KeyValueBackupTask implements BackupRestoreTask, Runnable {
boolean writingWidgetData = false;
try {
if (!validateBackupData(applicationInfo, mBackupDataFile)) {
- errorCleanup();
+ cleanUpAgentForAgentError();
return true;
}
writingWidgetData = true;
@@ -819,11 +822,11 @@ public class KeyValueBackupTask implements BackupRestoreTask, Runnable {
} else {
mReporter.onReadAgentDataError(packageName, e);
}
+ cleanUpAgentForAgentError();
revertTask();
return false;
}
- clearAgentState();
boolean nonIncremental = mSavedStateFile.length() == 0;
long size = mBackupDataFile.length();
if (size > 0) {
@@ -853,31 +856,12 @@ public class KeyValueBackupTask implements BackupRestoreTask, Runnable {
mStatus = BackupTransport.TRANSPORT_ERROR;
}
- updateFiles(mStatus);
- return handleTransportStatus(mStatus, packageName, size);
- }
-
- private void updateFiles(int status) {
- switch (status) {
- case BackupTransport.TRANSPORT_OK:
- mBackupDataFile.delete();
- mNewStateFile.renameTo(mSavedStateFile);
- break;
- case BackupTransport.TRANSPORT_NON_INCREMENTAL_BACKUP_REQUIRED:
- mSavedStateFile.delete();
- mBackupDataFile.delete();
- mNewStateFile.delete();
- break;
- default:
- // Includes:
- // * BackupTransport.TRANSPORT_PACKAGE_REJECTED
- // * BackupTransport.TRANSPORT_QUOTA_EXCEEDED
- // * BackupTransport.TRANSPORT_ERROR
- mBackupDataFile.delete();
- mNewStateFile.delete();
- break;
- }
+ boolean processQueue = handleTransportStatus(mStatus, packageName, size);
+ // We might report quota exceeded to the agent in handleTransportStatus() above, so we
+ // only clean-up after it.
+ cleanUpAgentForTransportStatus(mStatus);
+ return processQueue;
}
/** Returns whether to consume next queue package. */
@@ -898,7 +882,7 @@ public class KeyValueBackupTask implements BackupRestoreTask, Runnable {
}
if (status == BackupTransport.TRANSPORT_QUOTA_EXCEEDED) {
mReporter.onPackageBackupQuotaExceeded(packageName);
- agentDoQuotaExceeded(mAgentBinder, packageName, size);
+ agentDoQuotaExceeded(mAgent, packageName, size);
return true;
}
// Any other error here indicates a transport-level failure.
@@ -943,7 +927,7 @@ public class KeyValueBackupTask implements BackupRestoreTask, Runnable {
if (key != null && key.charAt(0) >= 0xff00) {
mReporter.onAgentIllegalKey(mCurrentPackage, key);
// Crash them if they wrote any protected keys.
- agentFail(mAgentBinder, "Illegal backup key: " + key);
+ agentFail(mAgent, "Illegal backup key: " + key);
return false;
}
backupDataInput.skipEntityData();
@@ -1025,21 +1009,50 @@ public class KeyValueBackupTask implements BackupRestoreTask, Runnable {
}
}
- private void errorCleanup() {
+ /** Cleans-up after having called the agent. */
+ private void cleanUpAgentForTransportStatus(int status) {
+ updateFiles(status);
+ cleanUpAgent();
+ }
+
+ /** Cleans-up if we failed to call the agent. */
+ private void cleanUpAgentForAgentError() {
mBackupDataFile.delete();
mNewStateFile.delete();
- clearAgentState();
+ cleanUpAgent();
}
- private void clearAgentState() {
- // Cleanup common to both success and failure cases.
+ private void updateFiles(int status) {
+ switch (status) {
+ case BackupTransport.TRANSPORT_OK:
+ mBackupDataFile.delete();
+ mNewStateFile.renameTo(mSavedStateFile);
+ break;
+ case BackupTransport.TRANSPORT_NON_INCREMENTAL_BACKUP_REQUIRED:
+ mSavedStateFile.delete();
+ mBackupDataFile.delete();
+ mNewStateFile.delete();
+ break;
+ default:
+ // Includes:
+ // * BackupTransport.TRANSPORT_PACKAGE_REJECTED
+ // * BackupTransport.TRANSPORT_QUOTA_EXCEEDED
+ // * BackupTransport.TRANSPORT_ERROR
+ mBackupDataFile.delete();
+ mNewStateFile.delete();
+ break;
+ }
+ }
+
+ /** Cleans-up file-descriptors and unbinds agent. */
+ private void cleanUpAgent() {
+ mAgent = null;
tryCloseFileDescriptor(mSavedState, "old state");
tryCloseFileDescriptor(mBackupData, "backup data");
tryCloseFileDescriptor(mNewState, "new state");
- synchronized (mBackupManagerService.getCurrentOpLock()) {
- // TODO: Do we still need this?
- mSavedState = mBackupData = mNewState = null;
- }
+ mSavedState = null;
+ mBackupData = null;
+ mNewState = null;
// For PM metadata (for which applicationInfo is null) there is no agent-bound state.
if (mCurrentPackage.applicationInfo != null) {
diff --git a/services/backup/java/com/android/server/backup/utils/FullBackupUtils.java b/services/backup/java/com/android/server/backup/utils/FullBackupUtils.java
index a3d56011272f..dbe3cd9225b5 100644
--- a/services/backup/java/com/android/server/backup/utils/FullBackupUtils.java
+++ b/services/backup/java/com/android/server/backup/utils/FullBackupUtils.java
@@ -16,23 +16,14 @@
package com.android.server.backup.utils;
-import static com.android.server.backup.BackupManagerService.BACKUP_MANIFEST_VERSION;
import static com.android.server.backup.BackupManagerService.TAG;
-import android.content.pm.PackageInfo;
-import android.content.pm.PackageManager;
-import android.content.pm.Signature;
-import android.content.pm.SigningInfo;
-import android.os.Build;
import android.os.ParcelFileDescriptor;
import android.util.Slog;
-import android.util.StringBuilderPrinter;
import java.io.DataInputStream;
import java.io.EOFException;
-import java.io.File;
import java.io.FileInputStream;
-import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
@@ -68,67 +59,4 @@ public class FullBackupUtils {
}
}
}
-
- /**
- * Writes app manifest to the given manifest file.
- *
- * @param pkg - app package, which manifest to write.
- * @param packageManager - {@link PackageManager} instance.
- * @param manifestFile - target manifest file.
- * @param withApk - whether include apk or not.
- * @param withWidgets - whether to write widgets data.
- * @throws IOException - in case of an error.
- */
- // TODO: withWidgets is not used, decide whether it is needed.
- public static void writeAppManifest(PackageInfo pkg, PackageManager packageManager,
- File manifestFile, boolean withApk, boolean withWidgets) throws IOException {
- // Manifest format. All data are strings ending in LF:
- // BACKUP_MANIFEST_VERSION, currently 1
- //
- // Version 1:
- // package name
- // package's versionCode
- // platform versionCode
- // getInstallerPackageName() for this package (maybe empty)
- // boolean: "1" if archive includes .apk; any other string means not
- // number of signatures == N
- // N*: signature byte array in ascii format per Signature.toCharsString()
- StringBuilder builder = new StringBuilder(4096);
- StringBuilderPrinter printer = new StringBuilderPrinter(builder);
-
- printer.println(Integer.toString(BACKUP_MANIFEST_VERSION));
- printer.println(pkg.packageName);
- printer.println(Long.toString(pkg.getLongVersionCode()));
- printer.println(Integer.toString(Build.VERSION.SDK_INT));
-
- String installerName = packageManager.getInstallerPackageName(pkg.packageName);
- printer.println((installerName != null) ? installerName : "");
-
- printer.println(withApk ? "1" : "0");
-
- // write the signature block
- SigningInfo signingInfo = pkg.signingInfo;
- if (signingInfo == null) {
- printer.println("0");
- } else {
- // retrieve the newest sigs to write
- // TODO (b/73988180) use entire signing history in case of rollbacks
- Signature[] signatures = signingInfo.getApkContentsSigners();
- printer.println(Integer.toString(signatures.length));
- for (Signature sig : signatures) {
- printer.println(sig.toCharsString());
- }
- }
-
- FileOutputStream outstream = new FileOutputStream(manifestFile);
- outstream.write(builder.toString().getBytes());
- outstream.close();
-
- // We want the manifest block in the archive stream to be idempotent:
- // each time we generate a backup stream for the app, we want the manifest
- // block to be identical. The underlying tar mechanism sees it as a file,
- // though, and will propagate its mtime, causing the tar header to vary.
- // Avoid this problem by pinning the mtime to zero.
- manifestFile.setLastModified(0);
- }
}
diff --git a/services/core/java/com/android/server/AlarmManagerService.java b/services/core/java/com/android/server/AlarmManagerService.java
index 26ef42f2b1e7..499c03d05bf2 100644
--- a/services/core/java/com/android/server/AlarmManagerService.java
+++ b/services/core/java/com/android/server/AlarmManagerService.java
@@ -52,6 +52,7 @@ import android.os.Bundle;
import android.os.Environment;
import android.os.Handler;
import android.os.IBinder;
+import android.os.Looper;
import android.os.Message;
import android.os.ParcelableException;
import android.os.PowerManager;
@@ -111,7 +112,7 @@ import java.util.TreeSet;
import java.util.function.Predicate;
/**
- * Alarm manager implementaion.
+ * Alarm manager implementation.
*
* Unit test:
atest $ANDROID_BUILD_TOP/frameworks/base/services/tests/servicestests/src/com/android/server/AlarmManagerServiceTest.java
@@ -138,7 +139,6 @@ class AlarmManagerService extends SystemService {
static final boolean DEBUG_STANDBY = localLOGV || false;
static final boolean RECORD_ALARMS_IN_HISTORY = true;
static final boolean RECORD_DEVICE_IDLE_ALARMS = false;
- static final int ALARM_EVENT = 1;
static final String TIMEZONE_PROPERTY = "persist.sys.timezone";
// Indices into the APP_STANDBY_MIN_DELAYS and KEYS_APP_STANDBY_DELAY arrays
@@ -169,7 +169,6 @@ class AlarmManagerService extends SystemService {
// List of alarms per uid deferred due to user applied background restrictions on the source app
SparseArray<ArrayList<Alarm>> mPendingBackgroundAlarms = new SparseArray<>();
- long mNativeData;
private long mNextWakeup;
private long mNextNonWakeup;
private long mNextWakeUpSetAt;
@@ -181,15 +180,14 @@ class AlarmManagerService extends SystemService {
private long mLastTickReceived;
private long mLastTickAdded;
private long mLastTickRemoved;
+ private final Injector mInjector;
int mBroadcastRefCount = 0;
PowerManager.WakeLock mWakeLock;
boolean mLastWakeLockUnimportantForLogging;
ArrayList<Alarm> mPendingNonWakeupAlarms = new ArrayList<>();
ArrayList<InFlight> mInFlight = new ArrayList<>();
- final AlarmHandler mHandler = new AlarmHandler();
+ AlarmHandler mHandler;
ClockReceiver mClockReceiver;
- InteractiveStateReceiver mInteractiveStateReceiver;
- private UninstallReceiver mUninstallReceiver;
final DeliveryTracker mDeliveryTracker = new DeliveryTracker();
PendingIntent mTimeTickSender;
PendingIntent mDateChangeSender;
@@ -277,7 +275,8 @@ class AlarmManagerService extends SystemService {
* global Settings. Any access to this class or its fields should be done while
* holding the AlarmManagerService.mLock lock.
*/
- private final class Constants extends ContentObserver {
+ @VisibleForTesting
+ final class Constants extends ContentObserver {
// Key names stored in the settings value.
private static final String KEY_MIN_FUTURITY = "min_futurity";
private static final String KEY_MIN_INTERVAL = "min_interval";
@@ -456,7 +455,7 @@ class AlarmManagerService extends SystemService {
}
}
- final Constants mConstants;
+ Constants mConstants;
// Alarm delivery ordering bookkeeping
static final int PRIO_TICK = 0;
@@ -510,7 +509,7 @@ class AlarmManagerService extends SystemService {
flags = seed.flags;
alarms.add(seed);
if (seed.operation == mTimeTickSender) {
- mLastTickAdded = System.currentTimeMillis();
+ mLastTickAdded = mInjector.getCurrentTimeMillis();
}
}
@@ -535,7 +534,7 @@ class AlarmManagerService extends SystemService {
}
alarms.add(index, alarm);
if (alarm.operation == mTimeTickSender) {
- mLastTickAdded = System.currentTimeMillis();
+ mLastTickAdded = mInjector.getCurrentTimeMillis();
}
if (DEBUG_BATCH) {
Slog.v(TAG, "Adding " + alarm + " to " + this);
@@ -573,7 +572,7 @@ class AlarmManagerService extends SystemService {
mNextAlarmClockMayChange = true;
}
if (alarm.operation == mTimeTickSender) {
- mLastTickRemoved = System.currentTimeMillis();
+ mLastTickRemoved = mInjector.getCurrentTimeMillis();
}
} else {
if (alarm.whenElapsed > newStart) {
@@ -734,17 +733,20 @@ class AlarmManagerService extends SystemService {
Alarm mNextWakeFromIdle = null;
ArrayList<Alarm> mPendingWhileIdleAlarms = new ArrayList<>();
- public AlarmManagerService(Context context) {
+ @VisibleForTesting
+ AlarmManagerService(Context context, Injector injector) {
super(context);
- mConstants = new Constants(mHandler);
+ mInjector = injector;
+ }
- publishLocalService(AlarmManagerInternal.class, new LocalService());
+ AlarmManagerService(Context context) {
+ this(context, new Injector(context));
}
- static long convertToElapsed(long when, int type) {
+ private long convertToElapsed(long when, int type) {
final boolean isRtc = (type == RTC || type == RTC_WAKEUP);
if (isRtc) {
- when -= System.currentTimeMillis() - SystemClock.elapsedRealtime();
+ when -= mInjector.getCurrentTimeMillis() - mInjector.getElapsedRealtime();
}
return when;
}
@@ -854,7 +856,7 @@ class AlarmManagerService extends SystemService {
ArrayList<Batch> oldSet = (ArrayList<Batch>) mAlarmBatches.clone();
mAlarmBatches.clear();
Alarm oldPendingIdleUntil = mPendingIdleUntil;
- final long nowElapsed = SystemClock.elapsedRealtime();
+ final long nowElapsed = mInjector.getElapsedRealtime();
final int oldBatches = oldSet.size();
for (int batchNum = 0; batchNum < oldBatches; batchNum++) {
Batch batch = oldSet.get(batchNum);
@@ -984,7 +986,7 @@ class AlarmManagerService extends SystemService {
alarmsToDeliver = alarmsForUid;
mPendingBackgroundAlarms.remove(uid);
}
- deliverPendingBackgroundAlarmsLocked(alarmsToDeliver, SystemClock.elapsedRealtime());
+ deliverPendingBackgroundAlarmsLocked(alarmsToDeliver, mInjector.getElapsedRealtime());
}
/**
@@ -1001,7 +1003,7 @@ class AlarmManagerService extends SystemService {
mPendingBackgroundAlarms, alarmsToDeliver, this::isBackgroundRestricted);
if (alarmsToDeliver.size() > 0) {
- deliverPendingBackgroundAlarmsLocked(alarmsToDeliver, SystemClock.elapsedRealtime());
+ deliverPendingBackgroundAlarmsLocked(alarmsToDeliver, mInjector.getElapsedRealtime());
}
}
@@ -1088,7 +1090,7 @@ class AlarmManagerService extends SystemService {
IdleDispatchEntry ent = new IdleDispatchEntry();
ent.uid = 0;
ent.pkg = "FINISH IDLE";
- ent.elapsedRealtime = SystemClock.elapsedRealtime();
+ ent.elapsedRealtime = mInjector.getElapsedRealtime();
mAllowWhileIdleDispatches.add(ent);
}
@@ -1096,7 +1098,7 @@ class AlarmManagerService extends SystemService {
if (mPendingWhileIdleAlarms.size() > 0) {
ArrayList<Alarm> alarms = mPendingWhileIdleAlarms;
mPendingWhileIdleAlarms = new ArrayList<>();
- final long nowElapsed = SystemClock.elapsedRealtime();
+ final long nowElapsed = mInjector.getElapsedRealtime();
for (int i=alarms.size() - 1; i >= 0; i--) {
Alarm a = alarms.get(i);
reAddAlarmLocked(a, nowElapsed, false);
@@ -1282,121 +1284,114 @@ class AlarmManagerService extends SystemService {
@Override
public void onStart() {
- mNativeData = init();
- mNextWakeup = mNextNonWakeup = 0;
+ mInjector.init();
+
+ synchronized (mLock) {
+ mHandler = new AlarmHandler(Looper.myLooper());
+ mConstants = new Constants(mHandler);
- // We have to set current TimeZone info to kernel
- // because kernel doesn't keep this after reboot
- setTimeZoneImpl(SystemProperties.get(TIMEZONE_PROPERTY));
+ mNextWakeup = mNextNonWakeup = 0;
- // Also sure that we're booting with a halfway sensible current time
- if (mNativeData != 0) {
+ // We have to set current TimeZone info to kernel
+ // because kernel doesn't keep this after reboot
+ setTimeZoneImpl(SystemProperties.get(TIMEZONE_PROPERTY));
+
+ // Also sure that we're booting with a halfway sensible current time
final long systemBuildTime = Environment.getRootDirectory().lastModified();
- if (System.currentTimeMillis() < systemBuildTime) {
- Slog.i(TAG, "Current time only " + System.currentTimeMillis()
+ if (mInjector.getCurrentTimeMillis() < systemBuildTime) {
+ Slog.i(TAG, "Current time only " + mInjector.getCurrentTimeMillis()
+ ", advancing to build time " + systemBuildTime);
- setKernelTime(mNativeData, systemBuildTime);
+ mInjector.setKernelTime(systemBuildTime);
}
- }
- // Determine SysUI's uid
- final PackageManager packMan = getContext().getPackageManager();
- try {
- PermissionInfo sysUiPerm = packMan.getPermissionInfo(SYSTEM_UI_SELF_PERMISSION, 0);
- ApplicationInfo sysUi = packMan.getApplicationInfo(sysUiPerm.packageName, 0);
- if ((sysUi.privateFlags&ApplicationInfo.PRIVATE_FLAG_PRIVILEGED) != 0) {
- mSystemUiUid = sysUi.uid;
+ // Determine SysUI's uid
+ mSystemUiUid = mInjector.getSystemUiUid();
+ if (mSystemUiUid <= 0) {
+ Slog.wtf(TAG, "SysUI package not found!");
+ }
+ mWakeLock = mInjector.getAlarmWakeLock();
+
+ mTimeTickSender = PendingIntent.getBroadcastAsUser(getContext(), 0,
+ new Intent(Intent.ACTION_TIME_TICK).addFlags(
+ Intent.FLAG_RECEIVER_REGISTERED_ONLY
+ | Intent.FLAG_RECEIVER_FOREGROUND
+ | Intent.FLAG_RECEIVER_VISIBLE_TO_INSTANT_APPS), 0,
+ UserHandle.ALL);
+ Intent intent = new Intent(Intent.ACTION_DATE_CHANGED);
+ intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING
+ | Intent.FLAG_RECEIVER_VISIBLE_TO_INSTANT_APPS);
+ mDateChangeSender = PendingIntent.getBroadcastAsUser(getContext(), 0, intent,
+ Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT, UserHandle.ALL);
+
+ mClockReceiver = mInjector.getClockReceiver(this);
+ new InteractiveStateReceiver();
+ new UninstallReceiver();
+
+ if (mInjector.isAlarmDriverPresent()) {
+ AlarmThread waitThread = new AlarmThread();
+ waitThread.start();
} else {
- Slog.e(TAG, "SysUI permission " + SYSTEM_UI_SELF_PERMISSION
- + " defined by non-privileged app " + sysUi.packageName
- + " - ignoring");
- }
- } catch (NameNotFoundException e) {
- }
-
- if (mSystemUiUid <= 0) {
- Slog.wtf(TAG, "SysUI package not found!");
- }
-
- PowerManager pm = (PowerManager) getContext().getSystemService(Context.POWER_SERVICE);
- mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "*alarm*");
-
- mTimeTickSender = PendingIntent.getBroadcastAsUser(getContext(), 0,
- new Intent(Intent.ACTION_TIME_TICK).addFlags(
- Intent.FLAG_RECEIVER_REGISTERED_ONLY
- | Intent.FLAG_RECEIVER_FOREGROUND
- | Intent.FLAG_RECEIVER_VISIBLE_TO_INSTANT_APPS), 0,
- UserHandle.ALL);
- Intent intent = new Intent(Intent.ACTION_DATE_CHANGED);
- intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING
- | Intent.FLAG_RECEIVER_VISIBLE_TO_INSTANT_APPS);
- mDateChangeSender = PendingIntent.getBroadcastAsUser(getContext(), 0, intent,
- Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT, UserHandle.ALL);
-
- // now that we have initied the driver schedule the alarm
- mClockReceiver = new ClockReceiver();
- mClockReceiver.scheduleTimeTickEvent();
- mClockReceiver.scheduleDateChangedEvent();
- mInteractiveStateReceiver = new InteractiveStateReceiver();
- mUninstallReceiver = new UninstallReceiver();
-
- if (mNativeData != 0) {
- AlarmThread waitThread = new AlarmThread();
- waitThread.start();
- } else {
- Slog.w(TAG, "Failed to open alarm driver. Falling back to a handler.");
- }
+ Slog.w(TAG, "Failed to open alarm driver. Falling back to a handler.");
+ }
- try {
- ActivityManager.getService().registerUidObserver(new UidObserver(),
- ActivityManager.UID_OBSERVER_GONE | ActivityManager.UID_OBSERVER_IDLE
- | ActivityManager.UID_OBSERVER_ACTIVE,
- ActivityManager.PROCESS_STATE_UNKNOWN, null);
- } catch (RemoteException e) {
- // ignored; both services live in system_server
+ try {
+ ActivityManager.getService().registerUidObserver(new UidObserver(),
+ ActivityManager.UID_OBSERVER_GONE | ActivityManager.UID_OBSERVER_IDLE
+ | ActivityManager.UID_OBSERVER_ACTIVE,
+ ActivityManager.PROCESS_STATE_UNKNOWN, null);
+ } catch (RemoteException e) {
+ // ignored; both services live in system_server
+ }
}
+ publishLocalService(AlarmManagerInternal.class, new LocalService());
publishBinderService(Context.ALARM_SERVICE, mService);
}
@Override
public void onBootPhase(int phase) {
if (phase == PHASE_SYSTEM_SERVICES_READY) {
- mConstants.start(getContext().getContentResolver());
- mAppOps = (AppOpsManager) getContext().getSystemService(Context.APP_OPS_SERVICE);
- mLocalDeviceIdleController
- = LocalServices.getService(DeviceIdleController.LocalService.class);
- mUsageStatsManagerInternal = LocalServices.getService(UsageStatsManagerInternal.class);
- mUsageStatsManagerInternal.addAppIdleStateChangeListener(new AppStandbyTracker());
+ synchronized (mLock) {
+ mConstants.start(getContext().getContentResolver());
+ mAppOps = (AppOpsManager) getContext().getSystemService(Context.APP_OPS_SERVICE);
+ mLocalDeviceIdleController =
+ LocalServices.getService(DeviceIdleController.LocalService.class);
+ mUsageStatsManagerInternal =
+ LocalServices.getService(UsageStatsManagerInternal.class);
+ mUsageStatsManagerInternal.addAppIdleStateChangeListener(new AppStandbyTracker());
+
+ mAppStateTracker = LocalServices.getService(AppStateTracker.class);
+ mAppStateTracker.addListener(mForceAppStandbyListener);
- mAppStateTracker = LocalServices.getService(AppStateTracker.class);
- mAppStateTracker.addListener(mForceAppStandbyListener);
+ mClockReceiver.scheduleTimeTickEvent();
+ mClockReceiver.scheduleDateChangedEvent();
+ }
}
}
@Override
protected void finalize() throws Throwable {
try {
- close(mNativeData);
+ mInjector.close();
} finally {
super.finalize();
}
}
boolean setTimeImpl(long millis) {
- if (mNativeData == 0) {
+ if (!mInjector.isAlarmDriverPresent()) {
Slog.w(TAG, "Not setting time since no alarm driver is available.");
return false;
}
synchronized (mLock) {
- final long currentTimeMillis = System.currentTimeMillis();
- setKernelTime(mNativeData, millis);
+ final long currentTimeMillis = mInjector.getCurrentTimeMillis();
+ mInjector.setKernelTime(millis);
final TimeZone timeZone = TimeZone.getDefault();
final int currentTzOffset = timeZone.getOffset(currentTimeMillis);
final int newTzOffset = timeZone.getOffset(millis);
if (currentTzOffset != newTzOffset) {
Slog.i(TAG, "Timezone offset has changed, updating kernel timezone");
- setKernelTimezone(mNativeData, -(newTzOffset / 60000));
+ mInjector.setKernelTimezone(-(newTzOffset / 60000));
}
// The native implementation of setKernelTime can return -1 even when the kernel
// time was set correctly, so assume setting kernel time was successful and always
@@ -1426,8 +1421,8 @@ class AlarmManagerService extends SystemService {
// Update the kernel timezone information
// Kernel tracks time offsets as 'minutes west of GMT'
- int gmtOffset = zone.getOffset(System.currentTimeMillis());
- setKernelTimezone(mNativeData, -(gmtOffset / 60000));
+ int gmtOffset = zone.getOffset(mInjector.getCurrentTimeMillis());
+ mInjector.setKernelTimezone(-(gmtOffset / 60000));
}
TimeZone.setDefault(null);
@@ -1498,7 +1493,7 @@ class AlarmManagerService extends SystemService {
triggerAtTime = 0;
}
- final long nowElapsed = SystemClock.elapsedRealtime();
+ final long nowElapsed = mInjector.getElapsedRealtime();
final long nominalTrigger = convertToElapsed(triggerAtTime, type);
// Try to prevent spamming by making sure we aren't firing alarms in the immediate future
final long minTrigger = nowElapsed + mConstants.MIN_FUTURITY;
@@ -1551,7 +1546,8 @@ class AlarmManagerService extends SystemService {
* Return the minimum time that should elapse before an app in the specified bucket
* can receive alarms again
*/
- private long getMinDelayForBucketLocked(int bucket) {
+ @VisibleForTesting
+ long getMinDelayForBucketLocked(int bucket) {
// UsageStats bucket values are treated as floors of their behavioral range.
// In other words, a bucket value between WORKING and ACTIVE is treated as
// WORKING, not as ACTIVE. The ACTIVE and NEVER bucket apply only at specific
@@ -1591,7 +1587,7 @@ class AlarmManagerService extends SystemService {
final String sourcePackage = alarm.sourcePackage;
final int sourceUserId = UserHandle.getUserId(alarm.creatorUid);
final int standbyBucket = mUsageStatsManagerInternal.getAppStandbyBucket(
- sourcePackage, sourceUserId, SystemClock.elapsedRealtime());
+ sourcePackage, sourceUserId, mInjector.getElapsedRealtime());
final Pair<String, Integer> packageUser = Pair.create(sourcePackage, sourceUserId);
final long lastElapsed = mLastAlarmDeliveredForPackage.getOrDefault(packageUser, 0L);
@@ -1619,7 +1615,7 @@ class AlarmManagerService extends SystemService {
a.when = a.whenElapsed = a.maxWhenElapsed = mNextWakeFromIdle.whenElapsed;
}
// Add fuzz to make the alarm go off some time before the actual desired time.
- final long nowElapsed = SystemClock.elapsedRealtime();
+ final long nowElapsed = mInjector.getElapsedRealtime();
final int fuzz = fuzzForDuration(a.whenElapsed-nowElapsed);
if (fuzz > 0) {
if (mRandom == null) {
@@ -1655,7 +1651,7 @@ class AlarmManagerService extends SystemService {
ent.pkg = a.operation.getCreatorPackage();
ent.tag = a.operation.getTag("");
ent.op = "SET";
- ent.elapsedRealtime = SystemClock.elapsedRealtime();
+ ent.elapsedRealtime = mInjector.getElapsedRealtime();
ent.argRealtime = a.whenElapsed;
mAllowWhileIdleDispatches.add(ent);
}
@@ -1675,7 +1671,7 @@ class AlarmManagerService extends SystemService {
IdleDispatchEntry ent = new IdleDispatchEntry();
ent.uid = 0;
ent.pkg = "START IDLE";
- ent.elapsedRealtime = SystemClock.elapsedRealtime();
+ ent.elapsedRealtime = mInjector.getElapsedRealtime();
mAllowWhileIdleDispatches.add(ent);
}
}
@@ -1890,8 +1886,8 @@ class AlarmManagerService extends SystemService {
pw.println(" App Standby Parole: " + mAppStandbyParole);
pw.println();
- final long nowRTC = System.currentTimeMillis();
- final long nowELAPSED = SystemClock.elapsedRealtime();
+ final long nowRTC = mInjector.getCurrentTimeMillis();
+ final long nowELAPSED = mInjector.getElapsedRealtime();
final long nowUPTIME = SystemClock.uptimeMillis();
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");
@@ -1958,10 +1954,10 @@ class AlarmManagerService extends SystemService {
pw.println();
pw.print(" Next kernel non-wakeup alarm: ");
- TimeUtils.formatDuration(getNextAlarm(mNativeData, ELAPSED_REALTIME), pw);
+ TimeUtils.formatDuration(mInjector.getNextAlarm(ELAPSED_REALTIME), pw);
pw.println();
pw.print(" Next kernel wakeup alarm: ");
- TimeUtils.formatDuration(getNextAlarm(mNativeData, ELAPSED_REALTIME_WAKEUP), pw);
+ TimeUtils.formatDuration(mInjector.getNextAlarm(ELAPSED_REALTIME_WAKEUP), pw);
pw.println();
pw.print(" Last wakeup: "); TimeUtils.formatDuration(mLastWakeup, nowELAPSED, pw);
@@ -2257,8 +2253,8 @@ class AlarmManagerService extends SystemService {
final ProtoOutputStream proto = new ProtoOutputStream(fd);
synchronized (mLock) {
- final long nowRTC = System.currentTimeMillis();
- final long nowElapsed = SystemClock.elapsedRealtime();
+ final long nowRTC = mInjector.getCurrentTimeMillis();
+ final long nowElapsed = mInjector.getElapsedRealtime();
proto.write(AlarmManagerServiceDumpProto.CURRENT_TIME, nowRTC);
proto.write(AlarmManagerServiceDumpProto.ELAPSED_REALTIME, nowElapsed);
proto.write(AlarmManagerServiceDumpProto.LAST_TIME_CHANGE_CLOCK_TIME,
@@ -2494,8 +2490,8 @@ class AlarmManagerService extends SystemService {
private void logBatchesLocked(SimpleDateFormat sdf) {
ByteArrayOutputStream bs = new ByteArrayOutputStream(2048);
PrintWriter pw = new PrintWriter(bs);
- final long nowRTC = System.currentTimeMillis();
- final long nowELAPSED = SystemClock.elapsedRealtime();
+ final long nowRTC = mInjector.getCurrentTimeMillis();
+ final long nowELAPSED = mInjector.getElapsedRealtime();
final int NZ = mAlarmBatches.size();
for (int iz = 0; iz < NZ; iz++) {
Batch bz = mAlarmBatches.get(iz);
@@ -2693,7 +2689,7 @@ class AlarmManagerService extends SystemService {
TimeUtils.formatDuration(mNextNonWakeUpSetAt - nowElapsed, errorMsg);
errorMsg.append(", mLastWakeup=");
TimeUtils.formatDuration(mLastWakeup - nowElapsed, errorMsg);
- errorMsg.append(", timerfd_gettime=" + getNextAlarm(mNativeData, ELAPSED_REALTIME));
+ errorMsg.append(", timerfd_gettime=" + mInjector.getNextAlarm(ELAPSED_REALTIME));
errorMsg.append("];");
}
if (mNextWakeup < (nowElapsed - 10_000) && mLastWakeup < mNextWakeup) {
@@ -2705,7 +2701,7 @@ class AlarmManagerService extends SystemService {
errorMsg.append(", mLastWakeup=");
TimeUtils.formatDuration(mLastWakeup - nowElapsed, errorMsg);
errorMsg.append(", timerfd_gettime="
- + getNextAlarm(mNativeData, ELAPSED_REALTIME_WAKEUP));
+ + mInjector.getNextAlarm(ELAPSED_REALTIME_WAKEUP));
errorMsg.append("];");
}
if (stuck) {
@@ -2716,7 +2712,7 @@ class AlarmManagerService extends SystemService {
void rescheduleKernelAlarmsLocked() {
// Schedule the next upcoming wakeup alarm. If there is a deliverable batch
// prior to that which contains no wakeups, we schedule that as well.
- final long nowElapsed = SystemClock.elapsedRealtime();
+ final long nowElapsed = mInjector.getElapsedRealtime();
validateLastAlarmExpiredLocked(nowElapsed);
long nextNonWakeup = 0;
if (mAlarmBatches.size() > 0) {
@@ -2743,7 +2739,7 @@ class AlarmManagerService extends SystemService {
}
}
- private void removeLocked(PendingIntent operation, IAlarmListener directReceiver) {
+ void removeLocked(PendingIntent operation, IAlarmListener directReceiver) {
if (operation == null && directReceiver == null) {
if (localLOGV) {
Slog.w(TAG, "requested remove() of null operation",
@@ -2983,7 +2979,7 @@ class AlarmManagerService extends SystemService {
void interactiveStateChangedLocked(boolean interactive) {
if (mInteractive != interactive) {
mInteractive = interactive;
- final long nowELAPSED = SystemClock.elapsedRealtime();
+ final long nowELAPSED = mInjector.getElapsedRealtime();
if (interactive) {
if (mPendingNonWakeupAlarms.size() > 0) {
final long thisDelayTime = nowELAPSED - mStartCurrentDelayTime;
@@ -3023,31 +3019,13 @@ class AlarmManagerService extends SystemService {
}
private void setLocked(int type, long when) {
- if (mNativeData != 0) {
- // The kernel never triggers alarms with negative wakeup times
- // so we ensure they are positive.
- long alarmSeconds, alarmNanoseconds;
- if (when < 0) {
- alarmSeconds = 0;
- alarmNanoseconds = 0;
- } else {
- alarmSeconds = when / 1000;
- alarmNanoseconds = (when % 1000) * 1000 * 1000;
- }
-
- final int result = set(mNativeData, type, alarmSeconds, alarmNanoseconds);
- if (result != 0) {
- final long nowElapsed = SystemClock.elapsedRealtime();
- Slog.wtf(TAG, "Unable to set kernel alarm, now=" + nowElapsed
- + " type=" + type + " when=" + when
- + " @ (" + alarmSeconds + "," + alarmNanoseconds
- + "), ret = " + result + " = " + Os.strerror(result));
- }
+ if (mInjector.isAlarmDriverPresent()) {
+ mInjector.setAlarm(type, when);
} else {
Message msg = Message.obtain();
- msg.what = ALARM_EVENT;
+ msg.what = AlarmHandler.ALARM_EVENT;
- mHandler.removeMessages(ALARM_EVENT);
+ mHandler.removeMessages(msg.what);
mHandler.sendMessageAtTime(msg, when);
}
}
@@ -3106,13 +3084,13 @@ class AlarmManagerService extends SystemService {
exemptOnBatterySaver);
}
- private native long init();
- private native void close(long nativeData);
- private native int set(long nativeData, int type, long seconds, long nanoseconds);
- private native int waitForAlarm(long nativeData);
- private native int setKernelTime(long nativeData, long millis);
- private native int setKernelTimezone(long nativeData, int minuteswest);
- private native long getNextAlarm(long nativeData, int type);
+ private static native long init();
+ private static native void close(long nativeData);
+ private static native int set(long nativeData, int type, long seconds, long nanoseconds);
+ private static native int waitForAlarm(long nativeData);
+ private static native int setKernelTime(long nativeData, long millis);
+ private static native int setKernelTimezone(long nativeData, int minuteswest);
+ private static native long getNextAlarm(long nativeData, int type);
private long getWhileIdleMinIntervalLocked(int uid) {
final boolean dozing = mPendingIdleUntil != null;
@@ -3516,6 +3494,103 @@ class AlarmManagerService extends SystemService {
|| (a.flags & FLAG_ALLOW_WHILE_IDLE_UNRESTRICTED) != 0;
}
+ @VisibleForTesting
+ static class Injector {
+ private long mNativeData;
+ private Context mContext;
+
+ Injector(Context context) {
+ mContext = context;
+ }
+
+ void init() {
+ mNativeData = AlarmManagerService.init();
+ }
+
+ int waitForAlarm() {
+ return AlarmManagerService.waitForAlarm(mNativeData);
+ }
+
+ boolean isAlarmDriverPresent() {
+ return mNativeData != 0;
+ }
+
+ void setAlarm(int type, long millis) {
+ // The kernel never triggers alarms with negative wakeup times
+ // so we ensure they are positive.
+ final long alarmSeconds, alarmNanoseconds;
+ if (millis < 0) {
+ alarmSeconds = 0;
+ alarmNanoseconds = 0;
+ } else {
+ alarmSeconds = millis / 1000;
+ alarmNanoseconds = (millis % 1000) * 1000 * 1000;
+ }
+
+ final int result = AlarmManagerService.set(mNativeData, type, alarmSeconds,
+ alarmNanoseconds);
+ if (result != 0) {
+ final long nowElapsed = SystemClock.elapsedRealtime();
+ Slog.wtf(TAG, "Unable to set kernel alarm, now=" + nowElapsed
+ + " type=" + type + " @ (" + alarmSeconds + "," + alarmNanoseconds
+ + "), ret = " + result + " = " + Os.strerror(result));
+ }
+ }
+
+ long getNextAlarm(int type) {
+ return AlarmManagerService.getNextAlarm(mNativeData, type);
+ }
+
+ void setKernelTimezone(int minutesWest) {
+ AlarmManagerService.setKernelTimezone(mNativeData, minutesWest);
+ }
+
+ void setKernelTime(long millis) {
+ if (mNativeData != 0) {
+ AlarmManagerService.setKernelTime(mNativeData, millis);
+ }
+ }
+
+ void close() {
+ AlarmManagerService.close(mNativeData);
+ }
+
+ long getElapsedRealtime() {
+ return SystemClock.elapsedRealtime();
+ }
+
+ long getCurrentTimeMillis() {
+ return System.currentTimeMillis();
+ }
+
+ PowerManager.WakeLock getAlarmWakeLock() {
+ final PowerManager pm = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
+ return pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "*alarm*");
+ }
+
+ int getSystemUiUid() {
+ int sysUiUid = -1;
+ final PackageManager pm = mContext.getPackageManager();
+ try {
+ PermissionInfo sysUiPerm = pm.getPermissionInfo(SYSTEM_UI_SELF_PERMISSION, 0);
+ ApplicationInfo sysUi = pm.getApplicationInfo(sysUiPerm.packageName, 0);
+ if ((sysUi.privateFlags & ApplicationInfo.PRIVATE_FLAG_PRIVILEGED) != 0) {
+ sysUiUid = sysUi.uid;
+ } else {
+ Slog.e(TAG, "SysUI permission " + SYSTEM_UI_SELF_PERMISSION
+ + " defined by non-privileged app " + sysUi.packageName
+ + " - ignoring");
+ }
+ } catch (NameNotFoundException e) {
+ }
+ return sysUiUid;
+ }
+
+ ClockReceiver getClockReceiver(AlarmManagerService service) {
+ return service.new ClockReceiver();
+ }
+ }
+
private class AlarmThread extends Thread
{
private int mFalseWakeups;
@@ -3524,7 +3599,7 @@ class AlarmManagerService extends SystemService {
{
super("AlarmManager");
mFalseWakeups = 0;
- mWtfThreshold = 10;
+ mWtfThreshold = 100;
}
public void run()
@@ -3533,14 +3608,16 @@ class AlarmManagerService extends SystemService {
while (true)
{
- int result = waitForAlarm(mNativeData);
-
- final long nowRTC = System.currentTimeMillis();
- final long nowELAPSED = SystemClock.elapsedRealtime();
+ int result = mInjector.waitForAlarm();
+ final long nowRTC = mInjector.getCurrentTimeMillis();
+ final long nowELAPSED = mInjector.getElapsedRealtime();
synchronized (mLock) {
mLastWakeup = nowELAPSED;
}
-
+ if (result == 0) {
+ Slog.wtf(TAG, "waitForAlarm returned 0, nowRTC = " + nowRTC
+ + ", nowElapsed = " + nowELAPSED);
+ }
triggerList.clear();
if ((result & TIME_CHANGED_MASK) != 0) {
@@ -3720,7 +3797,8 @@ class AlarmManagerService extends SystemService {
public static final int APP_STANDBY_PAROLE_CHANGED = 6;
public static final int REMOVE_FOR_STOPPED = 7;
- public AlarmHandler() {
+ AlarmHandler(Looper looper) {
+ super(looper);
}
public void postRemoveForStopped(int uid) {
@@ -3732,8 +3810,8 @@ class AlarmManagerService extends SystemService {
case ALARM_EVENT: {
ArrayList<Alarm> triggerList = new ArrayList<Alarm>();
synchronized (mLock) {
- final long nowRTC = System.currentTimeMillis();
- final long nowELAPSED = SystemClock.elapsedRealtime();
+ final long nowRTC = mInjector.getCurrentTimeMillis();
+ final long nowELAPSED = mInjector.getElapsedRealtime();
triggerAlarmsLocked(triggerList, nowELAPSED, nowRTC);
updateNextAlarmClockLocked();
}
@@ -3817,7 +3895,7 @@ class AlarmManagerService extends SystemService {
Slog.v(TAG, "Received TIME_TICK alarm; rescheduling");
}
synchronized (mLock) {
- mLastTickReceived = System.currentTimeMillis();
+ mLastTickReceived = mInjector.getCurrentTimeMillis();
}
scheduleTimeTickEvent();
} else if (intent.getAction().equals(Intent.ACTION_DATE_CHANGED)) {
@@ -3826,14 +3904,14 @@ class AlarmManagerService extends SystemService {
// based off of the current Zone gmt offset + userspace tracked
// daylight savings information.
TimeZone zone = TimeZone.getTimeZone(SystemProperties.get(TIMEZONE_PROPERTY));
- int gmtOffset = zone.getOffset(System.currentTimeMillis());
- setKernelTimezone(mNativeData, -(gmtOffset / 60000));
+ int gmtOffset = zone.getOffset(mInjector.getCurrentTimeMillis());
+ mInjector.setKernelTimezone(-(gmtOffset / 60000));
scheduleDateChangedEvent();
}
}
public void scheduleTimeTickEvent() {
- final long currentTime = System.currentTimeMillis();
+ final long currentTime = mInjector.getCurrentTimeMillis();
final long nextTime = 60000 * ((currentTime / 60000) + 1);
// Schedule this event for the amount of time that it would take to get to
@@ -3841,7 +3919,7 @@ class AlarmManagerService extends SystemService {
final long tickEventDelay = nextTime - currentTime;
final WorkSource workSource = null; // Let system take blame for time tick events.
- setImpl(ELAPSED_REALTIME, SystemClock.elapsedRealtime() + tickEventDelay, 0,
+ setImpl(ELAPSED_REALTIME, mInjector.getElapsedRealtime() + tickEventDelay, 0,
0, mTimeTickSender, null, null, AlarmManager.FLAG_STANDALONE, workSource,
null, Process.myUid(), "android");
@@ -3853,7 +3931,7 @@ class AlarmManagerService extends SystemService {
public void scheduleDateChangedEvent() {
Calendar calendar = Calendar.getInstance();
- calendar.setTimeInMillis(System.currentTimeMillis());
+ calendar.setTimeInMillis(mInjector.getCurrentTimeMillis());
calendar.set(Calendar.HOUR_OF_DAY, 0);
calendar.set(Calendar.MINUTE, 0);
calendar.set(Calendar.SECOND, 0);
@@ -4122,7 +4200,7 @@ class AlarmManagerService extends SystemService {
}
private void updateStatsLocked(InFlight inflight) {
- final long nowELAPSED = SystemClock.elapsedRealtime();
+ final long nowELAPSED = mInjector.getElapsedRealtime();
BroadcastStats bs = inflight.mBroadcastStats;
bs.nesting--;
if (bs.nesting <= 0) {
diff --git a/services/core/java/com/android/server/InputMethodManagerService.java b/services/core/java/com/android/server/InputMethodManagerService.java
index f981b261c537..e435a4fd6384 100644
--- a/services/core/java/com/android/server/InputMethodManagerService.java
+++ b/services/core/java/com/android/server/InputMethodManagerService.java
@@ -27,6 +27,7 @@ import android.accessibilityservice.AccessibilityService;
import android.annotation.AnyThread;
import android.annotation.BinderThread;
import android.annotation.ColorInt;
+import android.annotation.DrawableRes;
import android.annotation.IntDef;
import android.annotation.MainThread;
import android.annotation.NonNull;
@@ -209,7 +210,6 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
static final int MSG_BIND_CLIENT = 3010;
static final int MSG_SET_ACTIVE = 3020;
static final int MSG_SET_INTERACTIVE = 3030;
- static final int MSG_SET_USER_ACTION_NOTIFICATION_SEQUENCE_NUMBER = 3040;
static final int MSG_REPORT_FULLSCREEN_MODE = 3045;
static final int MSG_HARD_KEYBOARD_SWITCH_CHANGED = 4000;
@@ -597,8 +597,6 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
*/
boolean mIsInteractive = true;
- int mCurUserActionNotificationSequenceNumber = 0;
-
int mBackDisposition = InputMethodService.BACK_DISPOSITION_DEFAULT;
/**
@@ -1821,7 +1819,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
}
return new InputBindResult(InputBindResult.ResultCode.SUCCESS_WITH_IME_SESSION,
session.session, (session.channel != null ? session.channel.dup() : null),
- mCurId, mCurSeq, mCurUserActionNotificationSequenceNumber);
+ mCurId, mCurSeq);
}
@GuardedBy("mMethodMap")
@@ -1880,8 +1878,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
requestClientSessionLocked(cs);
return new InputBindResult(
InputBindResult.ResultCode.SUCCESS_WAITING_IME_SESSION,
- null, null, mCurId, mCurSeq,
- mCurUserActionNotificationSequenceNumber);
+ null, null, mCurId, mCurSeq);
} else if (SystemClock.uptimeMillis()
< (mLastBindTime+TIME_TO_RECONNECT)) {
// In this case we have connected to the service, but
@@ -1893,8 +1890,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
// to see if we can get back in touch with the service.
return new InputBindResult(
InputBindResult.ResultCode.SUCCESS_WAITING_IME_BINDING,
- null, null, mCurId, mCurSeq,
- mCurUserActionNotificationSequenceNumber);
+ null, null, mCurId, mCurSeq);
} else {
EventLog.writeEvent(EventLogTags.IMF_FORCE_RECONNECT_IME,
mCurMethodId, SystemClock.uptimeMillis()-mLastBindTime, 0);
@@ -1916,8 +1912,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
// party code.
return new InputBindResult(
InputBindResult.ResultCode.ERROR_SYSTEM_NOT_READY,
- null, null, mCurMethodId, mCurSeq,
- mCurUserActionNotificationSequenceNumber);
+ null, null, mCurMethodId, mCurSeq);
}
InputMethodInfo info = mMethodMap.get(mCurMethodId);
@@ -1945,8 +1940,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
}
return new InputBindResult(
InputBindResult.ResultCode.SUCCESS_WAITING_IME_BINDING,
- null, null, mCurId, mCurSeq,
- mCurUserActionNotificationSequenceNumber);
+ null, null, mCurId, mCurSeq);
}
mCurIntent = null;
Slog.w(TAG, "Failure connecting to input method service: " + mCurIntent);
@@ -2113,8 +2107,9 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
}
}
- @Override
- public void updateStatusIcon(IBinder token, String packageName, int iconId) {
+ @BinderThread
+ private void updateStatusIcon(@NonNull IBinder token, String packageName,
+ @DrawableRes int iconId) {
synchronized (mMethodMap) {
if (!calledWithValidToken(token)) {
return;
@@ -2752,7 +2747,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
}
return new InputBindResult(
InputBindResult.ResultCode.SUCCESS_REPORT_WINDOW_FOCUS_ONLY,
- null, null, null, -1, -1);
+ null, null, null, -1);
}
mCurFocusedWindow = windowToken;
mCurFocusedWindowSoftInputMode = softInputMode;
@@ -3060,8 +3055,8 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
}
}
- @Override
- public boolean shouldOfferSwitchingToNextInputMethod(IBinder token) {
+ @BinderThread
+ private boolean shouldOfferSwitchingToNextInputMethod(@NonNull IBinder token) {
if (!calledFromValidUser()) {
return false;
}
@@ -3170,17 +3165,16 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
mWindowManagerInternal.clearLastInputMethodWindowForTransition();
}
- @Override
- public void notifyUserAction(int sequenceNumber) {
+ @BinderThread
+ private void notifyUserAction(@NonNull IBinder token) {
if (DEBUG) {
- Slog.d(TAG, "Got the notification of a user action. sequenceNumber:" + sequenceNumber);
+ Slog.d(TAG, "Got the notification of a user action.");
}
synchronized (mMethodMap) {
- if (mCurUserActionNotificationSequenceNumber != sequenceNumber) {
+ if (mCurToken != token) {
if (DEBUG) {
- Slog.d(TAG, "Ignoring the user action notification due to the sequence number "
- + "mismatch. expected:" + mCurUserActionNotificationSequenceNumber
- + " actual: " + sequenceNumber);
+ Slog.d(TAG, "Ignoring the user action notification from IMEs that are no longer"
+ + " active.");
}
return;
}
@@ -3220,8 +3214,8 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
}
}
- @Override
- public void hideMySoftInput(IBinder token, int flags) {
+ @BinderThread
+ private void hideMySoftInput(@NonNull IBinder token, int flags) {
if (!calledFromValidUser()) {
return;
}
@@ -3238,8 +3232,8 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
}
}
- @Override
- public void showMySoftInput(IBinder token, int flags) {
+ @BinderThread
+ private void showMySoftInput(@NonNull IBinder token, int flags) {
if (!calledFromValidUser()) {
return;
}
@@ -3443,20 +3437,6 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
case MSG_START_VR_INPUT:
startVrInputMethodNoCheck((ComponentName) msg.obj);
return true;
- case MSG_SET_USER_ACTION_NOTIFICATION_SEQUENCE_NUMBER: {
- final int sequenceNumber = msg.arg1;
- final ClientState clientState = (ClientState)msg.obj;
- try {
- clientState.client.setUserActionNotificationSequenceNumber(sequenceNumber);
- } catch (RemoteException e) {
- Slog.w(TAG, "Got RemoteException sending "
- + "setUserActionNotificationSequenceNumber("
- + sequenceNumber + ") notification to pid "
- + clientState.pid + " uid "
- + clientState.uid);
- }
- return true;
- }
case MSG_REPORT_FULLSCREEN_MODE: {
final boolean fullscreen = msg.arg1 != 0;
final ClientState clientState = (ClientState)msg.obj;
@@ -3942,19 +3922,6 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
mSettings.saveCurrentInputMethodAndSubtypeToHistory(mCurMethodId, mCurrentSubtype);
}
- mCurUserActionNotificationSequenceNumber =
- Math.max(mCurUserActionNotificationSequenceNumber + 1, 1);
- if (DEBUG) {
- Slog.d(TAG, "Bump mCurUserActionNotificationSequenceNumber:"
- + mCurUserActionNotificationSequenceNumber);
- }
-
- if (mCurClient != null && mCurClient.client != null) {
- executeOrSendMessage(mCurClient.client, mCaller.obtainMessageIO(
- MSG_SET_USER_ACTION_NOTIFICATION_SEQUENCE_NUMBER,
- mCurUserActionNotificationSequenceNumber, mCurClient));
- }
-
if (isVrInput) {
// Updates to InputMethod are transient in VR mode. Any changes to Settings are skipped.
return;
@@ -4556,8 +4523,6 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
+ " mShowForced=" + mShowForced
+ " mInputShown=" + mInputShown);
p.println(" mInFullscreenMode=" + mInFullscreenMode);
- p.println(" mCurUserActionNotificationSequenceNumber="
- + mCurUserActionNotificationSequenceNumber);
p.println(" mSystemReady=" + mSystemReady + " mInteractive=" + mIsInteractive);
p.println(" mSettingsObserver=" + mSettingsObserver);
p.println(" mSwitchingController:");
@@ -5007,5 +4972,59 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
public void reportFullscreenMode(boolean fullscreen) {
mImms.reportFullscreenMode(mToken, fullscreen);
}
+
+ @BinderThread
+ @Override
+ public void setInputMethod(String id) {
+ mImms.setInputMethod(mToken, id);
+ }
+
+ @BinderThread
+ @Override
+ public void setInputMethodAndSubtype(String id, InputMethodSubtype subtype) {
+ mImms.setInputMethodAndSubtype(mToken, id, subtype);
+ }
+
+ @BinderThread
+ @Override
+ public void hideMySoftInput(int flags) {
+ mImms.hideMySoftInput(mToken, flags);
+ }
+
+ @BinderThread
+ @Override
+ public void showMySoftInput(int flags) {
+ mImms.showMySoftInput(mToken, flags);
+ }
+
+ @BinderThread
+ @Override
+ public void updateStatusIcon(String packageName, @DrawableRes int iconId) {
+ mImms.updateStatusIcon(mToken, packageName, iconId);
+ }
+
+ @BinderThread
+ @Override
+ public boolean switchToPreviousInputMethod() {
+ return mImms.switchToPreviousInputMethod(mToken);
+ }
+
+ @BinderThread
+ @Override
+ public boolean switchToNextInputMethod(boolean onlyCurrentIme) {
+ return mImms.switchToNextInputMethod(mToken, onlyCurrentIme);
+ }
+
+ @BinderThread
+ @Override
+ public boolean shouldOfferSwitchingToNextInputMethod() {
+ return mImms.shouldOfferSwitchingToNextInputMethod(mToken);
+ }
+
+ @BinderThread
+ @Override
+ public void notifyUserActionAsync() {
+ mImms.notifyUserAction(mToken);
+ }
}
}
diff --git a/services/core/java/com/android/server/LooperStatsService.java b/services/core/java/com/android/server/LooperStatsService.java
index 23b30cc5b1b0..ab7bf288a2ff 100644
--- a/services/core/java/com/android/server/LooperStatsService.java
+++ b/services/core/java/com/android/server/LooperStatsService.java
@@ -148,7 +148,7 @@ public class LooperStatsService extends Binder {
@Override
public void onStart() {
publishLocalService(LooperStats.class, mStats);
- // TODO: publish LooperStatsService as a binder service when the SE Policy is changed.
+ publishBinderService(LOOPER_STATS_SERVICE_NAME, mService);
}
@Override
diff --git a/services/core/java/com/android/server/NetworkManagementService.java b/services/core/java/com/android/server/NetworkManagementService.java
index d8296023383c..daf870dfebf5 100644
--- a/services/core/java/com/android/server/NetworkManagementService.java
+++ b/services/core/java/com/android/server/NetworkManagementService.java
@@ -316,7 +316,6 @@ public class NetworkManagementService extends INetworkManagementService.Stub
}
private HashMap<String, IdleTimerParams> mActiveIdleTimers = Maps.newHashMap();
- private volatile boolean mBandwidthControlEnabled;
private volatile boolean mFirewallEnabled;
private volatile boolean mStrictEnabled;
@@ -624,27 +623,11 @@ public class NetworkManagementService extends INetworkManagementService.Stub
*/
private void prepareNativeDaemon() {
- mBandwidthControlEnabled = false;
-
- // only enable bandwidth control when support exists
- final boolean hasKernelSupport = new File("/proc/net/xt_qtaguid/ctrl").exists();
-
// push any existing quota or UID rules
synchronized (mQuotaLock) {
- if (hasKernelSupport) {
- Slog.d(TAG, "enabling bandwidth control");
- try {
- mConnector.execute("bandwidth", "enable");
- mBandwidthControlEnabled = true;
- } catch (NativeDaemonConnectorException e) {
- Log.wtf(TAG, "problem enabling bandwidth controls", e);
- }
- } else {
- Slog.i(TAG, "not enabling bandwidth control");
- }
-
- SystemProperties.set(PROP_QTAGUID_ENABLED, mBandwidthControlEnabled ? "1" : "0");
+ // Netd unconditionally enable bandwidth control
+ SystemProperties.set(PROP_QTAGUID_ENABLED, "1");
mStrictEnabled = true;
@@ -726,11 +709,10 @@ public class NetworkManagementService extends INetworkManagementService.Stub
}
}
- if (mBandwidthControlEnabled) {
- try {
- getBatteryStats().noteNetworkStatsEnabled();
- } catch (RemoteException e) {
- }
+
+ try {
+ getBatteryStats().noteNetworkStatsEnabled();
+ } catch (RemoteException e) {
}
}
@@ -1576,10 +1558,6 @@ public class NetworkManagementService extends INetworkManagementService.Stub
public void setInterfaceQuota(String iface, long quotaBytes) {
mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
- // silently discard when control disabled
- // TODO: eventually migrate to be always enabled
- if (!mBandwidthControlEnabled) return;
-
synchronized (mQuotaLock) {
if (mActiveQuotas.containsKey(iface)) {
throw new IllegalStateException("iface " + iface + " already has quota");
@@ -1610,10 +1588,6 @@ public class NetworkManagementService extends INetworkManagementService.Stub
public void removeInterfaceQuota(String iface) {
mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
- // silently discard when control disabled
- // TODO: eventually migrate to be always enabled
- if (!mBandwidthControlEnabled) return;
-
synchronized (mQuotaLock) {
if (!mActiveQuotas.containsKey(iface)) {
// TODO: eventually consider throwing
@@ -1647,10 +1621,6 @@ public class NetworkManagementService extends INetworkManagementService.Stub
public void setInterfaceAlert(String iface, long alertBytes) {
mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
- // silently discard when control disabled
- // TODO: eventually migrate to be always enabled
- if (!mBandwidthControlEnabled) return;
-
// quick sanity check
if (!mActiveQuotas.containsKey(iface)) {
throw new IllegalStateException("setting alert requires existing quota on iface");
@@ -1675,10 +1645,6 @@ public class NetworkManagementService extends INetworkManagementService.Stub
public void removeInterfaceAlert(String iface) {
mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
- // silently discard when control disabled
- // TODO: eventually migrate to be always enabled
- if (!mBandwidthControlEnabled) return;
-
synchronized (mQuotaLock) {
if (!mActiveAlerts.containsKey(iface)) {
// TODO: eventually consider throwing
@@ -1699,10 +1665,6 @@ public class NetworkManagementService extends INetworkManagementService.Stub
public void setGlobalAlert(long alertBytes) {
mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
- // silently discard when control disabled
- // TODO: eventually migrate to be always enabled
- if (!mBandwidthControlEnabled) return;
-
try {
mConnector.execute("bandwidth", "setglobalalert", alertBytes);
} catch (NativeDaemonConnectorException e) {
@@ -1713,10 +1675,6 @@ public class NetworkManagementService extends INetworkManagementService.Stub
private void setUidOnMeteredNetworkList(int uid, boolean blacklist, boolean enable) {
mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
- // silently discard when control disabled
- // TODO: eventually migrate to be always enabled
- if (!mBandwidthControlEnabled) return;
-
final String chain = blacklist ? "naughtyapps" : "niceapps";
final String suffix = enable ? "add" : "remove";
@@ -1868,7 +1826,7 @@ public class NetworkManagementService extends INetworkManagementService.Stub
@Override
public boolean isBandwidthControlEnabled() {
mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
- return mBandwidthControlEnabled;
+ return true;
}
@Override
@@ -2376,7 +2334,6 @@ public class NetworkManagementService extends INetworkManagementService.Stub
mConnector.dump(fd, pw, args);
pw.println();
- pw.print("Bandwidth control enabled: "); pw.println(mBandwidthControlEnabled);
pw.print("mMobileActivityFromRadio="); pw.print(mMobileActivityFromRadio);
pw.print(" mLastPowerStateFromRadio="); pw.println(mLastPowerStateFromRadio);
pw.print("mNetworkActive="); pw.println(mNetworkActive);
diff --git a/services/core/java/com/android/server/TelephonyRegistry.java b/services/core/java/com/android/server/TelephonyRegistry.java
index c44a81e2dcd0..98b88cb557af 100644
--- a/services/core/java/com/android/server/TelephonyRegistry.java
+++ b/services/core/java/com/android/server/TelephonyRegistry.java
@@ -101,6 +101,7 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub {
IPhoneStateListener callback;
IOnSubscriptionsChangedListener onSubscriptionsChangedListenerCallback;
+ IOnSubscriptionsChangedListener onOpportunisticSubscriptionsChangedListenerCallback;
int callerUid;
int callerPid;
@@ -119,6 +120,10 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub {
return (onSubscriptionsChangedListenerCallback != null);
}
+ boolean matchOnOpportunisticSubscriptionsChangedListener() {
+ return (onOpportunisticSubscriptionsChangedListenerCallback != null);
+ }
+
boolean canReadCallLog() {
try {
return TelephonyPermissions.checkReadCallLog(
@@ -133,7 +138,9 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub {
return "{callingPackage=" + callingPackage + " binder=" + binder
+ " callback=" + callback
+ " onSubscriptionsChangedListenererCallback="
- + onSubscriptionsChangedListenerCallback
+ + onSubscriptionsChangedListenerCallback
+ + " onOpportunisticSubscriptionsChangedListenererCallback="
+ + onOpportunisticSubscriptionsChangedListenerCallback
+ " callerUid=" + callerUid + " subId=" + subId + " phoneId=" + phoneId
+ " events=" + Integer.toHexString(events) + "}";
}
@@ -149,7 +156,9 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub {
private final AppOpsManager mAppOps;
- private boolean hasNotifySubscriptionInfoChangedOccurred = false;
+ private boolean mHasNotifySubscriptionInfoChangedOccurred = false;
+
+ private boolean mHasNotifyOpportunisticSubscriptionInfoChangedOccurred = false;
private int mNumPhones;
@@ -410,7 +419,7 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub {
log("listen oscl: Register r=" + r);
}
// Always notify when registration occurs if there has been a notification.
- if (hasNotifySubscriptionInfoChangedOccurred) {
+ if (mHasNotifySubscriptionInfoChangedOccurred) {
try {
if (VDBG) log("listen oscl: send to r=" + r);
r.onSubscriptionsChangedListenerCallback.onSubscriptionsChanged();
@@ -420,7 +429,7 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub {
remove(r.binder);
}
} else {
- log("listen oscl: hasNotifySubscriptionInfoChangedOccurred==false no callback");
+ log("listen oscl: mHasNotifySubscriptionInfoChangedOccurred==false no callback");
}
}
}
@@ -432,15 +441,61 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub {
remove(callback.asBinder());
}
+
+ @Override
+ public void addOnOpportunisticSubscriptionsChangedListener(String callingPackage,
+ IOnSubscriptionsChangedListener callback) {
+ int callerUserId = UserHandle.getCallingUserId();
+ mAppOps.checkPackage(Binder.getCallingUid(), callingPackage);
+ if (VDBG) {
+ log("listen ooscl: E pkg=" + callingPackage + " myUserId=" + UserHandle.myUserId()
+ + " callerUserId=" + callerUserId + " callback=" + callback
+ + " callback.asBinder=" + callback.asBinder());
+ }
+
+ synchronized (mRecords) {
+ // register
+ IBinder b = callback.asBinder();
+ Record r = add(b);
+
+ if (r == null) {
+ return;
+ }
+
+ r.context = mContext;
+ r.onOpportunisticSubscriptionsChangedListenerCallback = callback;
+ r.callingPackage = callingPackage;
+ r.callerUid = Binder.getCallingUid();
+ r.callerPid = Binder.getCallingPid();
+ r.events = 0;
+ if (DBG) {
+ log("listen ooscl: Register r=" + r);
+ }
+ // Always notify when registration occurs if there has been a notification.
+ if (mHasNotifyOpportunisticSubscriptionInfoChangedOccurred) {
+ try {
+ if (VDBG) log("listen ooscl: send to r=" + r);
+ r.onOpportunisticSubscriptionsChangedListenerCallback.onSubscriptionsChanged();
+ if (VDBG) log("listen ooscl: sent to r=" + r);
+ } catch (RemoteException e) {
+ if (VDBG) log("listen ooscl: remote exception sending to r=" + r + " e=" + e);
+ remove(r.binder);
+ }
+ } else {
+ log("listen ooscl: hasNotifyOpptSubInfoChangedOccurred==false no callback");
+ }
+ }
+ }
+
@Override
public void notifySubscriptionInfoChanged() {
if (VDBG) log("notifySubscriptionInfoChanged:");
synchronized (mRecords) {
- if (!hasNotifySubscriptionInfoChangedOccurred) {
+ if (!mHasNotifySubscriptionInfoChangedOccurred) {
log("notifySubscriptionInfoChanged: first invocation mRecords.size="
+ mRecords.size());
}
- hasNotifySubscriptionInfoChangedOccurred = true;
+ mHasNotifySubscriptionInfoChangedOccurred = true;
mRemoveList.clear();
for (Record r : mRecords) {
if (r.matchOnSubscriptionsChangedListener()) {
@@ -459,6 +514,33 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub {
}
@Override
+ public void notifyOpportunisticSubscriptionInfoChanged() {
+ if (VDBG) log("notifyOpptSubscriptionInfoChanged:");
+ synchronized (mRecords) {
+ if (!mHasNotifyOpportunisticSubscriptionInfoChangedOccurred) {
+ log("notifyOpptSubscriptionInfoChanged: first invocation mRecords.size="
+ + mRecords.size());
+ }
+ mHasNotifyOpportunisticSubscriptionInfoChangedOccurred = true;
+ mRemoveList.clear();
+ for (Record r : mRecords) {
+ if (r.matchOnOpportunisticSubscriptionsChangedListener()) {
+ try {
+ if (VDBG) log("notifyOpptSubChanged: call oosc to r=" + r);
+ r.onOpportunisticSubscriptionsChangedListenerCallback
+ .onSubscriptionsChanged();
+ if (VDBG) log("notifyOpptSubChanged: done oosc to r=" + r);
+ } catch (RemoteException ex) {
+ if (VDBG) log("notifyOpptSubChanged: RemoteException r=" + r);
+ mRemoveList.add(r.binder);
+ }
+ }
+ }
+ handleRemoveListLocked();
+ }
+ }
+
+ @Override
public void listen(String pkgForDebug, IPhoneStateListener callback, int events,
boolean notifyNow) {
listenForSubscriber(SubscriptionManager.DEFAULT_SUBSCRIPTION_ID, pkgForDebug, callback,
diff --git a/services/core/java/com/android/server/accounts/AccountManagerService.java b/services/core/java/com/android/server/accounts/AccountManagerService.java
index 426a0c157aec..a392b51d5f53 100644
--- a/services/core/java/com/android/server/accounts/AccountManagerService.java
+++ b/services/core/java/com/android/server/accounts/AccountManagerService.java
@@ -1185,8 +1185,8 @@ public class AccountManagerService
final long accountId = accountEntry.getKey();
final Account account = accountEntry.getValue();
if (obsoleteAuthType.contains(account.type)) {
- Slog.w(TAG, "deleting account " + account.name + " because type "
- + account.type
+ Slog.w(TAG, "deleting account " + account.toSafeString()
+ + " because type " + account.type
+ "'s registered authenticator no longer exist.");
Map<String, Integer> packagesToVisibility =
getRequestingPackages(account, accounts);
@@ -1326,7 +1326,8 @@ public class AccountManagerService
Preconditions.checkState(Thread.holdsLock(mUsers), "mUsers lock must be held");
List<Account> accountsToRemove = accounts.accountsDb.findCeAccountsNotInDe();
if (!accountsToRemove.isEmpty()) {
- Slog.i(TAG, "Accounts " + accountsToRemove + " were previously deleted while user "
+ Slog.i(TAG, accountsToRemove.size()
+ + " accounts were previously deleted while user "
+ accounts.userId + " was locked. Removing accounts from CE tables");
logRecord(accounts, AccountsDb.DEBUG_ACTION_SYNC_DE_CE_ACCOUNTS,
AccountsDb.TABLE_ACCOUNTS);
@@ -1641,7 +1642,7 @@ public class AccountManagerService
return;
}
- Slog.d(TAG, "Copying account " + account.name
+ Slog.d(TAG, "Copying account " + account.toSafeString()
+ " from user " + userFrom + " to user " + userTo);
long identityToken = clearCallingIdentity();
try {
@@ -1777,8 +1778,8 @@ public class AccountManagerService
return false;
}
if (!isLocalUnlockedUser(accounts.userId)) {
- Log.w(TAG, "Account " + account + " cannot be added - user " + accounts.userId
- + " is locked. callingUid=" + callingUid);
+ Log.w(TAG, "Account " + account.toSafeString() + " cannot be added - user "
+ + accounts.userId + " is locked. callingUid=" + callingUid);
return false;
}
synchronized (accounts.dbLock) {
@@ -1786,19 +1787,19 @@ public class AccountManagerService
accounts.accountsDb.beginTransaction();
try {
if (accounts.accountsDb.findCeAccountId(account) >= 0) {
- Log.w(TAG, "insertAccountIntoDatabase: " + account
+ Log.w(TAG, "insertAccountIntoDatabase: " + account.toSafeString()
+ ", skipping since the account already exists");
return false;
}
long accountId = accounts.accountsDb.insertCeAccount(account, password);
if (accountId < 0) {
- Log.w(TAG, "insertAccountIntoDatabase: " + account
+ Log.w(TAG, "insertAccountIntoDatabase: " + account.toSafeString()
+ ", skipping the DB insert failed");
return false;
}
// Insert into DE table
if (accounts.accountsDb.insertDeAccount(account, accountId) < 0) {
- Log.w(TAG, "insertAccountIntoDatabase: " + account
+ Log.w(TAG, "insertAccountIntoDatabase: " + account.toSafeString()
+ ", skipping the DB insert failed");
return false;
}
@@ -1806,7 +1807,8 @@ public class AccountManagerService
for (String key : extras.keySet()) {
final String value = extras.getString(key);
if (accounts.accountsDb.insertExtra(accountId, key, value) < 0) {
- Log.w(TAG, "insertAccountIntoDatabase: " + account
+ Log.w(TAG, "insertAccountIntoDatabase: "
+ + account.toSafeString()
+ ", skipping since insertExtra failed for key " + key);
return false;
}
@@ -2282,7 +2284,8 @@ public class AccountManagerService
boolean isChanged = false;
boolean userUnlocked = isLocalUnlockedUser(accounts.userId);
if (!userUnlocked) {
- Slog.i(TAG, "Removing account " + account + " while user "+ accounts.userId
+ Slog.i(TAG, "Removing account " + account.toSafeString()
+ + " while user " + accounts.userId
+ " is still locked. CE data will be removed later");
}
synchronized (accounts.dbLock) {
@@ -2907,7 +2910,7 @@ public class AccountManagerService
protected String toDebugString(long now) {
if (loginOptions != null) loginOptions.keySet();
return super.toDebugString(now) + ", getAuthToken"
- + ", " + account
+ + ", " + account.toSafeString()
+ ", authTokenType " + authTokenType
+ ", loginOptions " + loginOptions
+ ", notifyOnAuthFailure " + notifyOnAuthFailure;
@@ -3669,7 +3672,7 @@ public class AccountManagerService
@Override
protected String toDebugString(long now) {
return super.toDebugString(now) + ", confirmCredentials"
- + ", " + account;
+ + ", " + account.toSafeString();
}
}.bind();
} finally {
@@ -3707,7 +3710,7 @@ public class AccountManagerService
protected String toDebugString(long now) {
if (loginOptions != null) loginOptions.keySet();
return super.toDebugString(now) + ", updateCredentials"
- + ", " + account
+ + ", " + account.toSafeString()
+ ", authTokenType " + authTokenType
+ ", loginOptions " + loginOptions;
}
@@ -3771,7 +3774,7 @@ public class AccountManagerService
loginOptions.keySet();
return super.toDebugString(now)
+ ", startUpdateCredentialsSession"
- + ", " + account
+ + ", " + account.toSafeString()
+ ", authTokenType " + authTokenType
+ ", loginOptions " + loginOptions;
}
@@ -3812,7 +3815,7 @@ public class AccountManagerService
@Override
protected String toDebugString(long now) {
return super.toDebugString(now) + ", isCredentialsUpdateSuggested"
- + ", " + account;
+ + ", " + account.toSafeString();
}
@Override
@@ -4369,7 +4372,7 @@ public class AccountManagerService
accounts.accountsDb.deleteSharedAccount(account);
long accountId = accounts.accountsDb.insertSharedAccount(account);
if (accountId < 0) {
- Log.w(TAG, "insertAccountIntoDatabase: " + account
+ Log.w(TAG, "insertAccountIntoDatabase: " + account.toSafeString()
+ ", skipping the DB insert failed");
return false;
}
@@ -5208,7 +5211,7 @@ public class AccountManagerService
Process.SYSTEM_UID, null /* packageName */, false);
fout.println("Accounts: " + accounts.length);
for (Account account : accounts) {
- fout.println(" " + account);
+ fout.println(" " + account.toSafeString());
}
// Add debug information.
@@ -5296,7 +5299,9 @@ public class AccountManagerService
try {
INotificationManager notificationManager = mInjector.getNotificationManager();
try {
- notificationManager.enqueueNotificationWithTag(packageName, packageName,
+ // The calling uid must match either the package or op package, so use an op
+ // package that matches the cleared calling identity.
+ notificationManager.enqueueNotificationWithTag(packageName, "android",
id.mTag, id.mId, notification, userId);
} catch (RemoteException e) {
/* ignore - local call */
@@ -5611,7 +5616,8 @@ public class AccountManagerService
if (!permissionGranted && ActivityManager.isRunningInTestHarness()) {
// TODO: Skip this check when running automated tests. Replace this
// with a more general solution.
- Log.d(TAG, "no credentials permission for usage of " + account + ", "
+ Log.d(TAG, "no credentials permission for usage of "
+ + account.toSafeString() + ", "
+ authTokenType + " by uid " + callerUid
+ " but ignoring since device is in test harness.");
return true;
diff --git a/services/core/java/com/android/server/am/ActivityDisplay.java b/services/core/java/com/android/server/am/ActivityDisplay.java
index aa5a2e091130..7276222bf19e 100644
--- a/services/core/java/com/android/server/am/ActivityDisplay.java
+++ b/services/core/java/com/android/server/am/ActivityDisplay.java
@@ -39,10 +39,13 @@ import static com.android.server.am.ActivityDisplayProto.RESUMED_ACTIVITY;
import static com.android.server.am.ActivityDisplayProto.STACKS;
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_STACK;
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_STATES;
+import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_TASKS;
import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_STACK;
import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM;
import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NAME;
+import static com.android.server.am.ActivityStackSupervisor.FindTaskResult;
import static com.android.server.am.ActivityStackSupervisor.TAG_STATES;
+import static com.android.server.am.ActivityStackSupervisor.TAG_TASKS;
import android.annotation.Nullable;
import android.app.ActivityOptions;
@@ -121,6 +124,8 @@ class ActivityDisplay extends ConfigurationContainer<ActivityStack>
private DisplayWindowController mWindowContainerController;
+ private final FindTaskResult mTmpFindTaskResult = new FindTaskResult();
+
@VisibleForTesting
ActivityDisplay(ActivityStackSupervisor supervisor, int displayId) {
this(supervisor, supervisor.mDisplayManager.getDisplay(displayId));
@@ -446,6 +451,41 @@ class ActivityDisplay extends ConfigurationContainer<ActivityStack>
}
/**
+ * Find task for putting the Activity in.
+ */
+ void findTaskLocked(final ActivityRecord r, final boolean isPreferredDisplay,
+ FindTaskResult result) {
+ mTmpFindTaskResult.clear();
+ for (int stackNdx = getChildCount() - 1; stackNdx >= 0; --stackNdx) {
+ final ActivityStack stack = getChildAt(stackNdx);
+ if (!r.hasCompatibleActivityType(stack)) {
+ if (DEBUG_TASKS) {
+ Slog.d(TAG_TASKS, "Skipping stack: (mismatch activity/stack) " + stack);
+ }
+ continue;
+ }
+
+ stack.findTaskLocked(r, mTmpFindTaskResult);
+ // It is possible to have tasks in multiple stacks with the same root affinity, so
+ // we should keep looking after finding an affinity match to see if there is a
+ // better match in another stack. Also, task affinity isn't a good enough reason
+ // to target a display which isn't the source of the intent, so skip any affinity
+ // matches not on the specified display.
+ if (mTmpFindTaskResult.mRecord != null) {
+ if (mTmpFindTaskResult.mIdealMatch) {
+ result.setTo(mTmpFindTaskResult);
+ return;
+ } else if (isPreferredDisplay) {
+ // Note: since the traversing through the stacks is top down, the floating
+ // tasks should always have lower priority than any affinity-matching tasks
+ // in the fullscreen stacks
+ result.setTo(mTmpFindTaskResult);
+ }
+ }
+ }
+ }
+
+ /**
* Removes stacks in the input windowing modes from the system if they are of activity type
* ACTIVITY_TYPE_STANDARD or ACTIVITY_TYPE_UNDEFINED
*/
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index e6ff0d8a677a..2ee598fee535 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -4349,6 +4349,7 @@ public class ActivityManagerService extends IActivityManager.Stub
private final void handleAppDiedLocked(ProcessRecord app,
boolean restarting, boolean allowRestart) {
int pid = app.pid;
+ final boolean clearLaunchStartTime = !restarting && app.removed && app.foregroundActivities;
boolean kept = cleanUpApplicationRecordLocked(app, restarting, allowRestart, -1,
false /*replacingPid*/);
if (!kept && !restarting) {
@@ -4388,6 +4389,19 @@ public class ActivityManagerService extends IActivityManager.Stub
} finally {
mWindowManager.continueSurfaceLayout();
}
+
+ // TODO (b/67683350)
+ // When an app process is removed, activities from the process may be relaunched. In the
+ // case of forceStopPackageLocked the activities are finished before any window is drawn,
+ // and the launch time is not cleared. This will be incorrectly used to calculate launch
+ // time for the next launched activity launched in the same windowing mode.
+ if (clearLaunchStartTime) {
+ final LaunchTimeTracker.Entry entry = mStackSupervisor
+ .getLaunchTimeTracker().getEntry(mStackSupervisor.getWindowingMode());
+ if (entry != null) {
+ entry.mLaunchStartTime = 0;
+ }
+ }
}
private final int getLRURecordIndexForAppLocked(IApplicationThread thread) {
diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java
index 355d890f1bd1..bc99827be47e 100644
--- a/services/core/java/com/android/server/am/ActivityStack.java
+++ b/services/core/java/com/android/server/am/ActivityStack.java
@@ -1176,8 +1176,8 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai
//dump();
if (DEBUG_TASKS) Slog.d(TAG_TASKS,
"For Intent " + intent + " bringing to top: " + r.intent);
- result.r = r;
- result.matchedByRootAffinity = false;
+ result.mRecord = r;
+ result.mIdealMatch = true;
break;
} else if (affinityIntent != null && affinityIntent.getComponent() != null &&
affinityIntent.getComponent().compareTo(cls) == 0 &&
@@ -1186,18 +1186,18 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai
//dump();
if (DEBUG_TASKS) Slog.d(TAG_TASKS,
"For Intent " + intent + " bringing to top: " + r.intent);
- result.r = r;
- result.matchedByRootAffinity = false;
+ result.mRecord = r;
+ result.mIdealMatch = true;
break;
} else if (!isDocument && !taskIsDocument
- && result.r == null && task.rootAffinity != null) {
+ && result.mRecord == null && task.rootAffinity != null) {
if (task.rootAffinity.equals(target.taskAffinity)) {
if (DEBUG_TASKS) Slog.d(TAG_TASKS, "Found matching affinity candidate!");
// It is possible for multiple tasks to have the same root affinity especially
// if they are in separate stacks. We save off this candidate, but keep looking
// to see if there is a better candidate.
- result.r = r;
- result.matchedByRootAffinity = true;
+ result.mRecord = r;
+ result.mIdealMatch = false;
}
} else if (DEBUG_TASKS) Slog.d(TAG_TASKS, "Not a match: " + task);
}
diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
index 1ffdc6738c1d..af2d3b0d47fd 100644
--- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
@@ -533,9 +533,20 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D
}
static class FindTaskResult {
- ActivityRecord r;
- boolean matchedByRootAffinity;
+ ActivityRecord mRecord;
+ boolean mIdealMatch;
+
+ void clear() {
+ mRecord = null;
+ mIdealMatch = false;
+ }
+
+ void setTo(FindTaskResult result) {
+ mRecord = result.mRecord;
+ mIdealMatch = result.mIdealMatch;
+ }
}
+
private final FindTaskResult mTmpFindTaskResult = new FindTaskResult();
/**
@@ -3459,44 +3470,33 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D
return true;
}
- ActivityRecord findTaskLocked(ActivityRecord r, int displayId) {
- mTmpFindTaskResult.r = null;
- mTmpFindTaskResult.matchedByRootAffinity = false;
- ActivityRecord affinityMatch = null;
+ ActivityRecord findTaskLocked(ActivityRecord r, int preferredDisplayId) {
if (DEBUG_TASKS) Slog.d(TAG_TASKS, "Looking for task of " + r);
+ mTmpFindTaskResult.clear();
+
+ // Looking up task on preferred display first
+ final ActivityDisplay preferredDisplay = getActivityDisplay(preferredDisplayId);
+ if (preferredDisplay != null) {
+ preferredDisplay.findTaskLocked(r, true /* isPreferredDisplay */, mTmpFindTaskResult);
+ if (mTmpFindTaskResult.mIdealMatch) {
+ return mTmpFindTaskResult.mRecord;
+ }
+ }
+
for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) {
final ActivityDisplay display = mActivityDisplays.get(displayNdx);
- for (int stackNdx = display.getChildCount() - 1; stackNdx >= 0; --stackNdx) {
- final ActivityStack stack = display.getChildAt(stackNdx);
- if (!r.hasCompatibleActivityType(stack)) {
- if (DEBUG_TASKS) Slog.d(TAG_TASKS, "Skipping stack: (mismatch activity/stack) "
- + stack);
- continue;
- }
- stack.findTaskLocked(r, mTmpFindTaskResult);
- // It is possible to have tasks in multiple stacks with the same root affinity, so
- // we should keep looking after finding an affinity match to see if there is a
- // better match in another stack. Also, task affinity isn't a good enough reason
- // to target a display which isn't the source of the intent, so skip any affinity
- // matches not on the specified display.
- if (mTmpFindTaskResult.r != null) {
- if (!mTmpFindTaskResult.matchedByRootAffinity) {
- return mTmpFindTaskResult.r;
- } else if (mTmpFindTaskResult.r.getDisplayId() == displayId) {
- // Note: since the traversing through the stacks is top down, the floating
- // tasks should always have lower priority than any affinity-matching tasks
- // in the fullscreen stacks
- affinityMatch = mTmpFindTaskResult.r;
- } else if (DEBUG_TASKS && mTmpFindTaskResult.matchedByRootAffinity) {
- Slog.d(TAG_TASKS, "Skipping match on different display "
- + mTmpFindTaskResult.r.getDisplayId() + " " + displayId);
- }
- }
+ if (display.mDisplayId == preferredDisplayId) {
+ continue;
+ }
+
+ display.findTaskLocked(r, false /* isPreferredDisplay */, mTmpFindTaskResult);
+ if (mTmpFindTaskResult.mIdealMatch) {
+ return mTmpFindTaskResult.mRecord;
}
}
- if (DEBUG_TASKS && affinityMatch == null) Slog.d(TAG_TASKS, "No task found");
- return affinityMatch;
+ if (DEBUG_TASKS && mTmpFindTaskResult.mRecord == null) Slog.d(TAG_TASKS, "No task found");
+ return mTmpFindTaskResult.mRecord;
}
ActivityRecord findActivityLocked(Intent intent, ActivityInfo info,
diff --git a/services/core/java/com/android/server/am/TEST_MAPPING b/services/core/java/com/android/server/am/TEST_MAPPING
index 4ca96a1904db..b817669ce70c 100644
--- a/services/core/java/com/android/server/am/TEST_MAPPING
+++ b/services/core/java/com/android/server/am/TEST_MAPPING
@@ -49,6 +49,20 @@
"exclude-annotation": "androidx.test.filters.FlakyTest"
}
]
+ },
+ {
+ "name": "WmTests",
+ "options": [
+ {
+ "include-filter": "com.android.server.am."
+ },
+ {
+ "include-annotation": "android.platform.test.annotations.Presubmit"
+ },
+ {
+ "exclude-annotation": "androidx.test.filters.FlakyTest"
+ }
+ ]
}
],
"postsubmit": [
@@ -65,6 +79,14 @@
"include-filter": "com.android.server.am."
}
]
+ },
+ {
+ "name": "WmTests",
+ "options": [
+ {
+ "include-filter": "com.android.server.am."
+ }
+ ]
}
]
}
diff --git a/services/core/java/com/android/server/biometrics/face/FaceService.java b/services/core/java/com/android/server/biometrics/face/FaceService.java
index f211e1716d13..8afac97f647f 100644
--- a/services/core/java/com/android/server/biometrics/face/FaceService.java
+++ b/services/core/java/com/android/server/biometrics/face/FaceService.java
@@ -574,7 +574,8 @@ public class FaceService extends BiometricService {
for (int i = 0; i < cryptoToken.length; i++) {
token.add(cryptoToken[i]);
}
- return daemon.enroll(token, timeout);
+ // TODO: plumb requireAttention down from framework
+ return daemon.enroll(token, timeout, true /* requireAttention */);
}
};
@@ -757,7 +758,7 @@ public class FaceService extends BiometricService {
return 0;
}
try {
- return daemon.preEnroll().value;
+ return daemon.generateChallenge().value;
} catch (RemoteException e) {
Slog.e(TAG, "startPreEnroll failed", e);
}
@@ -771,7 +772,7 @@ public class FaceService extends BiometricService {
return 0;
}
try {
- return daemon.postEnroll();
+ return daemon.revokeChallenge();
} catch (RemoteException e) {
Slog.e(TAG, "startPostEnroll failed", e);
}
diff --git a/services/core/java/com/android/server/clipboard/ClipboardService.java b/services/core/java/com/android/server/clipboard/ClipboardService.java
index c80c0f12dcdc..c028a4305fd7 100644
--- a/services/core/java/com/android/server/clipboard/ClipboardService.java
+++ b/services/core/java/com/android/server/clipboard/ClipboardService.java
@@ -26,6 +26,7 @@ import android.app.KeyguardManager;
import android.app.UriGrantsManager;
import android.content.ClipData;
import android.content.ClipDescription;
+import android.content.ComponentName;
import android.content.ContentProvider;
import android.content.ContentResolver;
import android.content.Context;
@@ -48,6 +49,7 @@ import android.os.SystemProperties;
import android.os.UserHandle;
import android.os.UserManager;
import android.provider.Settings;
+import android.text.TextUtils;
import android.util.Slog;
import android.util.SparseArray;
@@ -630,8 +632,11 @@ public class ClipboardService extends SystemService {
// The default IME is always allowed to access the clipboard.
String defaultIme = Settings.Secure.getStringForUser(getContext().getContentResolver(),
Settings.Secure.DEFAULT_INPUT_METHOD, UserHandle.getUserId(callingUid));
- if (defaultIme != null && defaultIme.equals(callingPackage)) {
- return true;
+ if (!TextUtils.isEmpty(defaultIme)) {
+ final String imePkg = ComponentName.unflattenFromString(defaultIme).getPackageName();
+ if (imePkg.equals(callingPackage)) {
+ return true;
+ }
}
// Otherwise only focused applications can access the clipboard.
diff --git a/services/core/java/com/android/server/job/JobSchedulerService.java b/services/core/java/com/android/server/job/JobSchedulerService.java
index 260633ac4feb..389782a91d06 100644
--- a/services/core/java/com/android/server/job/JobSchedulerService.java
+++ b/services/core/java/com/android/server/job/JobSchedulerService.java
@@ -2413,6 +2413,8 @@ public class JobSchedulerService extends com.android.server.SystemService
BatteryStatsInternal mBatteryStatsInternal = LocalServices.getService
(BatteryStatsInternal.class);
mBatteryStatsInternal.noteJobsDeferred(uid, counter.numDeferred(), sinceLast);
+ StatsLog.write_non_chained(StatsLog.DEFERRED_JOB_STATS_REPORTED, uid, null,
+ counter.numDeferred(), sinceLast);
}
}
}
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index ce71dd2ec9ad..03b7652e32ec 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -35,6 +35,8 @@ import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_SCREEN_ON
import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_STATUS_BAR;
import static android.content.pm.PackageManager.FEATURE_LEANBACK;
import static android.content.pm.PackageManager.FEATURE_TELEVISION;
+import static android.content.pm.PackageManager.MATCH_DIRECT_BOOT_AWARE;
+import static android.content.pm.PackageManager.MATCH_DIRECT_BOOT_UNAWARE;
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
import static android.os.IServiceManager.DUMP_FLAG_PRIORITY_CRITICAL;
import static android.os.IServiceManager.DUMP_FLAG_PRIORITY_NORMAL;
@@ -203,6 +205,7 @@ import com.android.server.lights.Light;
import com.android.server.lights.LightsManager;
import com.android.server.notification.ManagedServices.ManagedServiceInfo;
import com.android.server.notification.ManagedServices.UserProfiles;
+import com.android.server.pm.PackageManagerService;
import com.android.server.policy.PhoneWindowManager;
import com.android.server.statusbar.StatusBarManagerInternal;
import com.android.server.uri.UriGrantsManagerInternal;
@@ -470,8 +473,8 @@ public class NotificationManagerService extends SystemService {
// Gather all notification listener components for candidate pkgs.
Set<ComponentName> approvedListeners =
mListeners.queryPackageForServices(whitelisted,
- PackageManager.MATCH_DIRECT_BOOT_AWARE
- | PackageManager.MATCH_DIRECT_BOOT_UNAWARE, userId);
+ MATCH_DIRECT_BOOT_AWARE
+ | MATCH_DIRECT_BOOT_UNAWARE, userId);
for (ComponentName cn : approvedListeners) {
try {
getBinderService().setNotificationListenerAccessGrantedForUser(cn,
@@ -507,8 +510,8 @@ public class NotificationManagerService extends SystemService {
// only be one
Set<ComponentName> approvedAssistants =
mAssistants.queryPackageForServices(defaultAssistantAccess,
- PackageManager.MATCH_DIRECT_BOOT_AWARE
- | PackageManager.MATCH_DIRECT_BOOT_UNAWARE, userId);
+ MATCH_DIRECT_BOOT_AWARE
+ | MATCH_DIRECT_BOOT_UNAWARE, userId);
for (ComponentName cn : approvedAssistants) {
try {
getBinderService().setNotificationAssistantAccessGrantedForUser(
@@ -1377,7 +1380,7 @@ public class NotificationManagerService extends SystemService {
NotificationUsageStats usageStats, AtomicFile policyFile,
ActivityManager activityManager, GroupHelper groupHelper, IActivityManager am,
UsageStatsManagerInternal appUsageStats, DevicePolicyManagerInternal dpm,
- IUriGrantsManager ugm, UriGrantsManagerInternal ugmInternal) {
+ IUriGrantsManager ugm, UriGrantsManagerInternal ugmInternal, AppOpsManager appOps) {
Resources resources = getContext().getResources();
mMaxPackageEnqueueRate = Settings.Global.getFloat(getContext().getContentResolver(),
Settings.Global.MAX_NOTIFICATION_ENQUEUE_RATE,
@@ -1390,7 +1393,7 @@ public class NotificationManagerService extends SystemService {
mUgmInternal = ugmInternal;
mPackageManager = packageManager;
mPackageManagerClient = packageManagerClient;
- mAppOps = (AppOpsManager) getContext().getSystemService(Context.APP_OPS_SERVICE);
+ mAppOps = appOps;
mVibrator = (Vibrator) getContext().getSystemService(Context.VIBRATOR_SERVICE);
mAppUsageStats = appUsageStats;
mAlarmManager = (AlarmManager) getContext().getSystemService(Context.ALARM_SERVICE);
@@ -1544,7 +1547,8 @@ public class NotificationManagerService extends SystemService {
LocalServices.getService(UsageStatsManagerInternal.class),
LocalServices.getService(DevicePolicyManagerInternal.class),
UriGrantsManager.getService(),
- LocalServices.getService(UriGrantsManagerInternal.class));
+ LocalServices.getService(UriGrantsManagerInternal.class),
+ (AppOpsManager) getContext().getSystemService(Context.APP_OPS_SERVICE));
// register for various Intents
IntentFilter filter = new IntentFilter();
@@ -2234,6 +2238,60 @@ public class NotificationManagerService extends SystemService {
}
@Override
+ public void setNotificationDelegate(String callingPkg, String delegate) {
+ checkCallerIsSameApp(callingPkg);
+ final int callingUid = Binder.getCallingUid();
+ UserHandle user = UserHandle.getUserHandleForUid(callingUid);
+ try {
+ ApplicationInfo info =
+ mPackageManager.getApplicationInfo(delegate,
+ MATCH_DIRECT_BOOT_AWARE | MATCH_DIRECT_BOOT_UNAWARE,
+ user.getIdentifier());
+ if (info != null) {
+ mPreferencesHelper.setNotificationDelegate(
+ callingPkg, callingUid, delegate, info.uid);
+ savePolicyFile();
+ }
+ } catch (RemoteException e) {
+ // :(
+ }
+ }
+
+ @Override
+ public void revokeNotificationDelegate(String callingPkg) {
+ checkCallerIsSameApp(callingPkg);
+ mPreferencesHelper.revokeNotificationDelegate(callingPkg, Binder.getCallingUid());
+ savePolicyFile();
+ }
+
+ @Override
+ public String getNotificationDelegate(String callingPkg) {
+ // callable by Settings also
+ checkCallerIsSystemOrSameApp(callingPkg);
+ return mPreferencesHelper.getNotificationDelegate(callingPkg, Binder.getCallingUid());
+ }
+
+ @Override
+ public boolean canNotifyAsPackage(String callingPkg, String targetPkg) {
+ checkCallerIsSameApp(callingPkg);
+ final int callingUid = Binder.getCallingUid();
+ UserHandle user = UserHandle.getUserHandleForUid(callingUid);
+ try {
+ ApplicationInfo info =
+ mPackageManager.getApplicationInfo(targetPkg,
+ MATCH_DIRECT_BOOT_AWARE | MATCH_DIRECT_BOOT_UNAWARE,
+ user.getIdentifier());
+ if (info != null) {
+ return mPreferencesHelper.isDelegateAllowed(
+ targetPkg, info.uid, callingPkg, callingUid);
+ }
+ } catch (RemoteException e) {
+ // :(
+ }
+ return false;
+ }
+
+ @Override
public void updateNotificationChannelGroupForPackage(String pkg, int uid,
NotificationChannelGroup group) throws RemoteException {
enforceSystemOrSystemUI("Caller not system or systemui");
@@ -4053,20 +4111,21 @@ public class NotificationManagerService extends SystemService {
Slog.v(TAG, "enqueueNotificationInternal: pkg=" + pkg + " id=" + id
+ " notification=" + notification);
}
- checkCallerIsSystemOrSameApp(pkg);
- checkRestrictedCategories(notification);
-
- final int userId = ActivityManager.handleIncomingUser(callingPid,
- callingUid, incomingUserId, true, false, "enqueueNotification", pkg);
- final UserHandle user = new UserHandle(userId);
if (pkg == null || notification == null) {
throw new IllegalArgumentException("null not allowed: pkg=" + pkg
+ " id=" + id + " notification=" + notification);
}
- // The system can post notifications for any package, let us resolve that.
- final int notificationUid = resolveNotificationUid(opPkg, callingUid, userId);
+ final int userId = ActivityManager.handleIncomingUser(callingPid,
+ callingUid, incomingUserId, true, false, "enqueueNotification", pkg);
+ final UserHandle user = UserHandle.of(userId);
+
+ // Can throw a SecurityException if the calling uid doesn't have permission to post
+ // as "pkg"
+ final int notificationUid = resolveNotificationUid(opPkg, pkg, callingUid, userId);
+
+ checkRestrictedCategories(notification);
// Fix the notification as best we can.
try {
@@ -4193,17 +4252,28 @@ public class NotificationManagerService extends SystemService {
}
}
- private int resolveNotificationUid(String opPackageName, int callingUid, int userId) {
- // The system can post notifications on behalf of any package it wants
- if (isCallerSystemOrPhone() && opPackageName != null && !"android".equals(opPackageName)) {
- try {
- return getContext().getPackageManager()
- .getPackageUidAsUser(opPackageName, userId);
- } catch (NameNotFoundException e) {
- /* ignore */
- }
+ @VisibleForTesting
+ int resolveNotificationUid(String callingPkg, String targetPkg,
+ int callingUid, int userId) {
+ // posted from app A on behalf of app A
+ if (isCallerSameApp(targetPkg, callingUid) && TextUtils.equals(callingPkg, targetPkg)) {
+ return callingUid;
+ }
+
+ int targetUid = -1;
+ try {
+ targetUid = mPackageManagerClient.getPackageUidAsUser(targetPkg, userId);
+ } catch (NameNotFoundException e) {
+ /* ignore */
+ }
+ // posted from app A on behalf of app B
+ if (targetUid != -1 && (isCallerAndroid(callingPkg, callingUid)
+ || mPreferencesHelper.isDelegateAllowed(
+ targetPkg, targetUid, callingPkg, callingUid))) {
+ return targetUid;
}
- return callingUid;
+
+ throw new SecurityException("Caller " + callingUid + " cannot post for pkg " + targetPkg);
}
/**
@@ -4222,7 +4292,8 @@ public class NotificationManagerService extends SystemService {
// package or a registered listener can enqueue. Prevents DOS attacks and deals with leaks.
if (!isSystemNotification && !isNotificationFromListener) {
synchronized (mNotificationLock) {
- if (mNotificationsByKey.get(r.sbn.getKey()) == null && isCallerInstantApp(pkg)) {
+ if (mNotificationsByKey.get(r.sbn.getKey()) == null
+ && isCallerInstantApp(pkg, callingUid)) {
// Ephemeral apps have some special constraints for notifications.
// They are not allowed to create new notifications however they are allowed to
// update notifications created by the system (e.g. a foreground service
@@ -5149,11 +5220,11 @@ public class NotificationManagerService extends SystemService {
try {
Thread.sleep(waitMs);
} catch (InterruptedException e) { }
- mVibrator.vibrate(record.sbn.getUid(), record.sbn.getOpPkg(),
+ mVibrator.vibrate(record.sbn.getUid(), record.sbn.getPackageName(),
effect, "Notification (delayed)", record.getAudioAttributes());
}).start();
} else {
- mVibrator.vibrate(record.sbn.getUid(), record.sbn.getOpPkg(),
+ mVibrator.vibrate(record.sbn.getUid(), record.sbn.getPackageName(),
effect, "Notification", record.getAudioAttributes());
}
return true;
@@ -6282,6 +6353,11 @@ public class NotificationManagerService extends SystemService {
checkCallerIsSameApp(pkg);
}
+ private boolean isCallerAndroid(String callingPkg, int uid) {
+ return isUidSystemOrPhone(uid) && callingPkg != null
+ && PackageManagerService.PLATFORM_PACKAGE_NAME.equals(callingPkg);
+ }
+
/**
* Check if the notification is of a category type that is restricted to system use only,
* if so throw SecurityException
@@ -6302,13 +6378,13 @@ public class NotificationManagerService extends SystemService {
}
}
- private boolean isCallerInstantApp(String pkg) {
+ private boolean isCallerInstantApp(String pkg, int callingUid) {
// System is always allowed to act for ephemeral apps.
- if (isCallerSystemOrPhone()) {
+ if (isUidSystemOrPhone(callingUid)) {
return false;
}
- mAppOps.checkPackage(Binder.getCallingUid(), pkg);
+ mAppOps.checkPackage(callingUid, pkg);
try {
ApplicationInfo ai = mPackageManager.getApplicationInfo(pkg, 0,
@@ -6324,7 +6400,10 @@ public class NotificationManagerService extends SystemService {
}
private void checkCallerIsSameApp(String pkg) {
- final int uid = Binder.getCallingUid();
+ checkCallerIsSameApp(pkg, Binder.getCallingUid());
+ }
+
+ private void checkCallerIsSameApp(String pkg, int uid) {
try {
ApplicationInfo ai = mPackageManager.getApplicationInfo(
pkg, 0, UserHandle.getCallingUserId());
@@ -6340,6 +6419,24 @@ public class NotificationManagerService extends SystemService {
}
}
+ private boolean isCallerSameApp(String pkg) {
+ try {
+ checkCallerIsSameApp(pkg);
+ return true;
+ } catch (SecurityException e) {
+ return false;
+ }
+ }
+
+ private boolean isCallerSameApp(String pkg, int uid) {
+ try {
+ checkCallerIsSameApp(pkg, uid);
+ return true;
+ } catch (SecurityException e) {
+ return false;
+ }
+ }
+
private static String callStateToString(int state) {
switch (state) {
case TelephonyManager.CALL_STATE_IDLE: return "CALL_STATE_IDLE";
diff --git a/services/core/java/com/android/server/notification/PreferencesHelper.java b/services/core/java/com/android/server/notification/PreferencesHelper.java
index 432d17c821f2..593e7cdf4d66 100644
--- a/services/core/java/com/android/server/notification/PreferencesHelper.java
+++ b/services/core/java/com/android/server/notification/PreferencesHelper.java
@@ -20,6 +20,7 @@ import static android.app.NotificationManager.IMPORTANCE_NONE;
import android.annotation.IntDef;
import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.app.Notification;
import android.app.NotificationChannel;
import android.app.NotificationChannelGroup;
@@ -66,12 +67,14 @@ import java.util.concurrent.ConcurrentHashMap;
public class PreferencesHelper implements RankingConfig {
private static final String TAG = "NotificationPrefHelper";
private static final int XML_VERSION = 1;
+ private static final int UNKNOWN_UID = UserHandle.USER_NULL;
@VisibleForTesting
static final String TAG_RANKING = "ranking";
private static final String TAG_PACKAGE = "package";
private static final String TAG_CHANNEL = "channel";
private static final String TAG_GROUP = "channelGroup";
+ private static final String TAG_DELEGATE = "delegate";
private static final String ATT_VERSION = "version";
private static final String ATT_NAME = "name";
@@ -82,6 +85,8 @@ public class PreferencesHelper implements RankingConfig {
private static final String ATT_IMPORTANCE = "importance";
private static final String ATT_SHOW_BADGE = "show_badge";
private static final String ATT_APP_USER_LOCKED_FIELDS = "app_user_locked_fields";
+ private static final String ATT_ENABLED = "enabled";
+ private static final String ATT_USER_ALLOWED = "allowed";
private static final int DEFAULT_PRIORITY = Notification.PRIORITY_DEFAULT;
private static final int DEFAULT_VISIBILITY = NotificationManager.VISIBILITY_NO_OVERRIDE;
@@ -147,8 +152,7 @@ public class PreferencesHelper implements RankingConfig {
}
if (type == XmlPullParser.START_TAG) {
if (TAG_PACKAGE.equals(tag)) {
- int uid = XmlUtils.readIntAttribute(parser, ATT_UID,
- PackagePreferences.UNKNOWN_UID);
+ int uid = XmlUtils.readIntAttribute(parser, ATT_UID, UNKNOWN_UID);
String name = parser.getAttributeValue(null, ATT_NAME);
if (!TextUtils.isEmpty(name)) {
if (forRestore) {
@@ -217,6 +221,24 @@ public class PreferencesHelper implements RankingConfig {
r.channels.put(id, channel);
}
}
+ // Delegate
+ if (TAG_DELEGATE.equals(tagName)) {
+ int delegateId =
+ XmlUtils.readIntAttribute(parser, ATT_UID, UNKNOWN_UID);
+ String delegateName =
+ XmlUtils.readStringAttribute(parser, ATT_NAME);
+ boolean delegateEnabled = XmlUtils.readBooleanAttribute(
+ parser, ATT_ENABLED, Delegate.DEFAULT_ENABLED);
+ boolean userAllowed = XmlUtils.readBooleanAttribute(
+ parser, ATT_USER_ALLOWED, Delegate.DEFAULT_USER_ALLOWED);
+ Delegate d = null;
+ if (delegateId != UNKNOWN_UID && !TextUtils.isEmpty(delegateName)) {
+ d = new Delegate(
+ delegateName, delegateId, delegateEnabled, userAllowed);
+ }
+ r.delegate = d;
+ }
+
}
try {
@@ -248,7 +270,7 @@ public class PreferencesHelper implements RankingConfig {
final String key = packagePreferencesKey(pkg, uid);
synchronized (mPackagePreferencess) {
PackagePreferences
- r = (uid == PackagePreferences.UNKNOWN_UID) ? mRestoredWithoutUids.get(pkg)
+ r = (uid == UNKNOWN_UID) ? mRestoredWithoutUids.get(pkg)
: mPackagePreferencess.get(key);
if (r == null) {
r = new PackagePreferences();
@@ -265,7 +287,7 @@ public class PreferencesHelper implements RankingConfig {
Slog.e(TAG, "createDefaultChannelIfNeeded - Exception: " + e);
}
- if (r.uid == PackagePreferences.UNKNOWN_UID) {
+ if (r.uid == UNKNOWN_UID) {
mRestoredWithoutUids.put(pkg, r);
} else {
mPackagePreferencess.put(key, r);
@@ -357,7 +379,8 @@ public class PreferencesHelper implements RankingConfig {
|| r.showBadge != DEFAULT_SHOW_BADGE
|| r.lockedAppFields != DEFAULT_LOCKED_APP_FIELDS
|| r.channels.size() > 0
- || r.groups.size() > 0;
+ || r.groups.size() > 0
+ || r.delegate != null;
if (hasNonDefaultSettings) {
out.startTag(null, TAG_PACKAGE);
out.attribute(null, ATT_NAME, r.pkg);
@@ -378,6 +401,21 @@ public class PreferencesHelper implements RankingConfig {
out.attribute(null, ATT_UID, Integer.toString(r.uid));
}
+ if (r.delegate != null) {
+ out.startTag(null, TAG_DELEGATE);
+
+ out.attribute(null, ATT_NAME, r.delegate.mPkg);
+ out.attribute(null, ATT_UID, Integer.toString(r.delegate.mUid));
+ if (r.delegate.mEnabled != Delegate.DEFAULT_ENABLED) {
+ out.attribute(null, ATT_ENABLED, Boolean.toString(r.delegate.mEnabled));
+ }
+ if (r.delegate.mUserAllowed != Delegate.DEFAULT_USER_ALLOWED) {
+ out.attribute(null, ATT_USER_ALLOWED,
+ Boolean.toString(r.delegate.mUserAllowed));
+ }
+ out.endTag(null, TAG_DELEGATE);
+ }
+
for (NotificationChannelGroup group : r.groups.values()) {
group.writeXml(out);
}
@@ -923,16 +961,76 @@ public class PreferencesHelper implements RankingConfig {
* considered for sentiment adjustments (and thus never show a blocking helper).
*/
public void setAppImportanceLocked(String packageName, int uid) {
- PackagePreferences PackagePreferences = getOrCreatePackagePreferences(packageName, uid);
- if ((PackagePreferences.lockedAppFields & LockableAppFields.USER_LOCKED_IMPORTANCE) != 0) {
+ PackagePreferences prefs = getOrCreatePackagePreferences(packageName, uid);
+ if ((prefs.lockedAppFields & LockableAppFields.USER_LOCKED_IMPORTANCE) != 0) {
return;
}
- PackagePreferences.lockedAppFields =
- PackagePreferences.lockedAppFields | LockableAppFields.USER_LOCKED_IMPORTANCE;
+ prefs.lockedAppFields = prefs.lockedAppFields | LockableAppFields.USER_LOCKED_IMPORTANCE;
updateConfig();
}
+ /**
+ * Returns the delegate for a given package, if it's allowed by the package and the user.
+ */
+ public @Nullable String getNotificationDelegate(String sourcePkg, int sourceUid) {
+ PackagePreferences prefs = getPackagePreferences(sourcePkg, sourceUid);
+
+ if (prefs == null || prefs.delegate == null) {
+ return null;
+ }
+ if (!prefs.delegate.mUserAllowed || !prefs.delegate.mEnabled) {
+ return null;
+ }
+ return prefs.delegate.mPkg;
+ }
+
+ /**
+ * Used by an app to delegate notification posting privileges to another apps.
+ */
+ public void setNotificationDelegate(String sourcePkg, int sourceUid,
+ String delegatePkg, int delegateUid) {
+ PackagePreferences prefs = getOrCreatePackagePreferences(sourcePkg, sourceUid);
+
+ boolean userAllowed = prefs.delegate == null || prefs.delegate.mUserAllowed;
+ Delegate delegate = new Delegate(delegatePkg, delegateUid, true, userAllowed);
+ prefs.delegate = delegate;
+ updateConfig();
+ }
+
+ /**
+ * Used by an app to turn off its notification delegate.
+ */
+ public void revokeNotificationDelegate(String sourcePkg, int sourceUid) {
+ PackagePreferences prefs = getPackagePreferences(sourcePkg, sourceUid);
+ if (prefs != null && prefs.delegate != null) {
+ prefs.delegate.mEnabled = false;
+ updateConfig();
+ }
+ }
+
+ /**
+ * Toggles whether an app can have a notification delegate on behalf of a user.
+ */
+ public void toggleNotificationDelegate(String sourcePkg, int sourceUid, boolean userAllowed) {
+ PackagePreferences prefs = getPackagePreferences(sourcePkg, sourceUid);
+ if (prefs != null && prefs.delegate != null) {
+ prefs.delegate.mUserAllowed = userAllowed;
+ updateConfig();
+ }
+ }
+
+ /**
+ * Returns whether the given app is allowed on post notifications on behalf of the other given
+ * app.
+ */
+ public boolean isDelegateAllowed(String sourcePkg, int sourceUid,
+ String potentialDelegatePkg, int potentialDelegateUid) {
+ PackagePreferences prefs = getPackagePreferences(sourcePkg, sourceUid);
+
+ return prefs != null && prefs.isValidDelegate(potentialDelegatePkg, potentialDelegateUid);
+ }
+
@VisibleForTesting
void lockFieldsForUpdate(NotificationChannel original, NotificationChannel update) {
if (original.canBypassDnd() != update.canBypassDnd()) {
@@ -994,8 +1092,7 @@ public class PreferencesHelper implements RankingConfig {
pw.print(" AppSettings: ");
pw.print(r.pkg);
pw.print(" (");
- pw.print(r.uid == PackagePreferences.UNKNOWN_UID ? "UNKNOWN_UID"
- : Integer.toString(r.uid));
+ pw.print(r.uid == UNKNOWN_UID ? "UNKNOWN_UID" : Integer.toString(r.uid));
pw.print(')');
if (r.importance != DEFAULT_IMPORTANCE) {
pw.print(" importance=");
@@ -1356,8 +1453,6 @@ public class PreferencesHelper implements RankingConfig {
}
private static class PackagePreferences {
- static int UNKNOWN_UID = UserHandle.USER_NULL;
-
String pkg;
int uid = UNKNOWN_UID;
int importance = DEFAULT_IMPORTANCE;
@@ -1366,7 +1461,37 @@ public class PreferencesHelper implements RankingConfig {
boolean showBadge = DEFAULT_SHOW_BADGE;
int lockedAppFields = DEFAULT_LOCKED_APP_FIELDS;
+ Delegate delegate = null;
ArrayMap<String, NotificationChannel> channels = new ArrayMap<>();
Map<String, NotificationChannelGroup> groups = new ConcurrentHashMap<>();
+
+ public boolean isValidDelegate(String pkg, int uid) {
+ return delegate != null && delegate.isAllowed(pkg, uid);
+ }
+ }
+
+ private static class Delegate {
+ static final boolean DEFAULT_ENABLED = true;
+ static final boolean DEFAULT_USER_ALLOWED = true;
+ String mPkg;
+ int mUid = UNKNOWN_UID;
+ boolean mEnabled = DEFAULT_ENABLED;
+ boolean mUserAllowed = DEFAULT_USER_ALLOWED;
+
+ Delegate(String pkg, int uid, boolean enabled, boolean userAllowed) {
+ mPkg = pkg;
+ mUid = uid;
+ mEnabled = enabled;
+ mUserAllowed = userAllowed;
+ }
+
+ public boolean isAllowed(String pkg, int uid) {
+ if (pkg == null || uid == UNKNOWN_UID) {
+ return false;
+ }
+ return pkg.equals(mPkg)
+ && uid == mUid
+ && (mUserAllowed && mEnabled);
+ }
}
}
diff --git a/services/core/java/com/android/server/pm/OtaDexoptService.java b/services/core/java/com/android/server/pm/OtaDexoptService.java
index cf47d4e6af87..bca3ca71a911 100644
--- a/services/core/java/com/android/server/pm/OtaDexoptService.java
+++ b/services/core/java/com/android/server/pm/OtaDexoptService.java
@@ -40,6 +40,7 @@ import java.io.File;
import java.io.FileDescriptor;
import java.util.ArrayList;
import java.util.Collection;
+import java.util.Collections;
import java.util.List;
import java.util.concurrent.TimeUnit;
@@ -124,7 +125,8 @@ public class OtaDexoptService extends IOtaDexopt.Stub {
synchronized (mPackageManagerService.mPackages) {
// Important: the packages we need to run with ab-ota compiler-reason.
important = PackageManagerServiceUtils.getPackagesForDexopt(
- mPackageManagerService.mPackages.values(), mPackageManagerService);
+ mPackageManagerService.mPackages.values(), mPackageManagerService,
+ DEBUG_DEXOPT);
// Others: we should optimize this with the (first-)boot compiler-reason.
others = new ArrayList<>(mPackageManagerService.mPackages.values());
others.removeAll(important);
@@ -157,6 +159,24 @@ public class OtaDexoptService extends IOtaDexopt.Stub {
long spaceAvailableNow = getAvailableSpace();
prepareMetricsLogging(important.size(), others.size(), spaceAvailable, spaceAvailableNow);
+
+ if (DEBUG_DEXOPT) {
+ try {
+ // Output some data about the packages.
+ PackageParser.Package lastUsed = Collections.max(important,
+ (pkg1, pkg2) -> Long.compare(
+ pkg1.getLatestForegroundPackageUseTimeInMills(),
+ pkg2.getLatestForegroundPackageUseTimeInMills()));
+ Log.d(TAG, "A/B OTA: lastUsed time = "
+ + lastUsed.getLatestForegroundPackageUseTimeInMills());
+ Log.d(TAG, "A/B OTA: deprioritized packages:");
+ for (PackageParser.Package pkg : others) {
+ Log.d(TAG, " " + pkg.packageName + " - "
+ + pkg.getLatestForegroundPackageUseTimeInMills());
+ }
+ } catch (Exception ignored) {
+ }
+ }
}
@Override
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 07f3e176fc93..cacdccb2dc4e 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -8579,7 +8579,7 @@ public class PackageManagerService extends IPackageManager.Stub
* Traces a package scan.
* @see #scanPackageLI(File, int, int, long, UserHandle)
*/
- @GuardedBy("mInstallLock")
+ @GuardedBy({"mInstallLock", "mPackages"})
private PackageParser.Package scanPackageTracedLI(File scanFile, final int parseFlags,
int scanFlags, long currentTime, UserHandle user) throws PackageManagerException {
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "scanPackage [" + scanFile.toString() + "]");
diff --git a/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java b/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java
index 1aea8f0b0543..390c0ccb3c6e 100644
--- a/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java
+++ b/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java
@@ -164,6 +164,13 @@ public class PackageManagerServiceUtils {
public static List<PackageParser.Package> getPackagesForDexopt(
Collection<PackageParser.Package> packages,
PackageManagerService packageManagerService) {
+ return getPackagesForDexopt(packages, packageManagerService, DEBUG_DEXOPT);
+ }
+
+ public static List<PackageParser.Package> getPackagesForDexopt(
+ Collection<PackageParser.Package> packages,
+ PackageManagerService packageManagerService,
+ boolean debug) {
ArrayList<PackageParser.Package> remainingPkgs = new ArrayList<>(packages);
LinkedList<PackageParser.Package> result = new LinkedList<>();
ArrayList<PackageParser.Package> sortTemp = new ArrayList<>(remainingPkgs.size());
@@ -189,14 +196,14 @@ public class PackageManagerServiceUtils {
// TODO: add a property to control this?
Predicate<PackageParser.Package> remainingPredicate;
if (!remainingPkgs.isEmpty() && packageManagerService.isHistoricalPackageUsageAvailable()) {
- if (DEBUG_DEXOPT) {
+ if (debug) {
Log.i(TAG, "Looking at historical package use");
}
// Get the package that was used last.
PackageParser.Package lastUsed = Collections.max(remainingPkgs, (pkg1, pkg2) ->
Long.compare(pkg1.getLatestForegroundPackageUseTimeInMills(),
pkg2.getLatestForegroundPackageUseTimeInMills()));
- if (DEBUG_DEXOPT) {
+ if (debug) {
Log.i(TAG, "Taking package " + lastUsed.packageName + " as reference in time use");
}
long estimatedPreviousSystemUseTime =
@@ -218,7 +225,7 @@ public class PackageManagerServiceUtils {
applyPackageFilter(remainingPredicate, result, remainingPkgs, sortTemp,
packageManagerService);
- if (DEBUG_DEXOPT) {
+ if (debug) {
Log.i(TAG, "Packages to be dexopted: " + packagesToString(result));
Log.i(TAG, "Packages skipped from dexopt: " + packagesToString(remainingPkgs));
}
diff --git a/services/core/java/com/android/server/stats/StatsCompanionService.java b/services/core/java/com/android/server/stats/StatsCompanionService.java
index b922e40a5d38..6f9d8033cd88 100644
--- a/services/core/java/com/android/server/stats/StatsCompanionService.java
+++ b/services/core/java/com/android/server/stats/StatsCompanionService.java
@@ -43,6 +43,7 @@ import android.os.FileUtils;
import android.os.IBinder;
import android.os.IStatsCompanionService;
import android.os.IStatsManager;
+import android.os.IStoraged;
import android.os.Parcelable;
import android.os.Process;
import android.os.RemoteException;
@@ -54,6 +55,7 @@ import android.os.SynchronousResultReceiver;
import android.os.SystemClock;
import android.os.UserHandle;
import android.os.UserManager;
+import android.os.storage.StorageManager;
import android.telephony.ModemActivityInfo;
import android.telephony.TelephonyManager;
import android.util.ArrayMap;
@@ -76,9 +78,19 @@ import com.android.internal.util.DumpUtils;
import com.android.server.BinderCallsStatsService;
import com.android.server.LocalServices;
import com.android.server.SystemService;
+import com.android.server.storage.DiskStatsFileLogger;
+import com.android.server.storage.DiskStatsLoggingService;
+
+import libcore.io.IoUtils;
+
+import org.json.JSONArray;
+import org.json.JSONException;
+import org.json.JSONObject;
import java.io.File;
import java.io.FileDescriptor;
+import java.io.FileOutputStream;
+import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Arrays;
@@ -861,14 +873,6 @@ public class StatsCompanionService extends IStatsCompanionService.Stub {
pulledData.add(e);
}
- private void pullDiskSpace(int tagId, List<StatsLogEventWrapper> pulledData) {
- StatsLogEventWrapper e = new StatsLogEventWrapper(SystemClock.elapsedRealtimeNanos(), tagId, 3);
- e.writeLong(mStatFsData.getAvailableBytes());
- e.writeLong(mStatFsSystem.getAvailableBytes());
- e.writeLong(mStatFsTemp.getAvailableBytes());
- pulledData.add(e);
- }
-
private void pullSystemUpTime(int tagId, List<StatsLogEventWrapper> pulledData) {
StatsLogEventWrapper e = new StatsLogEventWrapper(SystemClock.elapsedRealtimeNanos(), tagId, 1);
e.writeLong(SystemClock.uptimeMillis());
@@ -962,6 +966,183 @@ public class StatsCompanionService extends IStatsCompanionService.Stub {
}
}
+ private void pullDiskStats(int tagId, List<StatsLogEventWrapper> 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
+
+ File tmp = new File(Environment.getDataDirectory(), "system/statsdperftest.tmp");
+ FileOutputStream fos = null;
+ IOException error = null;
+
+ long before = SystemClock.elapsedRealtime();
+ try {
+ fos = new FileOutputStream(tmp);
+ fos.write(junk);
+ } catch (IOException e) {
+ error = e;
+ } finally {
+ try {
+ if (fos != null) fos.close();
+ } catch (IOException e) {
+ // Do nothing.
+ }
+ }
+
+ long latency = SystemClock.elapsedRealtime() - before;
+ if (tmp.exists()) tmp.delete();
+
+ if (error != null) {
+ Slog.e(TAG, "Error performing diskstats latency test");
+ latency = -1;
+ }
+ // File based encryption.
+ boolean fileBased = StorageManager.isFileEncryptedNativeOnly();
+
+ //Recent disk write speed. Binder call to storaged.
+ int writeSpeed = -1;
+ try {
+ IBinder binder = ServiceManager.getService("storaged");
+ if (binder == null) {
+ Slog.e(TAG, "storaged not found");
+ }
+ IStoraged storaged = IStoraged.Stub.asInterface(binder);
+ writeSpeed = storaged.getRecentPerf();
+ } catch (RemoteException e) {
+ Slog.e(TAG, "storaged not found");
+ }
+
+ // Add info pulledData.
+ long elapsedNanos = SystemClock.elapsedRealtimeNanos();
+ StatsLogEventWrapper e = new StatsLogEventWrapper(elapsedNanos, tagId, 3 /* fields */);
+ e.writeLong(latency);
+ e.writeBoolean(fileBased);
+ e.writeInt(writeSpeed);
+ pulledData.add(e);
+ }
+
+ private void pullDirectoryUsage(int tagId, List<StatsLogEventWrapper> pulledData) {
+ long elapsedNanos = SystemClock.elapsedRealtimeNanos();
+ StatFs statFsData = new StatFs(Environment.getDataDirectory().getAbsolutePath());
+ StatFs statFsSystem = new StatFs(Environment.getRootDirectory().getAbsolutePath());
+ StatFs statFsCache = new StatFs(Environment.getDownloadCacheDirectory().getAbsolutePath());
+
+ StatsLogEventWrapper e = new StatsLogEventWrapper(elapsedNanos, tagId, 3 /* fields */);
+ e.writeInt(StatsLog.DIRECTORY_USAGE__DIRECTORY__DATA);
+ e.writeLong(statFsData.getAvailableBytes());
+ e.writeLong(statFsData.getTotalBytes());
+ pulledData.add(e);
+
+ e = new StatsLogEventWrapper(elapsedNanos, tagId, 3 /* fields */);
+ e.writeInt(StatsLog.DIRECTORY_USAGE__DIRECTORY__CACHE);
+ e.writeLong(statFsCache.getAvailableBytes());
+ e.writeLong(statFsCache.getTotalBytes());
+ pulledData.add(e);
+
+ e = new StatsLogEventWrapper(elapsedNanos, tagId, 3 /* fields */);
+ e.writeInt(StatsLog.DIRECTORY_USAGE__DIRECTORY__SYSTEM);
+ e.writeLong(statFsSystem.getAvailableBytes());
+ e.writeLong(statFsSystem.getTotalBytes());
+ pulledData.add(e);
+ }
+
+ private void pullAppSize(int tagId, List<StatsLogEventWrapper> pulledData) {
+ long elapsedNanos = SystemClock.elapsedRealtimeNanos();
+ try {
+ String jsonStr = IoUtils.readFileAsString(DiskStatsLoggingService.DUMPSYS_CACHE_PATH);
+ JSONObject json = new JSONObject(jsonStr);
+ long cache_time = json.optLong(DiskStatsFileLogger.LAST_QUERY_TIMESTAMP_KEY, -1L);
+ JSONArray pkg_names = json.getJSONArray(DiskStatsFileLogger.PACKAGE_NAMES_KEY);
+ JSONArray app_sizes = json.getJSONArray(DiskStatsFileLogger.APP_SIZES_KEY);
+ JSONArray app_data_sizes = json.getJSONArray(DiskStatsFileLogger.APP_DATA_KEY);
+ JSONArray app_cache_sizes = json.getJSONArray(DiskStatsFileLogger.APP_CACHES_KEY);
+ // Sanity check: Ensure all 4 lists have the same length.
+ int length = pkg_names.length();
+ if (app_sizes.length() != length || app_data_sizes.length() != length
+ || app_cache_sizes.length() != length) {
+ Slog.e(TAG, "formatting error in diskstats cache file!");
+ return;
+ }
+ for (int i = 0; i < length; i++) {
+ StatsLogEventWrapper e =
+ new StatsLogEventWrapper(elapsedNanos, tagId, 5 /* fields */);
+ e.writeString(pkg_names.getString(i));
+ e.writeLong(app_sizes.optLong(i, -1L));
+ e.writeLong(app_data_sizes.optLong(i, -1L));
+ e.writeLong(app_cache_sizes.optLong(i, -1L));
+ e.writeLong(cache_time);
+ pulledData.add(e);
+ }
+ } catch (IOException | JSONException e) {
+ Slog.e(TAG, "exception reading diskstats cache file", e);
+ }
+ }
+
+ private void pullCategorySize(int tagId, List<StatsLogEventWrapper> pulledData) {
+ long elapsedNanos = SystemClock.elapsedRealtimeNanos();
+ try {
+ String jsonStr = IoUtils.readFileAsString(DiskStatsLoggingService.DUMPSYS_CACHE_PATH);
+ JSONObject json = new JSONObject(jsonStr);
+ long cacheTime = json.optLong(DiskStatsFileLogger.LAST_QUERY_TIMESTAMP_KEY, -1L);
+
+ StatsLogEventWrapper e = new StatsLogEventWrapper(elapsedNanos, tagId, 3 /* fields */);
+ e.writeInt(StatsLog.CATEGORY_SIZE__CATEGORY__APP_SIZE);
+ e.writeLong(json.optLong(DiskStatsFileLogger.APP_SIZE_AGG_KEY, -1L));
+ e.writeLong(cacheTime);
+ pulledData.add(e);
+
+ e = new StatsLogEventWrapper(elapsedNanos, tagId, 3 /* fields */);
+ e.writeInt(StatsLog.CATEGORY_SIZE__CATEGORY__APP_DATA_SIZE);
+ e.writeLong(json.optLong(DiskStatsFileLogger.APP_DATA_SIZE_AGG_KEY, -1L));
+ e.writeLong(cacheTime);
+ pulledData.add(e);
+
+ e = new StatsLogEventWrapper(elapsedNanos, tagId, 3 /* fields */);
+ e.writeInt(StatsLog.CATEGORY_SIZE__CATEGORY__APP_CACHE_SIZE);
+ e.writeLong(json.optLong(DiskStatsFileLogger.APP_CACHE_AGG_KEY, -1L));
+ e.writeLong(cacheTime);
+ pulledData.add(e);
+
+ e = new StatsLogEventWrapper(elapsedNanos, tagId, 3 /* fields */);
+ e.writeInt(StatsLog.CATEGORY_SIZE__CATEGORY__PHOTOS);
+ e.writeLong(json.optLong(DiskStatsFileLogger.PHOTOS_KEY, -1L));
+ e.writeLong(cacheTime);
+ pulledData.add(e);
+
+ e = new StatsLogEventWrapper(elapsedNanos, tagId, 3 /* fields */);
+ e.writeInt(StatsLog.CATEGORY_SIZE__CATEGORY__VIDEOS);
+ e.writeLong(json.optLong(DiskStatsFileLogger.VIDEOS_KEY, -1L));
+ e.writeLong(cacheTime);
+ pulledData.add(e);
+
+ e = new StatsLogEventWrapper(elapsedNanos, tagId, 3 /* fields */);
+ e.writeInt(StatsLog.CATEGORY_SIZE__CATEGORY__AUDIO);
+ e.writeLong(json.optLong(DiskStatsFileLogger.AUDIO_KEY, -1L));
+ e.writeLong(cacheTime);
+ pulledData.add(e);
+
+ e = new StatsLogEventWrapper(elapsedNanos, tagId, 3 /* fields */);
+ e.writeInt(StatsLog.CATEGORY_SIZE__CATEGORY__DOWNLOADS);
+ e.writeLong(json.optLong(DiskStatsFileLogger.DOWNLOADS_KEY, -1L));
+ e.writeLong(cacheTime);
+ pulledData.add(e);
+
+ e = new StatsLogEventWrapper(elapsedNanos, tagId, 3 /* fields */);
+ e.writeInt(StatsLog.CATEGORY_SIZE__CATEGORY__SYSTEM);
+ e.writeLong(json.optLong(DiskStatsFileLogger.SYSTEM_KEY, -1L));
+ e.writeLong(cacheTime);
+ pulledData.add(e);
+
+ e = new StatsLogEventWrapper(elapsedNanos, tagId, 3 /* fields */);
+ e.writeInt(StatsLog.CATEGORY_SIZE__CATEGORY__OTHER);
+ e.writeLong(json.optLong(DiskStatsFileLogger.MISC_KEY, -1L));
+ e.writeLong(cacheTime);
+ pulledData.add(e);
+ } catch (IOException | JSONException e) {
+ Slog.e(TAG, "exception reading diskstats cache file", e);
+ }
+ }
+
/**
* Pulls various data.
*/
@@ -1036,10 +1217,6 @@ public class StatsCompanionService extends IStatsCompanionService.Stub {
pullSystemElapsedRealtime(tagId, ret);
break;
}
- case StatsLog.DISK_SPACE: {
- pullDiskSpace(tagId, ret);
- break;
- }
case StatsLog.PROCESS_MEMORY_STATE: {
pullProcessMemoryState(tagId, ret);
break;
@@ -1056,6 +1233,22 @@ public class StatsCompanionService extends IStatsCompanionService.Stub {
pullLooperStats(tagId, ret);
break;
}
+ case StatsLog.DISK_STATS: {
+ pullDiskStats(tagId, ret);
+ break;
+ }
+ case StatsLog.DIRECTORY_USAGE: {
+ pullDirectoryUsage(tagId, ret);
+ break;
+ }
+ case StatsLog.APP_SIZE: {
+ pullAppSize(tagId, ret);
+ break;
+ }
+ case StatsLog.CATEGORY_SIZE: {
+ pullCategorySize(tagId, ret);
+ break;
+ }
default:
Slog.w(TAG, "No such tagId data as " + tagId);
return null;
diff --git a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
index c8bd2113ac6c..479f427fb96f 100644
--- a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
+++ b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
@@ -55,7 +55,6 @@ import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.BitmapRegionDecoder;
import android.graphics.Color;
-import android.graphics.Point;
import android.graphics.Rect;
import android.os.Binder;
import android.os.Bundle;
@@ -99,7 +98,6 @@ import com.android.server.EventLogTags;
import com.android.server.FgThread;
import com.android.server.SystemService;
-import java.lang.reflect.InvocationTargetException;
import libcore.io.IoUtils;
import org.xmlpull.v1.XmlPullParser;
@@ -120,7 +118,6 @@ import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
-import com.android.internal.R;
public class WallpaperManagerService extends IWallpaperManager.Stub
implements IWallpaperManagerService {
@@ -1544,14 +1541,6 @@ public class WallpaperManagerService extends IWallpaperManager.Stub
return false;
}
- private Point getDefaultDisplaySize() {
- Point p = new Point();
- WindowManager wm = (WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE);
- Display d = wm.getDefaultDisplay();
- d.getRealSize(p);
- return p;
- }
-
public void setDimensionHints(int width, int height, String callingPackage)
throws RemoteException {
checkPermission(android.Manifest.permission.SET_WALLPAPER_HINTS);
@@ -1564,10 +1553,6 @@ public class WallpaperManagerService extends IWallpaperManager.Stub
if (width <= 0 || height <= 0) {
throw new IllegalArgumentException("width and height must be > 0");
}
- // Make sure it is at least as large as the display.
- Point displaySize = getDefaultDisplaySize();
- width = Math.max(width, displaySize.x);
- height = Math.max(height, displaySize.y);
if (width != wallpaper.width || height != wallpaper.height) {
wallpaper.width = width;
diff --git a/services/core/java/com/android/server/wm/BoundsAnimationController.java b/services/core/java/com/android/server/wm/BoundsAnimationController.java
index a6930717ff91..731ebb8a6e86 100644
--- a/services/core/java/com/android/server/wm/BoundsAnimationController.java
+++ b/services/core/java/com/android/server/wm/BoundsAnimationController.java
@@ -26,9 +26,9 @@ import android.animation.ValueAnimator;
import android.annotation.IntDef;
import android.content.Context;
import android.graphics.Rect;
+import android.os.Debug;
import android.os.Handler;
import android.os.IBinder;
-import android.os.Debug;
import android.util.ArrayMap;
import android.util.Slog;
import android.view.Choreographer;
@@ -36,8 +36,8 @@ import android.view.animation.AnimationUtils;
import android.view.animation.Interpolator;
import com.android.internal.annotations.VisibleForTesting;
-
import com.android.internal.graphics.SfVsyncFrameCallbackProvider;
+
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@@ -178,7 +178,7 @@ public class BoundsAnimationController {
BoundsAnimator(BoundsAnimationTarget target, Rect from, Rect to,
@SchedulePipModeChangedState int schedulePipModeChangedState,
@SchedulePipModeChangedState int prevShedulePipModeChangedState,
- boolean moveFromFullscreen, boolean moveToFullscreen) {
+ boolean moveFromFullscreen, boolean moveToFullscreen, Rect frozenTask) {
super();
mTarget = target;
mFrom.set(from);
@@ -198,8 +198,8 @@ public class BoundsAnimationController {
mFrozenTaskWidth = mTo.width();
mFrozenTaskHeight = mTo.height();
} else {
- mFrozenTaskWidth = mFrom.width();
- mFrozenTaskHeight = mFrom.height();
+ mFrozenTaskWidth = frozenTask.isEmpty() ? mFrom.width() : frozenTask.width();
+ mFrozenTaskHeight = frozenTask.isEmpty() ? mFrom.height() : frozenTask.height();
}
}
@@ -425,6 +425,7 @@ public class BoundsAnimationController {
+ " schedulePipModeChangedState=" + schedulePipModeChangedState
+ " replacing=" + replacing);
+ Rect frozenTask = new Rect();
if (replacing) {
if (existing.isAnimatingTo(to) && (!moveToFullscreen || existing.mMoveToFullscreen)
&& (!moveFromFullscreen || existing.mMoveFromFullscreen)) {
@@ -467,12 +468,17 @@ public class BoundsAnimationController {
moveFromFullscreen = existing.mMoveFromFullscreen;
}
+ // We are in the middle of an existing animation, so that this new animation may
+ // start from an interpolated bounds. We should keep using the existing frozen task
+ // width/height for consistent configurations.
+ frozenTask.set(0, 0, existing.mFrozenTaskWidth, existing.mFrozenTaskHeight);
+
// Since we are replacing, we skip both animation start and end callbacks
existing.cancel();
}
final BoundsAnimator animator = new BoundsAnimator(target, from, to,
schedulePipModeChangedState, prevSchedulePipModeChangedState,
- moveFromFullscreen, moveToFullscreen);
+ moveFromFullscreen, moveToFullscreen, frozenTask);
mRunningAnimations.put(target, animator);
animator.setFloatValues(0f, 1f);
animator.setDuration((animationDuration != -1 ? animationDuration
diff --git a/services/core/java/com/android/server/wm/TEST_MAPPING b/services/core/java/com/android/server/wm/TEST_MAPPING
index e885afa8031d..c99329a7508c 100644
--- a/services/core/java/com/android/server/wm/TEST_MAPPING
+++ b/services/core/java/com/android/server/wm/TEST_MAPPING
@@ -24,6 +24,20 @@
"exclude-annotation": "android.support.test.filters.FlakyTest"
}
]
+ },
+ {
+ "name": "WmTests",
+ "options": [
+ {
+ "include-filter": "com.android.server.wm."
+ },
+ {
+ "include-annotation": "android.platform.test.annotations.Presubmit"
+ },
+ {
+ "exclude-annotation": "android.support.test.filters.FlakyTest"
+ }
+ ]
}
],
"postsubmit": [
@@ -37,6 +51,14 @@
"include-filter": "com.android.server.wm."
}
]
+ },
+ {
+ "name": "WmTests",
+ "options": [
+ {
+ "include-filter": "com.android.server.wm."
+ }
+ ]
}
]
}
diff --git a/services/core/java/com/android/server/wm/WindowStateAnimator.java b/services/core/java/com/android/server/wm/WindowStateAnimator.java
index c80eb868a732..fec803960012 100644
--- a/services/core/java/com/android/server/wm/WindowStateAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowStateAnimator.java
@@ -1062,7 +1062,8 @@ class WindowStateAnimator {
// comes in at the new size (normally position and crop are unfrozen).
// setGeometryAppliesWithResizeInTransaction accomplishes this for us.
if (wasForceScaled && !mForceScaleUntilResize) {
- mSurfaceController.setGeometryAppliesWithResizeInTransaction(true);
+ mSurfaceController.deferTransactionUntil(mSurfaceController.getHandle(),
+ mWin.getFrameNumber());
mSurfaceController.forceScaleableInTransaction(false);
}
diff --git a/services/core/jni/com_android_server_UsbDescriptorParser.cpp b/services/core/jni/com_android_server_UsbDescriptorParser.cpp
index 62bab073ac1d..d29d3fcb51d5 100644
--- a/services/core/jni/com_android_server_UsbDescriptorParser.cpp
+++ b/services/core/jni/com_android_server_UsbDescriptorParser.cpp
@@ -25,6 +25,7 @@
#include <usbhost/usbhost.h>
#define MAX_DESCRIPTORS_LENGTH 4096
+static const int USB_CONTROL_TRANSFER_TIMEOUT_MS = 200;
// com.android.server.usb.descriptors
extern "C" {
@@ -85,8 +86,9 @@ jstring JNICALL Java_com_android_server_usb_descriptors_UsbDescriptorParser_getD
jbyte* byteBuffer = NULL;
size_t numUSC2Bytes = 0;
int retVal =
- usb_device_get_string_ucs2(device, stringId, 0 /*timeout*/,
- (void**)&byteBuffer, &numUSC2Bytes);
+ usb_device_get_string_ucs2(device, stringId,
+ USB_CONTROL_TRANSFER_TIMEOUT_MS,
+ (void**)&byteBuffer, &numUSC2Bytes);
jstring j_str = NULL;
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index c131858d3ffe..a1132d7dcde7 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -377,6 +377,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
private static final Set<String> GLOBAL_SETTINGS_WHITELIST;
private static final Set<String> GLOBAL_SETTINGS_DEPRECATED;
private static final Set<String> SYSTEM_SETTINGS_WHITELIST;
+ private static final Set<Integer> DA_DISALLOWED_POLICIES;
static {
SECURE_SETTINGS_WHITELIST = new ArraySet<>();
SECURE_SETTINGS_WHITELIST.add(Settings.Secure.DEFAULT_INPUT_METHOD);
@@ -408,6 +409,12 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
SYSTEM_SETTINGS_WHITELIST.add(Settings.System.SCREEN_BRIGHTNESS);
SYSTEM_SETTINGS_WHITELIST.add(Settings.System.SCREEN_BRIGHTNESS_MODE);
SYSTEM_SETTINGS_WHITELIST.add(Settings.System.SCREEN_OFF_TIMEOUT);
+
+ DA_DISALLOWED_POLICIES = new ArraySet<>();
+ DA_DISALLOWED_POLICIES.add(DeviceAdminInfo.USES_POLICY_DISABLE_CAMERA);
+ DA_DISALLOWED_POLICIES.add(DeviceAdminInfo.USES_POLICY_DISABLE_KEYGUARD_FEATURES);
+ DA_DISALLOWED_POLICIES.add(DeviceAdminInfo.USES_POLICY_EXPIRE_PASSWORD);
+ DA_DISALLOWED_POLICIES.add(DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
}
/**
@@ -2203,6 +2210,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
* @return the user password metrics, or {@code null} if none have been associated with
* the user yet (for example, if the device has booted but not been unlocked).
*/
+ @GuardedBy("getLockObject()")
PasswordMetrics getUserPasswordMetricsLocked(int userHandle) {
return mUserPasswordMetrics.get(userHandle);
}
@@ -2607,6 +2615,9 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
final int userId = UserHandle.getUserId(callingUid);
final DevicePolicyData policy = getUserData(userId);
ActiveAdmin admin = policy.mAdminMap.get(who);
+ final boolean isDeviceOwner = isDeviceOwner(admin.info.getComponent(), userId);
+ final boolean isProfileOwner = isProfileOwner(admin.info.getComponent(), userId);
+
if (reqPolicy == DeviceAdminInfo.USES_POLICY_DEVICE_OWNER) {
throw new SecurityException("Admin " + admin.info.getComponent()
+ " does not own the device");
@@ -2615,6 +2626,11 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
throw new SecurityException("Admin " + admin.info.getComponent()
+ " does not own the profile");
}
+ if (DA_DISALLOWED_POLICIES.contains(reqPolicy) && !isDeviceOwner && !isProfileOwner) {
+ throw new SecurityException("Admin " + admin.info.getComponent()
+ + " is not a device owner or profile owner, so may not use policy: "
+ + admin.info.getTagForPolicy(reqPolicy));
+ }
throw new SecurityException("Admin " + admin.info.getComponent()
+ " did not specify uses-policy for: "
+ admin.info.getTagForPolicy(reqPolicy));
@@ -2694,7 +2710,10 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
// DO always has the PO power.
return ownsDevice || ownsProfile;
} else {
- return admin.info.usesPolicy(reqPolicy);
+ boolean allowedToUsePolicy = ownsDevice || ownsProfile
+ || !DA_DISALLOWED_POLICIES.contains(reqPolicy)
+ || getTargetSdk(admin.info.getPackageName(), userId) < Build.VERSION_CODES.Q;
+ return allowedToUsePolicy && admin.info.usesPolicy(reqPolicy);
}
}
@@ -3972,6 +3991,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
* be the correct one upon boot.
* This should be called whenever the password or the admin policies have changed.
*/
+ @GuardedBy("getLockObject()")
private void updatePasswordValidityCheckpointLocked(int userHandle, boolean parent) {
final int credentialOwner = getCredentialOwner(userHandle, parent);
DevicePolicyData policy = getUserData(credentialOwner);
@@ -12313,6 +12333,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
}
/** Pauses security and network logging if there are unaffiliated users on the device */
+ @GuardedBy("getLockObject()")
private void maybePauseDeviceWideLoggingLocked() {
if (!areAllUsersAffiliatedWithDeviceLocked()) {
Slog.i(LOG_TAG, "There are unaffiliated users, security and network logging will be "
@@ -12325,6 +12346,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
}
/** Resumes security and network logging (if they are enabled) if all users are affiliated */
+ @GuardedBy("getLockObject()")
private void maybeResumeDeviceWideLoggingLocked() {
if (areAllUsersAffiliatedWithDeviceLocked()) {
final long ident = mInjector.binderClearCallingIdentity();
@@ -12340,6 +12362,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
}
/** Deletes any security and network logs that might have been collected so far */
+ @GuardedBy("getLockObject()")
private void discardDeviceWideLogsLocked() {
mSecurityLogMonitor.discardLogs();
if (mNetworkLogger != null) {
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index b9f8fdbc7674..0b6a33f8c013 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -883,7 +883,8 @@ public final class SystemServer {
}
traceBeginAndSlog("StartAlarmManagerService");
- mSystemServiceManager.startService(AlarmManagerService.class);
+ mSystemServiceManager.startService(new AlarmManagerService(context));
+
traceEnd();
traceBeginAndSlog("InitWatchdog");
diff --git a/services/net/java/android/net/ip/RouterAdvertisementDaemon.java b/services/net/java/android/net/ip/RouterAdvertisementDaemon.java
index 8fbc01ea4493..9d686efcb2ab 100644
--- a/services/net/java/android/net/ip/RouterAdvertisementDaemon.java
+++ b/services/net/java/android/net/ip/RouterAdvertisementDaemon.java
@@ -119,13 +119,23 @@ public class RouterAdvertisementDaemon {
private volatile UnicastResponder mUnicastResponder;
public static class RaParams {
+ // Tethered traffic will have the hop limit properly decremented.
+ // Consequently, set the hoplimit greater by one than the upstream
+ // unicast hop limit.
+ //
+ // TODO: Dynamically pass down the IPV6_UNICAST_HOPS value from the
+ // upstream interface for more correct behaviour.
+ static final byte DEFAULT_HOPLIMIT = 65;
+
public boolean hasDefaultRoute;
+ public byte hopLimit;
public int mtu;
public HashSet<IpPrefix> prefixes;
public HashSet<Inet6Address> dnses;
public RaParams() {
hasDefaultRoute = false;
+ hopLimit = DEFAULT_HOPLIMIT;
mtu = IPV6_MIN_MTU;
prefixes = new HashSet<IpPrefix>();
dnses = new HashSet<Inet6Address>();
@@ -133,6 +143,7 @@ public class RouterAdvertisementDaemon {
public RaParams(RaParams other) {
hasDefaultRoute = other.hasDefaultRoute;
+ hopLimit = other.hopLimit;
mtu = other.mtu;
prefixes = (HashSet) other.prefixes.clone();
dnses = (HashSet) other.dnses.clone();
@@ -273,10 +284,12 @@ public class RouterAdvertisementDaemon {
final ByteBuffer ra = ByteBuffer.wrap(mRA);
ra.order(ByteOrder.BIG_ENDIAN);
+ final boolean haveRaParams = (mRaParams != null);
boolean shouldSendRA = false;
try {
- putHeader(ra, mRaParams != null && mRaParams.hasDefaultRoute);
+ putHeader(ra, haveRaParams && mRaParams.hasDefaultRoute,
+ haveRaParams ? mRaParams.hopLimit : RaParams.DEFAULT_HOPLIMIT);
putSlla(ra, mInterface.macAddr.toByteArray());
mRaLength = ra.position();
@@ -287,7 +300,7 @@ public class RouterAdvertisementDaemon {
//
// putExpandedFlagsOption(ra);
- if (mRaParams != null) {
+ if (haveRaParams) {
putMtu(ra, mRaParams.mtu);
mRaLength = ra.position();
@@ -348,7 +361,7 @@ public class RouterAdvertisementDaemon {
private static byte asByte(int value) { return (byte) value; }
private static short asShort(int value) { return (short) value; }
- private static void putHeader(ByteBuffer ra, boolean hasDefaultRoute) {
+ private static void putHeader(ByteBuffer ra, boolean hasDefaultRoute, byte hopLimit) {
/**
Router Advertisement Message Format
@@ -366,11 +379,10 @@ public class RouterAdvertisementDaemon {
| Options ...
+-+-+-+-+-+-+-+-+-+-+-+-
*/
- final byte DEFAULT_HOPLIMIT = 64;
ra.put(ICMPV6_ND_ROUTER_ADVERT)
.put(asByte(0))
.putShort(asShort(0))
- .put(DEFAULT_HOPLIMIT)
+ .put(hopLimit)
// RFC 4191 "high" preference, iff. advertising a default route.
.put(hasDefaultRoute ? asByte(0x08) : asByte(0))
.putShort(hasDefaultRoute ? asShort(DEFAULT_LIFETIME) : asShort(0))
diff --git a/services/robotests/Android.mk b/services/robotests/Android.mk
index 3d7fdbdd7436..2691701f79af 100644
--- a/services/robotests/Android.mk
+++ b/services/robotests/Android.mk
@@ -63,7 +63,9 @@ LOCAL_SRC_FILES := \
$(call all-Iaidl-files-under, ../../core/java/android/app/backup) \
../../core/java/android/content/pm/PackageInfo.java \
../../core/java/android/app/IBackupAgent.aidl \
- ../../core/java/android/util/KeyValueSettingObserver.java
+ ../../core/java/android/util/KeyValueSettingObserver.java \
+ ../../core/java/android/content/pm/PackageParser.java \
+ ../../core/java/android/content/pm/SigningInfo.java
LOCAL_AIDL_INCLUDES := \
$(call all-Iaidl-files-under, $(INTERNAL_BACKUP)) \
diff --git a/services/robotests/src/com/android/server/backup/fullbackup/AppMetadataBackupWriterTest.java b/services/robotests/src/com/android/server/backup/fullbackup/AppMetadataBackupWriterTest.java
new file mode 100644
index 000000000000..112e1e385fed
--- /dev/null
+++ b/services/robotests/src/com/android/server/backup/fullbackup/AppMetadataBackupWriterTest.java
@@ -0,0 +1,495 @@
+package com.android.server.backup.fullbackup;
+
+import static com.android.server.backup.BackupManagerService.BACKUP_MANIFEST_FILENAME;
+import static com.android.server.backup.BackupManagerService.BACKUP_MANIFEST_VERSION;
+import static com.android.server.backup.BackupManagerService.BACKUP_METADATA_FILENAME;
+import static com.android.server.backup.BackupManagerService.BACKUP_METADATA_VERSION;
+import static com.android.server.backup.BackupManagerService.BACKUP_WIDGET_METADATA_TOKEN;
+
+import static com.google.common.truth.Truth.assertThat;
+import static org.robolectric.Shadows.shadowOf;
+import static org.testng.Assert.expectThrows;
+
+import android.annotation.Nullable;
+import android.app.Application;
+import android.app.backup.BackupDataInput;
+import android.app.backup.FullBackupDataOutput;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.PackageParser.SigningDetails;
+import android.content.pm.Signature;
+import android.content.pm.SigningInfo;
+import android.os.Build;
+import android.os.Build.VERSION_CODES;
+import android.os.Environment;
+import android.os.ParcelFileDescriptor;
+import android.os.UserHandle;
+
+import com.android.server.testing.FrameworkRobolectricTestRunner;
+import com.android.server.testing.SystemLoaderClasses;
+import com.android.server.testing.SystemLoaderPackages;
+import com.android.server.testing.shadows.ShadowBackupDataInput;
+import com.android.server.testing.shadows.ShadowBackupDataOutput;
+import com.android.server.testing.shadows.ShadowFullBackup;
+import java.io.ByteArrayOutputStream;
+import java.io.DataOutputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.nio.charset.StandardCharsets;
+import java.nio.file.Files;
+import java.nio.file.attribute.FileTime;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.robolectric.RuntimeEnvironment;
+import org.robolectric.annotation.Config;
+import org.robolectric.shadows.ShadowApplicationPackageManager;
+import org.robolectric.shadows.ShadowEnvironment;
+
+@RunWith(FrameworkRobolectricTestRunner.class)
+@Config(
+ manifest = Config.NONE,
+ sdk = 26,
+ shadows = {
+ ShadowBackupDataInput.class,
+ ShadowBackupDataOutput.class,
+ ShadowEnvironment.class,
+ ShadowFullBackup.class,
+ })
+@SystemLoaderPackages({"com.android.server.backup", "android.app.backup"})
+@SystemLoaderClasses({PackageInfo.class, SigningInfo.class})
+public class AppMetadataBackupWriterTest {
+ private static final String TEST_PACKAGE = "com.test.package";
+ private static final String TEST_PACKAGE_INSTALLER = "com.test.package.installer";
+ private static final Long TEST_PACKAGE_VERSION_CODE = 100L;
+
+ private ShadowApplicationPackageManager mShadowPackageManager;
+ private File mFilesDir;
+ private File mBackupDataOutputFile;
+ private AppMetadataBackupWriter mBackupWriter;
+
+ @Before
+ public void setUp() throws Exception {
+ Application application = RuntimeEnvironment.application;
+
+ PackageManager packageManager = application.getPackageManager();
+ mShadowPackageManager = (ShadowApplicationPackageManager) shadowOf(packageManager);
+
+ mFilesDir = RuntimeEnvironment.application.getFilesDir();
+ mBackupDataOutputFile = new File(mFilesDir, "output");
+ mBackupDataOutputFile.createNewFile();
+ ParcelFileDescriptor pfd =
+ ParcelFileDescriptor.open(
+ mBackupDataOutputFile, ParcelFileDescriptor.MODE_READ_WRITE);
+ FullBackupDataOutput output =
+ new FullBackupDataOutput(pfd, /* quota */ -1, /* transportFlags */ 0);
+ mBackupWriter = new AppMetadataBackupWriter(output, packageManager);
+ }
+
+ @After
+ public void tearDown() throws Exception {
+ mBackupDataOutputFile.delete();
+ }
+
+ /**
+ * The manifest format is:
+ *
+ * <pre>
+ * BACKUP_MANIFEST_VERSION
+ * package name
+ * package version code
+ * platform version code
+ * installer package name (can be empty)
+ * boolean (1 if archive includes .apk, otherwise 0)
+ * # of signatures N
+ * N* (signature byte array in ascii format per Signature.toCharsString())
+ * </pre>
+ */
+ @Test
+ public void testBackupManifest_withoutApkOrSignatures_writesCorrectData() throws Exception {
+ PackageInfo packageInfo =
+ createPackageInfo(TEST_PACKAGE, TEST_PACKAGE_INSTALLER, TEST_PACKAGE_VERSION_CODE);
+ File manifestFile = createFile(BACKUP_MANIFEST_FILENAME);
+
+ mBackupWriter.backupManifest(packageInfo, manifestFile, mFilesDir, /* withApk */ false);
+
+ byte[] manifestBytes = getWrittenBytes(mBackupDataOutputFile, /* includeTarHeader */ false);
+ String[] manifest = new String(manifestBytes, StandardCharsets.UTF_8).split("\n");
+ assertThat(manifest.length).isEqualTo(7);
+ assertThat(manifest[0]).isEqualTo(Integer.toString(BACKUP_MANIFEST_VERSION));
+ assertThat(manifest[1]).isEqualTo(TEST_PACKAGE);
+ assertThat(manifest[2]).isEqualTo(Long.toString(TEST_PACKAGE_VERSION_CODE));
+ assertThat(manifest[3]).isEqualTo(Integer.toString(Build.VERSION.SDK_INT));
+ assertThat(manifest[4]).isEqualTo(TEST_PACKAGE_INSTALLER);
+ assertThat(manifest[5]).isEqualTo("0"); // withApk
+ assertThat(manifest[6]).isEqualTo("0"); // signatures
+ manifestFile.delete();
+ }
+
+ /**
+ * The manifest format is:
+ *
+ * <pre>
+ * BACKUP_MANIFEST_VERSION
+ * package name
+ * package version code
+ * platform version code
+ * installer package name (can be empty)
+ * boolean (1 if archive includes .apk, otherwise 0)
+ * # of signatures N
+ * N* (signature byte array in ascii format per Signature.toCharsString())
+ * </pre>
+ */
+ @Test
+ public void testBackupManifest_withApk_writesApk() throws Exception {
+ PackageInfo packageInfo =
+ createPackageInfo(TEST_PACKAGE, TEST_PACKAGE_INSTALLER, TEST_PACKAGE_VERSION_CODE);
+ File manifestFile = createFile(BACKUP_MANIFEST_FILENAME);
+
+ mBackupWriter.backupManifest(packageInfo, manifestFile, mFilesDir, /* withApk */ true);
+
+ byte[] manifestBytes = getWrittenBytes(mBackupDataOutputFile, /* includeTarHeader */ false);
+ String[] manifest = new String(manifestBytes, StandardCharsets.UTF_8).split("\n");
+ assertThat(manifest.length).isEqualTo(7);
+ assertThat(manifest[5]).isEqualTo("1"); // withApk
+ manifestFile.delete();
+ }
+
+ /**
+ * The manifest format is:
+ *
+ * <pre>
+ * BACKUP_MANIFEST_VERSION
+ * package name
+ * package version code
+ * platform version code
+ * installer package name (can be empty)
+ * boolean (1 if archive includes .apk, otherwise 0)
+ * # of signatures N
+ * N* (signature byte array in ascii format per Signature.toCharsString())
+ * </pre>
+ */
+ @Test
+ public void testBackupManifest_withSignatures_writesCorrectSignatures() throws Exception {
+ PackageInfo packageInfo =
+ createPackageInfo(TEST_PACKAGE, TEST_PACKAGE_INSTALLER, TEST_PACKAGE_VERSION_CODE);
+ packageInfo.signingInfo =
+ new SigningInfo(
+ new SigningDetails(
+ new Signature[] {new Signature("1234"), new Signature("5678")},
+ SigningDetails.SignatureSchemeVersion.SIGNING_BLOCK_V3,
+ null,
+ null,
+ null));
+ File manifestFile = createFile(BACKUP_MANIFEST_FILENAME);
+
+ mBackupWriter.backupManifest(packageInfo, manifestFile, mFilesDir, /* withApk */ false);
+
+ byte[] manifestBytes = getWrittenBytes(mBackupDataOutputFile, /* includeTarHeader */ false);
+ String[] manifest = new String(manifestBytes, StandardCharsets.UTF_8).split("\n");
+ assertThat(manifest.length).isEqualTo(9);
+ assertThat(manifest[6]).isEqualTo("2"); // # of signatures
+ assertThat(manifest[7]).isEqualTo("1234"); // first signature
+ assertThat(manifest[8]).isEqualTo("5678"); // second signature
+ manifestFile.delete();
+ }
+
+ /**
+ * The manifest format is:
+ *
+ * <pre>
+ * BACKUP_MANIFEST_VERSION
+ * package name
+ * package version code
+ * platform version code
+ * installer package name (can be empty)
+ * boolean (1 if archive includes .apk, otherwise 0)
+ * # of signatures N
+ * N* (signature byte array in ascii format per Signature.toCharsString())
+ * </pre>
+ */
+ @Config(sdk = VERSION_CODES.O)
+ @Test
+ public void testBackupManifest_whenApiO_writesCorrectApi() throws Exception {
+ PackageInfo packageInfo =
+ createPackageInfo(TEST_PACKAGE, TEST_PACKAGE_INSTALLER, TEST_PACKAGE_VERSION_CODE);
+ File manifestFile = createFile(BACKUP_MANIFEST_FILENAME);
+
+ mBackupWriter.backupManifest(packageInfo, manifestFile, mFilesDir, /* withApk */ false);
+
+ byte[] manifestBytes = getWrittenBytes(mBackupDataOutputFile, /* includeTarHeader */ false);
+ String[] manifest = new String(manifestBytes, StandardCharsets.UTF_8).split("\n");
+ assertThat(manifest.length).isEqualTo(7);
+ assertThat(manifest[3]).isEqualTo(Integer.toString(VERSION_CODES.O)); // platform version
+ manifestFile.delete();
+ }
+
+ /**
+ * The manifest format is:
+ *
+ * <pre>
+ * BACKUP_MANIFEST_VERSION
+ * package name
+ * package version code
+ * platform version code
+ * installer package name (can be empty)
+ * boolean (1 if archive includes .apk, otherwise 0)
+ * # of signatures N
+ * N* (signature byte array in ascii format per Signature.toCharsString())
+ * </pre>
+ */
+ @Test
+ public void testBackupManifest_withoutInstallerPackage_writesEmptyInstaller() throws Exception {
+ PackageInfo packageInfo = createPackageInfo(TEST_PACKAGE, null, TEST_PACKAGE_VERSION_CODE);
+ File manifestFile = createFile(BACKUP_MANIFEST_FILENAME);
+
+ mBackupWriter.backupManifest(packageInfo, manifestFile, mFilesDir, /* withApk */ false);
+
+ byte[] manifestBytes = getWrittenBytes(mBackupDataOutputFile, /* includeTarHeader */ false);
+ String[] manifest = new String(manifestBytes, StandardCharsets.UTF_8).split("\n");
+ assertThat(manifest.length).isEqualTo(7);
+ assertThat(manifest[4]).isEqualTo(""); // installer package name
+ manifestFile.delete();
+ }
+
+ @Test
+ public void testBackupManifest_whenRunPreviouslyWithSameData_producesSameBytesOnSecondRun()
+ throws Exception {
+ PackageInfo packageInfo =
+ createPackageInfo(TEST_PACKAGE, TEST_PACKAGE_INSTALLER, TEST_PACKAGE_VERSION_CODE);
+ File manifestFile = createFile(BACKUP_MANIFEST_FILENAME);
+ mBackupWriter.backupManifest(packageInfo, manifestFile, mFilesDir, /* withApk */ false);
+ byte[] firstRunBytes = getWrittenBytes(mBackupDataOutputFile, /* includeTarHeader */ true);
+ // Simulate modifying the manifest file to ensure that file metadata does not change the
+ // backup bytes produced.
+ modifyFileMetadata(manifestFile);
+
+ mBackupWriter.backupManifest(packageInfo, manifestFile, mFilesDir, /* withApk */ false);
+
+ byte[] secondRunBytes = getWrittenBytes(mBackupDataOutputFile, /* includeTarHeader */ true);
+ assertThat(firstRunBytes).isEqualTo(secondRunBytes);
+ manifestFile.delete();
+ }
+
+ /**
+ * The widget data format with metadata is:
+ *
+ * <pre>
+ * BACKUP_METADATA_VERSION
+ * package name
+ * 4 : Integer token identifying the widget data blob.
+ * 4 : Integer size of the widget data.
+ * N : Raw bytes of the widget data.
+ * </pre>
+ */
+ @Test
+ public void testBackupWidget_writesCorrectData() throws Exception {
+ PackageInfo packageInfo =
+ createPackageInfo(TEST_PACKAGE, TEST_PACKAGE_INSTALLER, TEST_PACKAGE_VERSION_CODE);
+ File metadataFile = createFile(BACKUP_METADATA_FILENAME);
+ byte[] widgetBytes = "widget".getBytes();
+
+ mBackupWriter.backupWidget(packageInfo, metadataFile, mFilesDir, widgetBytes);
+
+ byte[] writtenBytes = getWrittenBytes(mBackupDataOutputFile, /* includeTarHeader */ false);
+ String[] widgetData = new String(writtenBytes, StandardCharsets.UTF_8).split("\n");
+ assertThat(widgetData.length).isEqualTo(3);
+ // Metadata header
+ assertThat(widgetData[0]).isEqualTo(Integer.toString(BACKUP_METADATA_VERSION));
+ assertThat(widgetData[1]).isEqualTo(packageInfo.packageName);
+ // Widget data
+ ByteArrayOutputStream expectedBytes = new ByteArrayOutputStream();
+ DataOutputStream stream = new DataOutputStream(expectedBytes);
+ stream.writeInt(BACKUP_WIDGET_METADATA_TOKEN);
+ stream.writeInt(widgetBytes.length);
+ stream.write(widgetBytes);
+ stream.flush();
+ assertThat(widgetData[2]).isEqualTo(expectedBytes.toString());
+ metadataFile.delete();
+ }
+
+ @Test
+ public void testBackupWidget_withNullWidgetData_throwsNullPointerException() throws Exception {
+ PackageInfo packageInfo =
+ createPackageInfo(TEST_PACKAGE, TEST_PACKAGE_INSTALLER, TEST_PACKAGE_VERSION_CODE);
+ File metadataFile = createFile(BACKUP_METADATA_FILENAME);
+
+ expectThrows(
+ NullPointerException.class,
+ () ->
+ mBackupWriter.backupWidget(
+ packageInfo, metadataFile, mFilesDir, /* widgetData */ null));
+
+ metadataFile.delete();
+ }
+
+ @Test
+ public void testBackupWidget_withEmptyWidgetData_throwsIllegalArgumentException()
+ throws Exception {
+ PackageInfo packageInfo =
+ createPackageInfo(TEST_PACKAGE, TEST_PACKAGE_INSTALLER, TEST_PACKAGE_VERSION_CODE);
+ File metadataFile = createFile(BACKUP_METADATA_FILENAME);
+
+ expectThrows(
+ IllegalArgumentException.class,
+ () ->
+ mBackupWriter.backupWidget(
+ packageInfo, metadataFile, mFilesDir, new byte[0]));
+
+ metadataFile.delete();
+ }
+
+ @Test
+ public void testBackupWidget_whenRunPreviouslyWithSameData_producesSameBytesOnSecondRun()
+ throws Exception {
+ PackageInfo packageInfo =
+ createPackageInfo(TEST_PACKAGE, TEST_PACKAGE_INSTALLER, TEST_PACKAGE_VERSION_CODE);
+ File metadataFile = createFile(BACKUP_METADATA_FILENAME);
+ byte[] widgetBytes = "widget".getBytes();
+ mBackupWriter.backupWidget(packageInfo, metadataFile, mFilesDir, widgetBytes);
+ byte[] firstRunBytes = getWrittenBytes(mBackupDataOutputFile, /* includeTarHeader */ true);
+ // Simulate modifying the metadata file to ensure that file metadata does not change the
+ // backup bytes produced.
+ modifyFileMetadata(metadataFile);
+
+ mBackupWriter.backupWidget(packageInfo, metadataFile, mFilesDir, widgetBytes);
+
+ byte[] secondRunBytes = getWrittenBytes(mBackupDataOutputFile, /* includeTarHeader */ true);
+ assertThat(firstRunBytes).isEqualTo(secondRunBytes);
+ metadataFile.delete();
+ }
+
+ @Test
+ public void testBackupApk_writesCorrectBytesToOutput() throws Exception {
+ PackageInfo packageInfo =
+ createPackageInfo(TEST_PACKAGE, TEST_PACKAGE_INSTALLER, TEST_PACKAGE_VERSION_CODE);
+ byte[] apkBytes = "apk".getBytes();
+ File apkFile = createApkFileAndWrite(apkBytes);
+ packageInfo.applicationInfo = new ApplicationInfo();
+ packageInfo.applicationInfo.sourceDir = apkFile.getPath();
+
+ mBackupWriter.backupApk(packageInfo);
+
+ byte[] writtenBytes = getWrittenBytes(mBackupDataOutputFile, /* includeTarHeader */ false);
+ assertThat(writtenBytes).isEqualTo(apkBytes);
+ apkFile.delete();
+ }
+
+ @Test
+ public void testBackupObb_withObbData_writesCorrectBytesToOutput() throws Exception {
+ PackageInfo packageInfo =
+ createPackageInfo(TEST_PACKAGE, TEST_PACKAGE_INSTALLER, TEST_PACKAGE_VERSION_CODE);
+ File obbDir = createObbDirForPackage(packageInfo.packageName);
+ byte[] obbBytes = "obb".getBytes();
+ File obbFile = createObbFileAndWrite(obbDir, obbBytes);
+
+ mBackupWriter.backupObb(packageInfo);
+
+ byte[] writtenBytes = getWrittenBytes(mBackupDataOutputFile, /* includeTarHeader */ false);
+ assertThat(writtenBytes).isEqualTo(obbBytes);
+ obbFile.delete();
+ }
+
+ @Test
+ public void testBackupObb_withNoObbData_doesNotWriteBytesToOutput() throws Exception {
+ PackageInfo packageInfo =
+ createPackageInfo(TEST_PACKAGE, TEST_PACKAGE_INSTALLER, TEST_PACKAGE_VERSION_CODE);
+ File obbDir = createObbDirForPackage(packageInfo.packageName);
+ // No obb file created.
+
+ mBackupWriter.backupObb(packageInfo);
+
+ assertThat(mBackupDataOutputFile.length()).isEqualTo(0);
+ }
+
+ /**
+ * Creates a test package and registers it with the package manager. Also sets the installer
+ * package name if not {@code null}.
+ */
+ private PackageInfo createPackageInfo(
+ String packageName, @Nullable String installerPackageName, long versionCode) {
+ PackageInfo packageInfo = new PackageInfo();
+ packageInfo.packageName = packageName;
+ packageInfo.setLongVersionCode(versionCode);
+ mShadowPackageManager.addPackage(packageInfo);
+ if (installerPackageName != null) {
+ mShadowPackageManager.setInstallerPackageName(packageName, installerPackageName);
+ }
+ return packageInfo;
+ }
+
+ /**
+ * Reads backup data written to the {@code file} by {@link ShadowBackupDataOutput}. Uses {@link
+ * ShadowBackupDataInput} to parse the data. Follows the format used by {@link
+ * ShadowFullBackup#backupToTar(String, String, String, String, String, FullBackupDataOutput)}.
+ *
+ * @param includeTarHeader If {@code true}, returns the TAR header and data bytes combined.
+ * Otherwise, only returns the data bytes.
+ */
+ private byte[] getWrittenBytes(File file, boolean includeTarHeader) throws IOException {
+ BackupDataInput input = new BackupDataInput(new FileInputStream(file).getFD());
+ input.readNextHeader();
+ int dataSize = input.getDataSize();
+
+ byte[] bytes;
+ if (includeTarHeader) {
+ bytes = new byte[dataSize + 512];
+ input.readEntityData(bytes, 0, dataSize + 512);
+ } else {
+ input.readEntityData(new byte[512], 0, 512); // skip TAR header
+ bytes = new byte[dataSize];
+ input.readEntityData(bytes, 0, dataSize);
+ }
+
+ return bytes;
+ }
+
+ private File createFile(String fileName) throws IOException {
+ File file = new File(mFilesDir, fileName);
+ file.createNewFile();
+ return file;
+ }
+
+ /**
+ * Sets the last modified time of the {@code file} to the current time to edit the file's
+ * metadata.
+ */
+ private void modifyFileMetadata(File file) throws IOException {
+ Files.setLastModifiedTime(file.toPath(), FileTime.fromMillis(System.currentTimeMillis()));
+ }
+
+ private File createApkFileAndWrite(byte[] data) throws IOException {
+ File apkFile = new File(mFilesDir, "apk");
+ apkFile.createNewFile();
+ Files.write(apkFile.toPath(), data);
+ return apkFile;
+ }
+
+ /** Creates an .obb file in the input directory. */
+ private File createObbFileAndWrite(File obbDir, byte[] data) throws IOException {
+ File obbFile = new File(obbDir, "obb");
+ obbFile.createNewFile();
+ Files.write(obbFile.toPath(), data);
+ return obbFile;
+ }
+
+ /**
+ * Creates a package specific obb data directory since the backup method checks for obb data
+ * there. See {@link Environment#buildExternalStorageAppObbDirs(String)}.
+ */
+ private File createObbDirForPackage(String packageName) {
+ ShadowEnvironment.addExternalDir("test");
+ Environment.UserEnvironment userEnv =
+ new Environment.UserEnvironment(UserHandle.USER_SYSTEM);
+ File obbDir =
+ new File(
+ userEnv.getExternalDirs()[0],
+ Environment.DIR_ANDROID + "/obb/" + packageName);
+ obbDir.mkdirs();
+ return obbDir;
+ }
+}
diff --git a/services/robotests/src/com/android/server/backup/keyvalue/KeyValueBackupTaskTest.java b/services/robotests/src/com/android/server/backup/keyvalue/KeyValueBackupTaskTest.java
index 82d7ab89ee20..b4bc9d199cb0 100644
--- a/services/robotests/src/com/android/server/backup/keyvalue/KeyValueBackupTaskTest.java
+++ b/services/robotests/src/com/android/server/backup/keyvalue/KeyValueBackupTaskTest.java
@@ -819,7 +819,7 @@ public class KeyValueBackupTaskTest {
}
@Test
- public void testRunTask_whenAgentOnBackupThrows_updatesAndCleansUpFiles() throws Exception {
+ public void testRunTask_whenAgentOnBackupThrows_updatesFilesAndCleansUp() throws Exception {
TransportMock transportMock = setUpInitializedTransport(mTransport);
AgentMock agentMock = setUpAgent(PACKAGE_1);
remoteAgentOnBackupThrows(
@@ -834,8 +834,7 @@ public class KeyValueBackupTaskTest {
assertThat(Files.readAllBytes(getStateFile(mTransport, PACKAGE_1)))
.isEqualTo("oldState".getBytes());
- assertThat(Files.exists(getTemporaryStateFile(mTransport, PACKAGE_1))).isFalse();
- assertThat(Files.exists(getStagingFile(PACKAGE_1))).isFalse();
+ assertCleansUpFilesAndAgent(mTransport, PACKAGE_1);
}
@Test
@@ -914,7 +913,7 @@ public class KeyValueBackupTaskTest {
}
@Test
- public void testRunTask_whenAgentUsesProhibitedKey_updatesAndCleansUpFiles() throws Exception {
+ public void testRunTask_whenAgentUsesProhibitedKey_updatesFilesAndCleansUp() throws Exception {
TransportMock transportMock = setUpInitializedTransport(mTransport);
AgentMock agentMock = setUpAgent(PACKAGE_1);
agentOnBackupDo(
@@ -931,8 +930,7 @@ public class KeyValueBackupTaskTest {
assertThat(Files.readAllBytes(getStateFile(mTransport, PACKAGE_1)))
.isEqualTo("oldState".getBytes());
- assertThat(Files.exists(getTemporaryStateFile(mTransport, PACKAGE_1))).isFalse();
- assertThat(Files.exists(getStagingFile(PACKAGE_1))).isFalse();
+ assertCleansUpFilesAndAgent(mTransport, PACKAGE_1);
}
@Test
@@ -1094,7 +1092,7 @@ public class KeyValueBackupTaskTest {
}
@Test
- public void testRunTask_whenAgentDoesNotWriteData_updatesAndCleansUpFiles() throws Exception {
+ public void testRunTask_whenAgentDoesNotWriteData_updatesFilesAndCleansUp() throws Exception {
TransportMock transportMock = setUpInitializedTransport(mTransport);
AgentMock agentMock = setUpAgent(PACKAGE_1);
agentOnBackupDo(
@@ -1107,8 +1105,7 @@ public class KeyValueBackupTaskTest {
runTask(task);
assertThat(Files.readAllBytes(getStateFile(mTransport, PACKAGE_1))).isEqualTo(new byte[0]);
- assertThat(Files.exists(getTemporaryStateFile(mTransport, PACKAGE_1))).isFalse();
- assertThat(Files.exists(getStagingFile(PACKAGE_1))).isFalse();
+ assertCleansUpFilesAndAgent(mTransport, PACKAGE_1);
}
@Test
@@ -1159,7 +1156,7 @@ public class KeyValueBackupTaskTest {
}
@Test
- public void testRunTask_whenFinishBackupSucceeds_updatesAndCleansUpFiles() throws Exception {
+ public void testRunTask_whenFinishBackupSucceeds_updatesFilesAndCleansUp() throws Exception {
TransportMock transportMock = setUpInitializedTransport(mTransport);
when(transportMock.transport.finishBackup()).thenReturn(BackupTransport.TRANSPORT_OK);
AgentMock agentMock = setUpAgent(PACKAGE_1);
@@ -1175,8 +1172,7 @@ public class KeyValueBackupTaskTest {
assertThat(Files.readAllBytes(getStateFile(mTransport, PACKAGE_1)))
.isEqualTo("newState".getBytes());
- assertThat(Files.exists(getTemporaryStateFile(mTransport, PACKAGE_1))).isFalse();
- assertThat(Files.exists(getStagingFile(PACKAGE_1))).isFalse();
+ assertCleansUpFilesAndAgent(mTransport, PACKAGE_1);
}
@Test
@@ -1236,7 +1232,7 @@ public class KeyValueBackupTaskTest {
}
@Test
- public void testRunTask_whenTransportRejectsPackage_updatesAndCleansUpFiles() throws Exception {
+ public void testRunTask_whenTransportRejectsPackage_updatesFilesAndCleansUp() throws Exception {
TransportMock transportMock = setUpInitializedTransport(mTransport);
when(transportMock.transport.performBackup(
argThat(packageInfo(PACKAGE_1)), any(), anyInt()))
@@ -1249,8 +1245,7 @@ public class KeyValueBackupTaskTest {
assertThat(Files.readAllBytes(getStateFile(mTransport, PACKAGE_1)))
.isEqualTo("oldState".getBytes());
- assertThat(Files.exists(getTemporaryStateFile(mTransport, PACKAGE_1))).isFalse();
- assertThat(Files.exists(getStagingFile(PACKAGE_1))).isFalse();
+ assertCleansUpFilesAndAgent(mTransport, PACKAGE_1);
}
@Test
@@ -1350,7 +1345,9 @@ public class KeyValueBackupTaskTest {
runTask(task);
- verify(agentMock.agent).onQuotaExceeded(anyLong(), eq(1234L));
+ InOrder inOrder = inOrder(agentMock.agent, mBackupManagerService);
+ inOrder.verify(agentMock.agent).onQuotaExceeded(anyLong(), eq(1234L));
+ inOrder.verify(mBackupManagerService).unbindAgent(argThat(applicationInfo(PACKAGE_1)));
}
@Test
@@ -1397,8 +1394,7 @@ public class KeyValueBackupTaskTest {
runTask(task);
- assertThat(Files.exists(getTemporaryStateFile(mTransport, PACKAGE_1))).isFalse();
- assertThat(Files.exists(getStagingFile(PACKAGE_1))).isFalse();
+ assertCleansUpFilesAndAgent(mTransport, PACKAGE_1);
}
@Test
@@ -1413,8 +1409,7 @@ public class KeyValueBackupTaskTest {
runTask(task);
assertThat(isFileNonEmpty(getStateFile(mTransport, PACKAGE_1))).isFalse();
- assertThat(Files.exists(getTemporaryStateFile(mTransport, PACKAGE_1))).isFalse();
- assertThat(Files.exists(getStagingFile(PACKAGE_1))).isFalse();
+ assertCleansUpFilesAndAgent(mTransport, PACKAGE_1);
}
@Test
@@ -1671,7 +1666,7 @@ public class KeyValueBackupTaskTest {
}
@Test
- public void testRunTask_whenTransportReturnsError_updatesAndCleansUpFiles() throws Exception {
+ public void testRunTask_whenTransportReturnsError_updatesFilesAndCleansUp() throws Exception {
TransportMock transportMock = setUpInitializedTransport(mTransport);
when(transportMock.transport.performBackup(
argThat(packageInfo(PACKAGE_1)), any(), anyInt()))
@@ -1684,8 +1679,7 @@ public class KeyValueBackupTaskTest {
assertThat(Files.readAllBytes(getStateFile(mTransport, PACKAGE_1)))
.isEqualTo("oldState".getBytes());
- assertThat(Files.exists(getTemporaryStateFile(mTransport, PACKAGE_1))).isFalse();
- assertThat(Files.exists(getStagingFile(PACKAGE_1))).isFalse();
+ assertCleansUpFilesAndAgent(mTransport, PACKAGE_1);
}
@Test
@@ -1733,20 +1727,54 @@ public class KeyValueBackupTaskTest {
}
@Test
- public void testRunTask_whenReadingBackupDataThrows() throws Exception {
+ public void testRunTask_whenReadingBackupDataThrows_reportsCorrectly() throws Exception {
TransportMock transportMock = setUpInitializedTransport(mTransport);
setUpAgentWithData(PACKAGE_1);
- AgentMock agentMock = setUpAgentWithData(PACKAGE_2);
- KeyValueBackupTask task = createKeyValueBackupTask(transportMock, PACKAGE_1, PACKAGE_2);
+ KeyValueBackupTask task = createKeyValueBackupTask(transportMock, PACKAGE_1);
// We don't validate PM's data, so it will only throw in PACKAGE_1
ShadowBackupDataInput.throwInNextHeaderRead();
runTask(task);
verify(mReporter).onReadAgentDataError(eq(PACKAGE_1.packageName), any());
+ }
+
+ @Test
+ public void testRunTask_whenReadingBackupDataThrows_doesNotCallTransport() throws Exception {
+ TransportMock transportMock = setUpInitializedTransport(mTransport);
+ setUpAgentWithData(PACKAGE_1);
+ KeyValueBackupTask task = createKeyValueBackupTask(transportMock, PACKAGE_1);
+ ShadowBackupDataInput.throwInNextHeaderRead();
+
+ runTask(task);
+
verify(transportMock.transport, never())
.performBackup(argThat(packageInfo(PACKAGE_1)), any(), anyInt());
+ }
+
+ @Test
+ public void testRunTask_whenReadingBackupDataThrows_doesNotCallSecondAgent() throws Exception {
+ TransportMock transportMock = setUpInitializedTransport(mTransport);
+ setUpAgentWithData(PACKAGE_1);
+ AgentMock agentMock = setUpAgentWithData(PACKAGE_2);
+ KeyValueBackupTask task = createKeyValueBackupTask(transportMock, PACKAGE_1, PACKAGE_2);
+ ShadowBackupDataInput.throwInNextHeaderRead();
+
+ runTask(task);
+
verify(agentMock.agent, never()).onBackup(any(), any(), any());
+ }
+
+ @Test
+ public void testRunTask_whenReadingBackupDataThrows_cleansUpAndRevertsTask() throws Exception {
+ TransportMock transportMock = setUpInitializedTransport(mTransport);
+ setUpAgentsWithData(PACKAGE_1, PACKAGE_2);
+ KeyValueBackupTask task = createKeyValueBackupTask(transportMock, PACKAGE_1, PACKAGE_2);
+ ShadowBackupDataInput.throwInNextHeaderRead();
+
+ runTask(task);
+
+ assertCleansUpFiles(mTransport, PACKAGE_2);
assertTaskReverted(transportMock, PACKAGE_1, PACKAGE_2);
}
@@ -2385,6 +2413,16 @@ public class KeyValueBackupTaskTest {
assertThat(data1).isEqualTo(value);
}
+ private void assertCleansUpFilesAndAgent(TransportData transport, PackageData packageData) {
+ assertCleansUpFiles(transport, packageData);
+ verify(mBackupManagerService).unbindAgent(argThat(applicationInfo(packageData)));
+ }
+
+ private void assertCleansUpFiles(TransportData transport, PackageData packageData) {
+ assertThat(Files.exists(getTemporaryStateFile(transport, packageData))).isFalse();
+ assertThat(Files.exists(getStagingFile(packageData))).isFalse();
+ }
+
/**
* Put conditions that should *always* be true after task execution.
*
diff --git a/services/robotests/src/com/android/server/testing/shadows/ShadowBackupDataOutput.java b/services/robotests/src/com/android/server/testing/shadows/ShadowBackupDataOutput.java
index ca0400832345..5812c3c85a58 100644
--- a/services/robotests/src/com/android/server/testing/shadows/ShadowBackupDataOutput.java
+++ b/services/robotests/src/com/android/server/testing/shadows/ShadowBackupDataOutput.java
@@ -55,6 +55,11 @@ public class ShadowBackupDataOutput {
return mTransportFlags;
}
+ public ObjectOutputStream getOutputStream() {
+ ensureOutput();
+ return mOutput;
+ }
+
@Implementation
public int writeEntityHeader(String key, int dataSize) throws IOException {
ensureOutput();
diff --git a/services/robotests/src/com/android/server/testing/shadows/ShadowFullBackup.java b/services/robotests/src/com/android/server/testing/shadows/ShadowFullBackup.java
new file mode 100644
index 000000000000..3c913e317375
--- /dev/null
+++ b/services/robotests/src/com/android/server/testing/shadows/ShadowFullBackup.java
@@ -0,0 +1,70 @@
+package com.android.server.testing.shadows;
+
+import android.app.backup.BackupDataOutput;
+import android.app.backup.FullBackup;
+import android.app.backup.FullBackupDataOutput;
+
+import org.robolectric.annotation.Implementation;
+import org.robolectric.annotation.Implements;
+import org.robolectric.shadow.api.Shadow;
+
+import java.io.IOException;
+import java.io.ObjectOutputStream;
+import java.nio.ByteBuffer;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+
+/**
+ * Shadow for {@link FullBackup}. Used to emulate the native method {@link
+ * FullBackup#backupToTar(String, String, String, String, String, FullBackupDataOutput)}. Relies on
+ * the shadow {@link ShadowBackupDataOutput}, which must be included in tests that use this shadow.
+ */
+@Implements(FullBackup.class)
+public class ShadowFullBackup {
+ /**
+ * Reads data from the specified file at {@code path} and writes it to the {@code output}. Does
+ * not match the native implementation, and only partially simulates TAR format. Used solely for
+ * passing backup data for testing purposes.
+ *
+ * <p>Note: Only handles the {@code path} denoting a file and not a directory like the real
+ * implementation.
+ */
+ @Implementation
+ public static int backupToTar(
+ String packageName,
+ String domain,
+ String linkdomain,
+ String rootpath,
+ String path,
+ FullBackupDataOutput output) {
+ BackupDataOutput backupDataOutput = output.getData();
+ try {
+ Path file = Paths.get(path);
+ byte[] data = Files.readAllBytes(file);
+ backupDataOutput.writeEntityHeader("key", data.length);
+
+ // Partially simulate TAR header (not all fields included). We use a 512 byte block for
+ // the header to follow the TAR convention and to have a consistent size block to help
+ // with separating the header from the data.
+ ByteBuffer tarBlock = ByteBuffer.wrap(new byte[512]);
+ String tarPath = "apps/" + packageName + (domain == null ? "" : "/" + domain) + path;
+ tarBlock.put(tarPath.getBytes()); // file path
+ tarBlock.putInt(0x1ff); // file mode
+ tarBlock.putLong(Files.size(file)); // file size
+ tarBlock.putLong(Files.getLastModifiedTime(file).toMillis()); // last modified time
+ tarBlock.putInt(0); // file type
+
+ // Write TAR header directly to the BackupDataOutput's output stream.
+ ShadowBackupDataOutput shadowBackupDataOutput = Shadow.extract(backupDataOutput);
+ ObjectOutputStream outputStream = shadowBackupDataOutput.getOutputStream();
+ outputStream.write(tarBlock.array());
+ outputStream.flush();
+
+ backupDataOutput.writeEntityData(data, data.length);
+ } catch (IOException e) {
+ throw new AssertionError(e);
+ }
+ return 0;
+ }
+}
diff --git a/services/tests/mockingservicestests/Android.mk b/services/tests/mockingservicestests/Android.mk
index 34de9dfb7ad6..8c0283318419 100644
--- a/services/tests/mockingservicestests/Android.mk
+++ b/services/tests/mockingservicestests/Android.mk
@@ -20,22 +20,21 @@ LOCAL_MODULE_TAGS := tests
LOCAL_SRC_FILES := $(call all-java-files-under, src)
LOCAL_STATIC_JAVA_LIBRARIES := \
- services.core \
- services.devicepolicy \
frameworks-base-testutils \
+ services.core \
androidx-test \
mockito-target-extended-minus-junit4 \
+ platform-test-annotations \
ShortcutManagerTestUtils \
- compatibility-device-util \
- truth-prebuilt
+ truth-prebuilt \
-LOCAL_JAVA_LIBRARIES := \
- android.test.mock
+LOCAL_JAVA_LIBRARIES := android.test.mock android.test.base android.test.runner
LOCAL_JNI_SHARED_LIBRARIES := \
libdexmakerjvmtiagent \
- libstaticjvmtiagent
+ libstaticjvmtiagent \
+LOCAL_CERTIFICATE := platform
LOCAL_PACKAGE_NAME := FrameworksMockingServicesTests
LOCAL_PRIVATE_PLATFORM_APIS := true
LOCAL_COMPATIBILITY_SUITE := device-tests
diff --git a/services/tests/mockingservicestests/AndroidManifest.xml b/services/tests/mockingservicestests/AndroidManifest.xml
index 247e446d1bfc..c9aa63153a5d 100644
--- a/services/tests/mockingservicestests/AndroidManifest.xml
+++ b/services/tests/mockingservicestests/AndroidManifest.xml
@@ -17,7 +17,10 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.android.frameworks.mockingservicestests">
- <application android:debuggable="true">
+ <uses-permission android:name="android.permission.INTERACT_ACROSS_USERS_FULL" />
+
+ <application android:testOnly="true"
+ android:debuggable="true">
<uses-library android:name="android.test.runner" />
</application>
diff --git a/services/tests/mockingservicestests/AndroidTest.xml b/services/tests/mockingservicestests/AndroidTest.xml
index adfee96d4e28..7782d570856f 100644
--- a/services/tests/mockingservicestests/AndroidTest.xml
+++ b/services/tests/mockingservicestests/AndroidTest.xml
@@ -19,6 +19,7 @@
<target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
<option name="cleanup-apks" value="true" />
+ <option name="install-arg" value="-t" />
<option name="test-file-name" value="FrameworksMockingServicesTests.apk" />
</target_preparer>
diff --git a/services/tests/mockingservicestests/src/com/android/server/AlarmManagerServiceTest.java b/services/tests/mockingservicestests/src/com/android/server/AlarmManagerServiceTest.java
new file mode 100644
index 000000000000..de3d285cd23a
--- /dev/null
+++ b/services/tests/mockingservicestests/src/com/android/server/AlarmManagerServiceTest.java
@@ -0,0 +1,374 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.server;
+
+import static android.app.AlarmManager.ELAPSED_REALTIME_WAKEUP;
+import static android.app.usage.UsageStatsManager.STANDBY_BUCKET_ACTIVE;
+import static android.app.usage.UsageStatsManager.STANDBY_BUCKET_FREQUENT;
+import static android.app.usage.UsageStatsManager.STANDBY_BUCKET_RARE;
+import static android.app.usage.UsageStatsManager.STANDBY_BUCKET_WORKING_SET;
+
+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;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.spy;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.timeout;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.when;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.anyLong;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.ArgumentMatchers.isNull;
+
+import android.app.ActivityManager;
+import android.app.AlarmManager;
+import android.app.IActivityManager;
+import android.app.IUidObserver;
+import android.app.PendingIntent;
+import android.app.usage.UsageStatsManagerInternal;
+import android.content.Context;
+import android.content.Intent;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.PowerManager;
+import android.os.SystemClock;
+import android.os.UserHandle;
+import android.util.Log;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Answers;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mock;
+import org.mockito.MockitoSession;
+
+import javax.annotation.concurrent.GuardedBy;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class AlarmManagerServiceTest {
+ private static final String TAG = AlarmManagerServiceTest.class.getSimpleName();
+ private static final String TEST_CALLING_PACKAGE = "com.android.framework.test-package";
+ private static final int SYSTEM_UI_UID = 123456789;
+ private static final int TEST_CALLING_UID = 12345;
+ private static final long DEFAULT_TIMEOUT = 5_000;
+
+ private AlarmManagerService mService;
+ @Mock
+ private IActivityManager mIActivityManager;
+ @Mock
+ private UsageStatsManagerInternal mUsageStatsManagerInternal;
+ @Mock
+ private AppStateTracker mAppStateTracker;
+ @Mock
+ private AlarmManagerService.ClockReceiver mClockReceiver;
+ @Mock
+ private PowerManager.WakeLock mWakeLock;
+
+ private MockitoSession mMockingSession;
+ private Injector mInjector;
+ private volatile long mNowElapsedTest;
+ @GuardedBy("mTestTimer")
+ private TestTimer mTestTimer = new TestTimer();
+
+ static class TestTimer {
+ private long mElapsed;
+ boolean mExpired;
+
+ synchronized long getElapsed() {
+ return mElapsed;
+ }
+
+ synchronized void set(long millisElapsed) {
+ mElapsed = millisElapsed;
+ }
+
+ synchronized long expire() {
+ mExpired = true;
+ notify();
+ return mElapsed;
+ }
+ }
+
+ public class Injector extends AlarmManagerService.Injector {
+ Injector(Context context) {
+ super(context);
+ }
+
+ @Override
+ void init() {
+ // Do nothing.
+ }
+
+ @Override
+ int waitForAlarm() {
+ synchronized (mTestTimer) {
+ if (!mTestTimer.mExpired) {
+ try {
+ mTestTimer.wait();
+ } catch (InterruptedException ie) {
+ Log.e(TAG, "Wait interrupted!", ie);
+ return 0;
+ }
+ }
+ mTestTimer.mExpired = false;
+ }
+ return AlarmManagerService.IS_WAKEUP_MASK; // Doesn't matter, just evaluate.
+ }
+
+ @Override
+ void setKernelTimezone(int minutesWest) {
+ // Do nothing.
+ }
+
+ @Override
+ void setAlarm(int type, long millis) {
+ mTestTimer.set(millis);
+ }
+
+ @Override
+ void setKernelTime(long millis) {
+ }
+
+ @Override
+ int getSystemUiUid() {
+ return SYSTEM_UI_UID;
+ }
+
+ @Override
+ boolean isAlarmDriverPresent() {
+ // Pretend the driver is present, so code does not fall back to handler
+ return true;
+ }
+
+ @Override
+ long getElapsedRealtime() {
+ return mNowElapsedTest;
+ }
+
+ @Override
+ AlarmManagerService.ClockReceiver getClockReceiver(AlarmManagerService service) {
+ return mClockReceiver;
+ }
+
+ @Override
+ PowerManager.WakeLock getAlarmWakeLock() {
+ return mWakeLock;
+ }
+ }
+
+ @Before
+ public final void setUp() throws Exception {
+ mMockingSession = mockitoSession()
+ .initMocks(this)
+ .mockStatic(ActivityManager.class, Answers.CALLS_REAL_METHODS)
+ .mockStatic(LocalServices.class)
+ .mockStatic(Looper.class, Answers.CALLS_REAL_METHODS)
+ .startMocking();
+ doReturn(mIActivityManager).when(ActivityManager::getService);
+ doReturn(mAppStateTracker).when(() -> LocalServices.getService(AppStateTracker.class));
+ doReturn(null)
+ .when(() -> LocalServices.getService(DeviceIdleController.LocalService.class));
+ doReturn(mUsageStatsManagerInternal).when(
+ () -> LocalServices.getService(UsageStatsManagerInternal.class));
+ when(mUsageStatsManagerInternal.getAppStandbyBucket(eq(TEST_CALLING_PACKAGE),
+ eq(UserHandle.getUserId(TEST_CALLING_UID)), anyLong()))
+ .thenReturn(STANDBY_BUCKET_ACTIVE);
+ doReturn(Looper.getMainLooper()).when(Looper::myLooper);
+
+ final Context context = InstrumentationRegistry.getTargetContext();
+ mInjector = spy(new Injector(context));
+ mService = new AlarmManagerService(context, mInjector);
+ spyOn(mService);
+ doNothing().when(mService).publishBinderService(any(), any());
+ mService.onStart();
+ mService.onBootPhase(SystemService.PHASE_SYSTEM_SERVICES_READY);
+ mService.mConstants.MIN_FUTURITY = 0;
+
+ assertEquals(mService.mSystemUiUid, SYSTEM_UI_UID);
+ assertEquals(mService.mClockReceiver, mClockReceiver);
+ assertEquals(mService.mWakeLock, mWakeLock);
+ verify(mIActivityManager).registerUidObserver(any(IUidObserver.class), anyInt(), anyInt(),
+ isNull());
+ }
+
+ private void setTestAlarm(int type, long triggerTime, PendingIntent operation) {
+ mService.setImpl(type, triggerTime, AlarmManager.WINDOW_EXACT, 0,
+ operation, null, "test", AlarmManager.FLAG_STANDALONE, null, null,
+ TEST_CALLING_UID, TEST_CALLING_PACKAGE);
+ }
+
+ private PendingIntent getNewMockPendingIntent() {
+ final PendingIntent mockPi = mock(PendingIntent.class, Answers.RETURNS_DEEP_STUBS);
+ when(mockPi.getCreatorUid()).thenReturn(TEST_CALLING_UID);
+ when(mockPi.getCreatorPackage()).thenReturn(TEST_CALLING_PACKAGE);
+ return mockPi;
+ }
+
+ @Test
+ public void testSingleAlarmSet() {
+ final long triggerTime = mNowElapsedTest + 5000;
+ final PendingIntent alarmPi = getNewMockPendingIntent();
+ setTestAlarm(ELAPSED_REALTIME_WAKEUP, triggerTime, alarmPi);
+ verify(mInjector).setAlarm(ELAPSED_REALTIME_WAKEUP, triggerTime);
+ assertEquals(triggerTime, mTestTimer.getElapsed());
+ }
+
+ @Test
+ public void testSingleAlarmExpiration() throws Exception {
+ final long triggerTime = mNowElapsedTest + 5000;
+ final PendingIntent alarmPi = getNewMockPendingIntent();
+ setTestAlarm(ELAPSED_REALTIME_WAKEUP, triggerTime, alarmPi);
+
+ mNowElapsedTest = mTestTimer.expire();
+
+ final ArgumentCaptor<PendingIntent.OnFinished> onFinishedCaptor =
+ ArgumentCaptor.forClass(PendingIntent.OnFinished.class);
+ verify(alarmPi, timeout(DEFAULT_TIMEOUT)).send(any(Context.class), eq(0),
+ any(Intent.class), onFinishedCaptor.capture(), any(Handler.class), isNull(), any());
+ verify(mWakeLock, timeout(DEFAULT_TIMEOUT)).acquire();
+ onFinishedCaptor.getValue().onSendFinished(alarmPi, null, 0, null, null);
+ verify(mWakeLock, timeout(DEFAULT_TIMEOUT)).release();
+ }
+
+ @Test
+ public void testMinFuturity() {
+ mService.mConstants.MIN_FUTURITY = 10;
+ final long triggerTime = mNowElapsedTest + 1;
+ final long expectedTriggerTime = mNowElapsedTest + mService.mConstants.MIN_FUTURITY;
+ setTestAlarm(ELAPSED_REALTIME_WAKEUP, triggerTime, getNewMockPendingIntent());
+ verify(mInjector).setAlarm(ELAPSED_REALTIME_WAKEUP, expectedTriggerTime);
+ }
+
+ @Test
+ public void testEarliestAlarmSet() {
+ final PendingIntent pi6 = getNewMockPendingIntent();
+ final PendingIntent pi8 = getNewMockPendingIntent();
+ final PendingIntent pi9 = getNewMockPendingIntent();
+
+ setTestAlarm(ELAPSED_REALTIME_WAKEUP, mNowElapsedTest + 8, pi8);
+ assertEquals(mNowElapsedTest + 8, mTestTimer.getElapsed());
+
+ setTestAlarm(ELAPSED_REALTIME_WAKEUP, mNowElapsedTest + 9, pi9);
+ assertEquals(mNowElapsedTest + 8, mTestTimer.getElapsed());
+
+ setTestAlarm(ELAPSED_REALTIME_WAKEUP, mNowElapsedTest + 6, pi6);
+ assertEquals(mNowElapsedTest + 6, mTestTimer.getElapsed());
+
+ mService.removeLocked(pi6, null);
+ assertEquals(mNowElapsedTest + 8, mTestTimer.getElapsed());
+
+ mService.removeLocked(pi8, null);
+ assertEquals(mNowElapsedTest + 9, mTestTimer.getElapsed());
+ }
+
+ @Test
+ public void testStandbyBucketDelay_workingSet() throws Exception {
+ setTestAlarm(ELAPSED_REALTIME_WAKEUP, mNowElapsedTest + 5, getNewMockPendingIntent());
+ setTestAlarm(ELAPSED_REALTIME_WAKEUP, mNowElapsedTest + 6, getNewMockPendingIntent());
+ assertEquals(mNowElapsedTest + 5, mTestTimer.getElapsed());
+
+ when(mUsageStatsManagerInternal.getAppStandbyBucket(eq(TEST_CALLING_PACKAGE), anyInt(),
+ anyLong())).thenReturn(STANDBY_BUCKET_WORKING_SET);
+ mNowElapsedTest = mTestTimer.expire();
+ verify(mUsageStatsManagerInternal, timeout(DEFAULT_TIMEOUT).atLeastOnce())
+ .getAppStandbyBucket(eq(TEST_CALLING_PACKAGE),
+ eq(UserHandle.getUserId(TEST_CALLING_UID)), anyLong());
+ final long expectedNextTrigger = mNowElapsedTest
+ + mService.getMinDelayForBucketLocked(STANDBY_BUCKET_WORKING_SET);
+ assertTrue("Incorrect next alarm trigger. Expected " + expectedNextTrigger + " found: "
+ + mTestTimer.getElapsed(), pollingCheck(DEFAULT_TIMEOUT,
+ () -> (mTestTimer.getElapsed() == expectedNextTrigger)));
+ }
+
+ @Test
+ public void testStandbyBucketDelay_frequent() {
+ setTestAlarm(ELAPSED_REALTIME_WAKEUP, mNowElapsedTest + 5, getNewMockPendingIntent());
+ setTestAlarm(ELAPSED_REALTIME_WAKEUP, mNowElapsedTest + 6, getNewMockPendingIntent());
+ assertEquals(mNowElapsedTest + 5, mTestTimer.getElapsed());
+
+ when(mUsageStatsManagerInternal.getAppStandbyBucket(eq(TEST_CALLING_PACKAGE), anyInt(),
+ anyLong())).thenReturn(STANDBY_BUCKET_FREQUENT);
+ mNowElapsedTest = mTestTimer.expire();
+ verify(mUsageStatsManagerInternal, timeout(DEFAULT_TIMEOUT).atLeastOnce())
+ .getAppStandbyBucket(eq(TEST_CALLING_PACKAGE),
+ eq(UserHandle.getUserId(TEST_CALLING_UID)), anyLong());
+ final long expectedNextTrigger = mNowElapsedTest
+ + mService.getMinDelayForBucketLocked(STANDBY_BUCKET_FREQUENT);
+ assertTrue("Incorrect next alarm trigger. Expected " + expectedNextTrigger + " found: "
+ + mTestTimer.getElapsed(), pollingCheck(DEFAULT_TIMEOUT,
+ () -> (mTestTimer.getElapsed() == expectedNextTrigger)));
+ }
+
+ @Test
+ public void testStandbyBucketDelay_rare() {
+ setTestAlarm(ELAPSED_REALTIME_WAKEUP, mNowElapsedTest + 5, getNewMockPendingIntent());
+ setTestAlarm(ELAPSED_REALTIME_WAKEUP, mNowElapsedTest + 6, getNewMockPendingIntent());
+ assertEquals(mNowElapsedTest + 5, mTestTimer.getElapsed());
+
+ when(mUsageStatsManagerInternal.getAppStandbyBucket(eq(TEST_CALLING_PACKAGE), anyInt(),
+ anyLong())).thenReturn(STANDBY_BUCKET_RARE);
+ mNowElapsedTest = mTestTimer.expire();
+ verify(mUsageStatsManagerInternal, timeout(DEFAULT_TIMEOUT).atLeastOnce())
+ .getAppStandbyBucket(eq(TEST_CALLING_PACKAGE),
+ eq(UserHandle.getUserId(TEST_CALLING_UID)), anyLong());
+ final long expectedNextTrigger = mNowElapsedTest
+ + mService.getMinDelayForBucketLocked(STANDBY_BUCKET_RARE);
+ assertTrue("Incorrect next alarm trigger. Expected " + expectedNextTrigger + " found: "
+ + mTestTimer.getElapsed(), pollingCheck(DEFAULT_TIMEOUT,
+ () -> (mTestTimer.getElapsed() == expectedNextTrigger)));
+ }
+
+ @After
+ public void tearDown() {
+ if (mMockingSession != null) {
+ mMockingSession.finishMocking();
+ }
+ }
+
+ private boolean pollingCheck(long timeout, Condition condition) {
+ final long deadline = SystemClock.uptimeMillis() + timeout;
+ boolean interrupted = false;
+ while (!condition.check() && SystemClock.uptimeMillis() < deadline) {
+ try {
+ Thread.sleep(500);
+ } catch (InterruptedException ie) {
+ interrupted = true;
+ }
+ }
+ if (interrupted) {
+ Thread.currentThread().interrupt();
+ }
+ return condition.check();
+ }
+
+ @FunctionalInterface
+ interface Condition {
+ boolean check();
+ }
+}
diff --git a/services/tests/servicestests/Android.mk b/services/tests/servicestests/Android.mk
index 43f319e8ccd6..80307eebf53b 100644
--- a/services/tests/servicestests/Android.mk
+++ b/services/tests/servicestests/Android.mk
@@ -9,7 +9,9 @@ include $(CLEAR_VARS)
LOCAL_MODULE_TAGS := tests
# Include all test java files.
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
+LOCAL_SRC_FILES := \
+ $(call all-java-files-under, src) \
+ $(call all-java-files-under, utils) \
LOCAL_STATIC_JAVA_LIBRARIES := \
frameworks-base-testutils \
diff --git a/services/tests/servicestests/AndroidManifest.xml b/services/tests/servicestests/AndroidManifest.xml
index 348e2015c7c0..863e48792c0d 100644
--- a/services/tests/servicestests/AndroidManifest.xml
+++ b/services/tests/servicestests/AndroidManifest.xml
@@ -143,7 +143,8 @@
<activity android:name="com.android.server.pm.BaseShortcutManagerTest$ShortcutActivity2" />
<activity android:name="com.android.server.pm.BaseShortcutManagerTest$ShortcutActivity3" />
- <activity android:name="com.android.server.wm.ScreenDecorWindowTests$TestActivity" />
+ <activity android:name="com.android.server.wm.ScreenDecorWindowTests$TestActivity"
+ android:showWhenLocked="true"/>
<activity android:name="com.android.server.pm.ShortcutTestActivity"
android:enabled="true" android:exported="true" />
diff --git a/services/tests/servicestests/src/com/android/server/AlarmManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/BackgroundRestrictedAlarmsTest.java
index 1f63d6165617..d248b8902e35 100644
--- a/services/tests/servicestests/src/com/android/server/AlarmManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/BackgroundRestrictedAlarmsTest.java
@@ -35,14 +35,13 @@ import java.util.ArrayList;
@SmallTest
@RunWith(AndroidJUnit4.class)
-public class AlarmManagerServiceTest {
+public class BackgroundRestrictedAlarmsTest {
private SparseArray<ArrayList<Alarm>> addPendingAlarm(
SparseArray<ArrayList<Alarm>> all, int uid, String name, boolean removeIt) {
ArrayList<Alarm> uidAlarms = all.get(uid);
if (uidAlarms == null) {
all.put(uid, uidAlarms = new ArrayList<>());
}
- // Details don't matter.
uidAlarms.add(new Alarm(
removeIt ? RTC : RTC_WAKEUP,
0, 0, 0, 0, 0, null, null, null, null, 0, null, uid, name));
diff --git a/services/tests/servicestests/src/com/android/server/am/ActivityStackTests.java b/services/tests/servicestests/src/com/android/server/am/ActivityStackTests.java
index 59b08909bb76..1023bc1e3b0c 100644
--- a/services/tests/servicestests/src/com/android/server/am/ActivityStackTests.java
+++ b/services/tests/servicestests/src/com/android/server/am/ActivityStackTests.java
@@ -189,7 +189,7 @@ public class ActivityStackTests extends ActivityTestsBase {
assertEquals(task.getTopActivity(false /* includeOverlays */), r);
assertEquals(task.getTopActivity(true /* includeOverlays */), taskOverlay);
- assertNotNull(result.r);
+ assertNotNull(result.mRecord);
}
@Test
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 e37a6c10409d..d94a5f34517f 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
@@ -1713,24 +1713,35 @@ public class DevicePolicyManagerTest extends DpmTestBase {
UserManager.DISALLOW_ADD_USER),
eq(true), eq(CAMERA_DISABLED_GLOBALLY));
reset(getServices().userManagerInternal);
+ }
- // Set up another DA and let it disable camera. Now DISALLOW_CAMERA will only be applied
- // locally.
- dpm.setCameraDisabled(admin1, false);
- reset(getServices().userManagerInternal);
+ public void testDaDisallowedPolicies_SecurityException() throws Exception {
+ mContext.callerPermissions.add(permission.MANAGE_DEVICE_ADMINS);
+ mContext.callerPermissions.add(permission.INTERACT_ACROSS_USERS_FULL);
- setUpPackageManagerForAdmin(admin2, DpmMockContext.CALLER_SYSTEM_USER_UID);
- dpm.setActiveAdmin(admin2, /* replace =*/ false, UserHandle.USER_SYSTEM);
- dpm.setCameraDisabled(admin2, true);
+ setUpPackageManagerForAdmin(admin1, DpmMockContext.CALLER_SYSTEM_USER_UID);
+ dpm.setActiveAdmin(admin1, /* replace =*/ false, UserHandle.USER_SYSTEM);
- verify(getServices().userManagerInternal).setDevicePolicyUserRestrictions(
- eq(UserHandle.USER_SYSTEM),
- // DISALLOW_CAMERA will be applied to both local and global. <- TODO: fix this
- MockUtils.checkUserRestrictions(UserManager.DISALLOW_FUN,
- UserManager.DISALLOW_ADD_USER),
- eq(true), eq(CAMERA_DISABLED_LOCALLY));
- reset(getServices().userManagerInternal);
- // TODO Make sure restrictions are written to the file.
+ boolean originalCameraDisabled = dpm.getCameraDisabled(admin1);
+ assertExpectException(SecurityException.class, /* messageRegex= */ null,
+ () -> dpm.setCameraDisabled(admin1, true));
+ assertEquals(originalCameraDisabled, dpm.getCameraDisabled(admin1));
+
+ int originalKeyguardDisabledFeatures = dpm.getKeyguardDisabledFeatures(admin1);
+ assertExpectException(SecurityException.class, /* messageRegex= */ null,
+ () -> dpm.setKeyguardDisabledFeatures(admin1,
+ DevicePolicyManager.KEYGUARD_DISABLE_FEATURES_ALL));
+ assertEquals(originalKeyguardDisabledFeatures, dpm.getKeyguardDisabledFeatures(admin1));
+
+ long originalPasswordExpirationTimeout = dpm.getPasswordExpirationTimeout(admin1);
+ assertExpectException(SecurityException.class, /* messageRegex= */ null,
+ () -> dpm.setPasswordExpirationTimeout(admin1, 1234));
+ assertEquals(originalPasswordExpirationTimeout, dpm.getPasswordExpirationTimeout(admin1));
+
+ int originalPasswordQuality = dpm.getPasswordQuality(admin1);
+ assertExpectException(SecurityException.class, /* messageRegex= */ null,
+ () -> dpm.setPasswordQuality(admin1, DevicePolicyManager.PASSWORD_QUALITY_NUMERIC));
+ assertEquals(originalPasswordQuality, dpm.getPasswordQuality(admin1));
}
public void testSetUserRestriction_asPo() {
diff --git a/services/tests/servicestests/src/com/android/server/testutils/OffsettableClock.java b/services/tests/servicestests/utils/com/android/server/testutils/OffsettableClock.java
index 8dabbc4d4356..8dabbc4d4356 100644
--- a/services/tests/servicestests/src/com/android/server/testutils/OffsettableClock.java
+++ b/services/tests/servicestests/utils/com/android/server/testutils/OffsettableClock.java
diff --git a/services/tests/servicestests/src/com/android/server/testutils/TestHandler.java b/services/tests/servicestests/utils/com/android/server/testutils/TestHandler.java
index 1222b59e92b9..1222b59e92b9 100644
--- a/services/tests/servicestests/src/com/android/server/testutils/TestHandler.java
+++ b/services/tests/servicestests/utils/com/android/server/testutils/TestHandler.java
diff --git a/services/tests/servicestests/src/com/android/server/testutils/TestUtils.java b/services/tests/servicestests/utils/com/android/server/testutils/TestUtils.java
index b200293ee916..b200293ee916 100644
--- a/services/tests/servicestests/src/com/android/server/testutils/TestUtils.java
+++ b/services/tests/servicestests/utils/com/android/server/testutils/TestUtils.java
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 0ff124e4ce7a..a1b3b988397c 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
@@ -65,6 +65,8 @@ import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.app.ActivityManager;
+import android.app.AppOpsManager;
+import android.app.Application;
import android.app.IActivityManager;
import android.app.INotificationManager;
import android.app.Notification;
@@ -195,6 +197,8 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
IUriGrantsManager mUgm;
@Mock
UriGrantsManagerInternal mUgmInternal;
+ @Mock
+ AppOpsManager mAppOpsManager;
// Use a Testable subclass so we can simulate calls from the system without failing.
private static class TestableNotificationManagerService extends NotificationManagerService {
@@ -295,7 +299,8 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
mListeners, mAssistants, mConditionProviders,
mCompanionMgr, mSnoozeHelper, mUsageStats, mPolicyFile, mActivityManager,
mGroupHelper, mAm, mAppUsageStats,
- mock(DevicePolicyManagerInternal.class), mUgm, mUgmInternal);
+ mock(DevicePolicyManagerInternal.class), mUgm, mUgmInternal,
+ mAppOpsManager);
} catch (SecurityException e) {
if (!e.getMessage().contains("Permission Denial: not allowed to send broadcast")) {
throw e;
@@ -531,7 +536,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
mBinderService.createNotificationChannels(
PKG, new ParceledListSlice(Arrays.asList(channel)));
final StatusBarNotification sbn = generateNotificationRecord(channel).sbn;
- mBinderService.enqueueNotificationWithTag(PKG, "opPkg", "tag",
+ mBinderService.enqueueNotificationWithTag(PKG, PKG, "tag",
sbn.getId(), sbn.getNotification(), sbn.getUserId());
waitForIdle();
assertEquals(0, mBinderService.getActiveNotifications(sbn.getPackageName()).length);
@@ -549,7 +554,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
final StatusBarNotification sbn = generateNotificationRecord(channel).sbn;
sbn.getNotification().flags |= FLAG_FOREGROUND_SERVICE;
- mBinderService.enqueueNotificationWithTag(PKG, "opPkg", "tag",
+ mBinderService.enqueueNotificationWithTag(PKG, PKG, "tag",
sbn.getId(), sbn.getNotification(), sbn.getUserId());
waitForIdle();
assertEquals(1, mBinderService.getActiveNotifications(sbn.getPackageName()).length);
@@ -578,7 +583,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
StatusBarNotification sbn = generateNotificationRecord(channel).sbn;
sbn.getNotification().flags |= FLAG_FOREGROUND_SERVICE;
- mBinderService.enqueueNotificationWithTag(PKG, "opPkg", "tag",
+ mBinderService.enqueueNotificationWithTag(PKG, PKG, "tag",
sbn.getId(), sbn.getNotification(), sbn.getUserId());
waitForIdle();
// The first time a foreground service notification is shown, we allow the channel
@@ -600,7 +605,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
sbn = generateNotificationRecord(channel).sbn;
sbn.getNotification().flags |= FLAG_FOREGROUND_SERVICE;
- mBinderService.enqueueNotificationWithTag(PKG, "opPkg", "tag",
+ mBinderService.enqueueNotificationWithTag(PKG, PKG, "tag",
sbn.getId(), sbn.getNotification(), sbn.getUserId());
waitForIdle();
// The second time it is shown, we keep the user's preference.
@@ -631,7 +636,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
mBinderService.setNotificationsEnabledForPackage(PKG, mUid, false);
final StatusBarNotification sbn = generateNotificationRecord(null).sbn;
- mBinderService.enqueueNotificationWithTag(PKG, "opPkg", "tag",
+ mBinderService.enqueueNotificationWithTag(PKG, PKG, "tag",
sbn.getId(), sbn.getNotification(), sbn.getUserId());
waitForIdle();
assertEquals(0, mBinderService.getActiveNotifications(sbn.getPackageName()).length);
@@ -645,7 +650,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
final StatusBarNotification sbn = generateNotificationRecord(null).sbn;
sbn.getNotification().flags |= FLAG_FOREGROUND_SERVICE;
- mBinderService.enqueueNotificationWithTag(PKG, "opPkg", "tag",
+ mBinderService.enqueueNotificationWithTag(PKG, PKG, "tag",
sbn.getId(), sbn.getNotification(), sbn.getUserId());
waitForIdle();
assertEquals(0, mBinderService.getActiveNotifications(sbn.getPackageName()).length);
@@ -667,7 +672,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
final StatusBarNotification sbn =
generateNotificationRecord(mTestNotificationChannel, ++id, "", false).sbn;
sbn.getNotification().category = category;
- mBinderService.enqueueNotificationWithTag(PKG, "opPkg", "tag",
+ mBinderService.enqueueNotificationWithTag(PKG, PKG, "tag",
sbn.getId(), sbn.getNotification(), sbn.getUserId());
}
waitForIdle();
@@ -691,7 +696,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
final StatusBarNotification sbn =
generateNotificationRecord(mTestNotificationChannel, ++id, "", false).sbn;
sbn.getNotification().category = category;
- mBinderService.enqueueNotificationWithTag(PKG, "opPkg", "tag",
+ mBinderService.enqueueNotificationWithTag(PKG, PKG, "tag",
sbn.getId(), sbn.getNotification(), sbn.getUserId());
}
waitForIdle();
@@ -714,7 +719,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
final StatusBarNotification sbn = generateNotificationRecord(null).sbn;
sbn.getNotification().category = category;
try {
- mBinderService.enqueueNotificationWithTag(PKG, "opPkg", "tag",
+ mBinderService.enqueueNotificationWithTag(PKG, PKG, "tag",
sbn.getId(), sbn.getNotification(), sbn.getUserId());
fail("Calls from non system apps should not allow use of restricted categories");
} catch (SecurityException e) {
@@ -746,7 +751,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
@Test
public void testEnqueueNotificationWithTag_PopulatesGetActiveNotifications() throws Exception {
- mBinderService.enqueueNotificationWithTag(PKG, "opPkg", "tag", 0,
+ mBinderService.enqueueNotificationWithTag(PKG, PKG, "tag", 0,
generateNotificationRecord(null).getNotification(), 0);
waitForIdle();
StatusBarNotification[] notifs = mBinderService.getActiveNotifications(PKG);
@@ -756,7 +761,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
@Test
public void testCancelNotificationImmediatelyAfterEnqueue() throws Exception {
- mBinderService.enqueueNotificationWithTag(PKG, "opPkg", "tag", 0,
+ mBinderService.enqueueNotificationWithTag(PKG, PKG, "tag", 0,
generateNotificationRecord(null).getNotification(), 0);
mBinderService.cancelNotificationWithTag(PKG, "tag", 0, 0);
waitForIdle();
@@ -768,10 +773,10 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
@Test
public void testCancelNotificationWhilePostedAndEnqueued() throws Exception {
- mBinderService.enqueueNotificationWithTag(PKG, "opPkg", "tag", 0,
+ mBinderService.enqueueNotificationWithTag(PKG, PKG, "tag", 0,
generateNotificationRecord(null).getNotification(), 0);
waitForIdle();
- mBinderService.enqueueNotificationWithTag(PKG, "opPkg", "tag", 0,
+ mBinderService.enqueueNotificationWithTag(PKG, PKG, "tag", 0,
generateNotificationRecord(null).getNotification(), 0);
mBinderService.cancelNotificationWithTag(PKG, "tag", 0, 0);
waitForIdle();
@@ -788,7 +793,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
public void testCancelNotificationsFromListenerImmediatelyAfterEnqueue() throws Exception {
NotificationRecord r = generateNotificationRecord(null);
final StatusBarNotification sbn = r.sbn;
- mBinderService.enqueueNotificationWithTag(PKG, "opPkg", "tag",
+ mBinderService.enqueueNotificationWithTag(PKG, PKG, "tag",
sbn.getId(), sbn.getNotification(), sbn.getUserId());
mBinderService.cancelNotificationsFromListener(null, null);
waitForIdle();
@@ -801,7 +806,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
@Test
public void testCancelAllNotificationsImmediatelyAfterEnqueue() throws Exception {
final StatusBarNotification sbn = generateNotificationRecord(null).sbn;
- mBinderService.enqueueNotificationWithTag(PKG, "opPkg", "tag",
+ mBinderService.enqueueNotificationWithTag(PKG, PKG, "tag",
sbn.getId(), sbn.getNotification(), sbn.getUserId());
mBinderService.cancelAllNotifications(PKG, sbn.getUserId());
waitForIdle();
@@ -816,7 +821,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
final NotificationRecord n = generateNotificationRecord(
mTestNotificationChannel, 1, "group", true);
- mBinderService.enqueueNotificationWithTag(PKG, "opPkg", "tag",
+ mBinderService.enqueueNotificationWithTag(PKG, PKG, "tag",
n.sbn.getId(), n.sbn.getNotification(), n.sbn.getUserId());
waitForIdle();
@@ -839,9 +844,9 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
final NotificationRecord child = generateNotificationRecord(
mTestNotificationChannel, 2, "group1", false);
- mBinderService.enqueueNotificationWithTag(PKG, "opPkg", "tag",
+ mBinderService.enqueueNotificationWithTag(PKG, PKG, "tag",
parent.sbn.getId(), parent.sbn.getNotification(), parent.sbn.getUserId());
- mBinderService.enqueueNotificationWithTag(PKG, "opPkg", "tag",
+ mBinderService.enqueueNotificationWithTag(PKG, PKG, "tag",
child.sbn.getId(), child.sbn.getNotification(), child.sbn.getUserId());
waitForIdle();
@@ -854,7 +859,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
public void testCancelAllNotificationsMultipleEnqueuedDoesNotCrash() throws Exception {
final StatusBarNotification sbn = generateNotificationRecord(null).sbn;
for (int i = 0; i < 10; i++) {
- mBinderService.enqueueNotificationWithTag(PKG, "opPkg", "tag",
+ mBinderService.enqueueNotificationWithTag(PKG, PKG, "tag",
sbn.getId(), sbn.getNotification(), sbn.getUserId());
}
mBinderService.cancelAllNotifications(PKG, sbn.getUserId());
@@ -873,17 +878,17 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
mTestNotificationChannel, 2, "group1", false);
// fully post parent notification
- mBinderService.enqueueNotificationWithTag(PKG, "opPkg", "tag",
+ mBinderService.enqueueNotificationWithTag(PKG, PKG, "tag",
parent.sbn.getId(), parent.sbn.getNotification(), parent.sbn.getUserId());
waitForIdle();
// enqueue the child several times
for (int i = 0; i < 10; i++) {
- mBinderService.enqueueNotificationWithTag(PKG, "opPkg", "tag",
+ mBinderService.enqueueNotificationWithTag(PKG, PKG, "tag",
child.sbn.getId(), child.sbn.getNotification(), child.sbn.getUserId());
}
// make the parent a child, which will cancel the child notification
- mBinderService.enqueueNotificationWithTag(PKG, "opPkg", "tag",
+ mBinderService.enqueueNotificationWithTag(PKG, PKG, "tag",
parentAsChild.sbn.getId(), parentAsChild.sbn.getNotification(),
parentAsChild.sbn.getUserId());
waitForIdle();
@@ -895,7 +900,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
public void testCancelAllNotifications_IgnoreForegroundService() throws Exception {
final StatusBarNotification sbn = generateNotificationRecord(null).sbn;
sbn.getNotification().flags |= FLAG_FOREGROUND_SERVICE;
- mBinderService.enqueueNotificationWithTag(PKG, "opPkg", "tag",
+ mBinderService.enqueueNotificationWithTag(PKG, PKG, "tag",
sbn.getId(), sbn.getNotification(), sbn.getUserId());
mBinderService.cancelAllNotifications(PKG, sbn.getUserId());
waitForIdle();
@@ -909,7 +914,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
public void testCancelAllNotifications_IgnoreOtherPackages() throws Exception {
final StatusBarNotification sbn = generateNotificationRecord(null).sbn;
sbn.getNotification().flags |= FLAG_FOREGROUND_SERVICE;
- mBinderService.enqueueNotificationWithTag(PKG, "opPkg", "tag",
+ mBinderService.enqueueNotificationWithTag(PKG, PKG, "tag",
sbn.getId(), sbn.getNotification(), sbn.getUserId());
mBinderService.cancelAllNotifications("other_pkg_name", sbn.getUserId());
waitForIdle();
@@ -922,7 +927,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
@Test
public void testCancelAllNotifications_NullPkgRemovesAll() throws Exception {
final StatusBarNotification sbn = generateNotificationRecord(null).sbn;
- mBinderService.enqueueNotificationWithTag(PKG, "opPkg", "tag",
+ mBinderService.enqueueNotificationWithTag(PKG, PKG, "tag",
sbn.getId(), sbn.getNotification(), sbn.getUserId());
mBinderService.cancelAllNotifications(null, sbn.getUserId());
waitForIdle();
@@ -935,7 +940,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
@Test
public void testCancelAllNotifications_NullPkgIgnoresUserAllNotifications() throws Exception {
final StatusBarNotification sbn = generateNotificationRecord(null).sbn;
- mBinderService.enqueueNotificationWithTag(PKG, "opPkg", "tag",
+ mBinderService.enqueueNotificationWithTag(PKG, PKG, "tag",
sbn.getId(), sbn.getNotification(), UserHandle.USER_ALL);
// Null pkg is how we signal a user switch.
mBinderService.cancelAllNotifications(null, sbn.getUserId());
@@ -950,7 +955,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
public void testAppInitiatedCancelAllNotifications_CancelsNoClearFlag() throws Exception {
final StatusBarNotification sbn = generateNotificationRecord(null).sbn;
sbn.getNotification().flags |= Notification.FLAG_NO_CLEAR;
- mBinderService.enqueueNotificationWithTag(PKG, "opPkg", "tag",
+ mBinderService.enqueueNotificationWithTag(PKG, PKG, "tag",
sbn.getId(), sbn.getNotification(), sbn.getUserId());
mBinderService.cancelAllNotifications(PKG, sbn.getUserId());
waitForIdle();
@@ -1037,7 +1042,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
public void testRemoveForegroundServiceFlag_ImmediatelyAfterEnqueue() throws Exception {
final StatusBarNotification sbn = generateNotificationRecord(null).sbn;
sbn.getNotification().flags |= FLAG_FOREGROUND_SERVICE;
- mBinderService.enqueueNotificationWithTag(PKG, "opPkg", null,
+ mBinderService.enqueueNotificationWithTag(PKG, PKG, null,
sbn.getId(), sbn.getNotification(), sbn.getUserId());
mInternalService.removeForegroundServiceFlagFromNotification(PKG, sbn.getId(),
sbn.getUserId());
@@ -1052,10 +1057,10 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
final StatusBarNotification sbn = generateNotificationRecord(null).sbn;
sbn.getNotification().flags =
Notification.FLAG_ONGOING_EVENT | FLAG_FOREGROUND_SERVICE;
- mBinderService.enqueueNotificationWithTag(PKG, "opPkg", "tag",
+ mBinderService.enqueueNotificationWithTag(PKG, PKG, "tag",
sbn.getId(), sbn.getNotification(), sbn.getUserId());
sbn.getNotification().flags = Notification.FLAG_ONGOING_EVENT;
- mBinderService.enqueueNotificationWithTag(PKG, "opPkg", "tag",
+ mBinderService.enqueueNotificationWithTag(PKG, PKG, "tag",
sbn.getId(), sbn.getNotification(), sbn.getUserId());
mBinderService.cancelNotificationWithTag(PKG, "tag", sbn.getId(), sbn.getUserId());
waitForIdle();
@@ -1145,21 +1150,21 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
// should not be returned
final NotificationRecord group2 = generateNotificationRecord(
mTestNotificationChannel, 2, "group2", true);
- mBinderService.enqueueNotificationWithTag(PKG, "opPkg", null,
+ mBinderService.enqueueNotificationWithTag(PKG, PKG, null,
group2.sbn.getId(), group2.sbn.getNotification(), group2.sbn.getUserId());
waitForIdle();
// should not be returned
final NotificationRecord nonGroup = generateNotificationRecord(
mTestNotificationChannel, 3, null, false);
- mBinderService.enqueueNotificationWithTag(PKG, "opPkg", null,
+ mBinderService.enqueueNotificationWithTag(PKG, PKG, null,
nonGroup.sbn.getId(), nonGroup.sbn.getNotification(), nonGroup.sbn.getUserId());
waitForIdle();
// same group, child, should be returned
final NotificationRecord group1Child = generateNotificationRecord(
mTestNotificationChannel, 4, "group1", false);
- mBinderService.enqueueNotificationWithTag(PKG, "opPkg", null, group1Child.sbn.getId(),
+ mBinderService.enqueueNotificationWithTag(PKG, PKG, null, group1Child.sbn.getId(),
group1Child.sbn.getNotification(), group1Child.sbn.getUserId());
waitForIdle();
@@ -1216,7 +1221,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
public void testAppInitiatedCancelAllNotifications_CancelsOnGoingFlag() throws Exception {
final StatusBarNotification sbn = generateNotificationRecord(null).sbn;
sbn.getNotification().flags |= Notification.FLAG_ONGOING_EVENT;
- mBinderService.enqueueNotificationWithTag(PKG, "opPkg", "tag",
+ mBinderService.enqueueNotificationWithTag(PKG, PKG, "tag",
sbn.getId(), sbn.getNotification(), sbn.getUserId());
mBinderService.cancelAllNotifications(PKG, sbn.getUserId());
waitForIdle();
@@ -1333,7 +1338,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
new NotificationChannel("foo", "foo", IMPORTANCE_HIGH));
Notification.TvExtender tv = new Notification.TvExtender().setChannelId("foo");
- mBinderService.enqueueNotificationWithTag(PKG, "opPkg", "tag", 0,
+ mBinderService.enqueueNotificationWithTag(PKG, PKG, "tag", 0,
generateNotificationRecord(null, tv).getNotification(), 0);
verify(mPreferencesHelper, times(1)).getNotificationChannel(
anyString(), anyInt(), eq("foo"), anyBoolean());
@@ -1348,7 +1353,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
mTestNotificationChannel);
Notification.TvExtender tv = new Notification.TvExtender().setChannelId("foo");
- mBinderService.enqueueNotificationWithTag(PKG, "opPkg", "tag", 0,
+ mBinderService.enqueueNotificationWithTag(PKG, PKG, "tag", 0,
generateNotificationRecord(null, tv).getNotification(), 0);
verify(mPreferencesHelper, times(1)).getNotificationChannel(
anyString(), anyInt(), eq(mTestNotificationChannel.getId()), anyBoolean());
@@ -1879,7 +1884,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
final NotificationRecord child = generateNotificationRecord(
mTestNotificationChannel, 2, "group", false);
- mBinderService.enqueueNotificationWithTag(PKG, "opPkg", null,
+ mBinderService.enqueueNotificationWithTag(PKG, PKG, null,
child.sbn.getId(), child.sbn.getNotification(), child.sbn.getUserId());
waitForIdle();
@@ -1892,7 +1897,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
final NotificationRecord record = generateNotificationRecord(
mTestNotificationChannel, 2, null, false);
- mBinderService.enqueueNotificationWithTag(PKG, "opPkg", null,
+ mBinderService.enqueueNotificationWithTag(PKG, PKG, null,
record.sbn.getId(), record.sbn.getNotification(), record.sbn.getUserId());
waitForIdle();
@@ -1904,7 +1909,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
final NotificationRecord parent = generateNotificationRecord(
mTestNotificationChannel, 2, "group", true);
- mBinderService.enqueueNotificationWithTag(PKG, "opPkg", null,
+ mBinderService.enqueueNotificationWithTag(PKG, PKG, null,
parent.sbn.getId(), parent.sbn.getNotification(), parent.sbn.getUserId());
waitForIdle();
@@ -2378,12 +2383,12 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
@Test
public void testBumpFGImportance_noChannelChangePreOApp() throws Exception {
String preOPkg = PKG_N_MR1;
- int preOUid = 145;
final ApplicationInfo legacy = new ApplicationInfo();
legacy.targetSdkVersion = Build.VERSION_CODES.N_MR1;
when(mPackageManagerClient.getApplicationInfoAsUser(eq(preOPkg), anyInt(), anyInt()))
.thenReturn(legacy);
- when(mPackageManagerClient.getPackageUidAsUser(eq(preOPkg), anyInt())).thenReturn(preOUid);
+ when(mPackageManagerClient.getPackageUidAsUser(eq(preOPkg), anyInt()))
+ .thenReturn(Binder.getCallingUid());
getContext().setMockPackageManager(mPackageManagerClient);
Notification.Builder nb = new Notification.Builder(mContext,
@@ -2393,12 +2398,13 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
.setFlag(FLAG_FOREGROUND_SERVICE, true)
.setPriority(Notification.PRIORITY_MIN);
- StatusBarNotification sbn = new StatusBarNotification(preOPkg, preOPkg, 9, "tag", preOUid,
- 0, nb.build(), new UserHandle(preOUid), null, 0);
+ StatusBarNotification sbn = new StatusBarNotification(preOPkg, preOPkg, 9, "tag",
+ Binder.getCallingUid(), 0, nb.build(), new UserHandle(Binder.getCallingUid()), null, 0);
- mBinderService.enqueueNotificationWithTag(preOPkg, preOPkg, "tag",
- sbn.getId(), sbn.getNotification(), sbn.getUserId());
+ mBinderService.enqueueNotificationWithTag(sbn.getPackageName(), sbn.getOpPkg(),
+ sbn.getTag(), sbn.getId(), sbn.getNotification(), sbn.getUserId());
waitForIdle();
+
assertEquals(IMPORTANCE_LOW,
mService.getNotificationRecord(sbn.getKey()).getImportance());
@@ -2408,8 +2414,8 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
.setFlag(FLAG_FOREGROUND_SERVICE, true)
.setPriority(Notification.PRIORITY_MIN);
- sbn = new StatusBarNotification(preOPkg, preOPkg, 9, "tag", preOUid,
- 0, nb.build(), new UserHandle(preOUid), null, 0);
+ sbn = new StatusBarNotification(preOPkg, preOPkg, 9, "tag", Binder.getCallingUid(),
+ 0, nb.build(), new UserHandle(Binder.getCallingUid()), null, 0);
mBinderService.enqueueNotificationWithTag(preOPkg, preOPkg, "tag",
sbn.getId(), sbn.getNotification(), sbn.getUserId());
@@ -3360,7 +3366,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
}
@Test
- public void testMybeRecordInterruptionLocked_doesNotRecordTwice()
+ public void testMaybeRecordInterruptionLocked_doesNotRecordTwice()
throws RemoteException {
final NotificationRecord r = generateNotificationRecord(
mTestNotificationChannel, 1, null, true);
@@ -3373,4 +3379,78 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
verify(mAppUsageStats, times(1)).reportInterruptiveNotification(
anyString(), anyString(), anyInt());
}
+
+ @Test
+ public void testResolveNotificationUid_sameApp() throws Exception {
+ ApplicationInfo info = new ApplicationInfo();
+ info.uid = Binder.getCallingUid();
+ when(mPackageManager.getApplicationInfo(anyString(), anyInt(), anyInt())).thenReturn(info);
+
+ int actualUid = mService.resolveNotificationUid("caller", "caller", info.uid, 0);
+
+ assertEquals(info.uid, actualUid);
+ }
+
+ @Test
+ public void testResolveNotificationUid_sameAppWrongPkg() throws Exception {
+ ApplicationInfo info = new ApplicationInfo();
+ info.uid = Binder.getCallingUid();
+ when(mPackageManager.getApplicationInfo(anyString(), anyInt(), anyInt())).thenReturn(info);
+
+ try {
+ mService.resolveNotificationUid("caller", "other", info.uid, 0);
+ fail("Incorrect pkg didn't throw security exception");
+ } catch (SecurityException e) {
+ // yay
+ }
+ }
+
+ @Test
+ public void testResolveNotificationUid_sameAppWrongUid() throws Exception {
+ ApplicationInfo info = new ApplicationInfo();
+ info.uid = 1356347;
+ when(mPackageManager.getApplicationInfo(anyString(), anyInt(), anyInt())).thenReturn(info);
+
+ try {
+ mService.resolveNotificationUid("caller", "caller", 9, 0);
+ fail("Incorrect uid didn't throw security exception");
+ } catch (SecurityException e) {
+ // yay
+ }
+ }
+
+ @Test
+ public void testResolveNotificationUid_delegateAllowed() throws Exception {
+ int expectedUid = 123;
+
+ when(mPackageManagerClient.getPackageUidAsUser("target", 0)).thenReturn(expectedUid);
+ mService.setPreferencesHelper(mPreferencesHelper);
+ when(mPreferencesHelper.isDelegateAllowed(anyString(), anyInt(), anyString(), anyInt()))
+ .thenReturn(true);
+
+ assertEquals(expectedUid, mService.resolveNotificationUid("caller", "target", 9, 0));
+ }
+
+ @Test
+ public void testResolveNotificationUid_androidAllowed() throws Exception {
+ int expectedUid = 123;
+
+ when(mPackageManagerClient.getPackageUidAsUser("target", 0)).thenReturn(expectedUid);
+ // no delegate
+
+ assertEquals(expectedUid, mService.resolveNotificationUid("android", "target", 0, 0));
+ }
+
+ @Test
+ public void testResolveNotificationUid_delegateNotAllowed() throws Exception {
+ when(mPackageManagerClient.getPackageUidAsUser("target", 0)).thenReturn(123);
+ // no delegate
+
+ try {
+ mService.resolveNotificationUid("caller", "target", 9, 0);
+ fail("Incorrect uid didn't throw security exception");
+ } catch (SecurityException e) {
+ // yay
+ }
+ }
}
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java b/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java
index 73adf25cb3ec..750345be1c1d 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java
@@ -123,7 +123,6 @@ public class PreferencesHelperTest extends UiServiceTestCase {
@Before
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
- UserHandle user = UserHandle.ALL;
final ApplicationInfo legacy = new ApplicationInfo();
legacy.targetSdkVersion = Build.VERSION_CODES.N_MR1;
@@ -176,11 +175,6 @@ public class PreferencesHelperTest extends UiServiceTestCase {
.build();
}
- private NotificationChannel getDefaultChannel() {
- return new NotificationChannel(NotificationChannel.DEFAULT_CHANNEL_ID, "name",
- IMPORTANCE_LOW);
- }
-
private ByteArrayOutputStream writeXmlAndPurge(String pkg, int uid, boolean forBackup,
String... channelIds)
throws Exception {
@@ -1787,4 +1781,159 @@ public class PreferencesHelperTest extends UiServiceTestCase {
mHelper.setEnabled(PKG_N_MR1, 1000, true);
assertEquals(3, mHelper.getBlockedAppCount(0));
}
+
+ @Test
+ public void testSetNotificationDelegate() {
+ mHelper.setNotificationDelegate(PKG_O, UID_O, "other", 53);
+ assertEquals("other", mHelper.getNotificationDelegate(PKG_O, UID_O));
+ }
+
+ @Test
+ public void testRevokeNotificationDelegate() {
+ mHelper.setNotificationDelegate(PKG_O, UID_O, "other", 53);
+ mHelper.revokeNotificationDelegate(PKG_O, UID_O);
+
+ assertNull(mHelper.getNotificationDelegate(PKG_O, UID_O));
+ }
+
+ @Test
+ public void testRevokeNotificationDelegate_noDelegateExistsNoCrash() {
+ mHelper.revokeNotificationDelegate(PKG_O, UID_O);
+
+ assertNull(mHelper.getNotificationDelegate(PKG_O, UID_O));
+ }
+
+ @Test
+ public void testToggleNotificationDelegate() {
+ mHelper.setNotificationDelegate(PKG_O, UID_O, "other", 53);
+ mHelper.toggleNotificationDelegate(PKG_O, UID_O, false);
+
+ assertNull(mHelper.getNotificationDelegate(PKG_O, UID_O));
+
+ mHelper.toggleNotificationDelegate(PKG_O, UID_O, true);
+ assertEquals("other", mHelper.getNotificationDelegate(PKG_O, UID_O));
+ }
+
+ @Test
+ public void testToggleNotificationDelegate_noDelegateExistsNoCrash() {
+ mHelper.toggleNotificationDelegate(PKG_O, UID_O, false);
+ assertNull(mHelper.getNotificationDelegate(PKG_O, UID_O));
+
+ mHelper.toggleNotificationDelegate(PKG_O, UID_O, true);
+ assertNull(mHelper.getNotificationDelegate(PKG_O, UID_O));
+ }
+
+ @Test
+ public void testIsDelegateAllowed_noSource() {
+ assertFalse(mHelper.isDelegateAllowed("does not exist", -1, "whatever", 0));
+ }
+
+ @Test
+ public void testIsDelegateAllowed_noDelegate() {
+ mHelper.setImportance(PKG_O, UID_O, IMPORTANCE_UNSPECIFIED);
+
+ assertFalse(mHelper.isDelegateAllowed(PKG_O, UID_O, "whatever", 0));
+ }
+
+ @Test
+ public void testIsDelegateAllowed_delegateDisabledByApp() {
+ mHelper.setNotificationDelegate(PKG_O, UID_O, "other", 53);
+ mHelper.revokeNotificationDelegate(PKG_O, UID_O);
+
+ assertFalse(mHelper.isDelegateAllowed(PKG_O, UID_O, "other", 53));
+ }
+
+ @Test
+ public void testIsDelegateAllowed_wrongDelegate() {
+ mHelper.setNotificationDelegate(PKG_O, UID_O, "other", 53);
+ mHelper.revokeNotificationDelegate(PKG_O, UID_O);
+
+ assertFalse(mHelper.isDelegateAllowed(PKG_O, UID_O, "banana", 27));
+ }
+
+ @Test
+ public void testIsDelegateAllowed_delegateDisabledByUser() {
+ mHelper.setNotificationDelegate(PKG_O, UID_O, "other", 53);
+ mHelper.toggleNotificationDelegate(PKG_O, UID_O, false);
+
+ assertFalse(mHelper.isDelegateAllowed(PKG_O, UID_O, "other", 53));
+ }
+
+ @Test
+ public void testIsDelegateAllowed() {
+ mHelper.setNotificationDelegate(PKG_O, UID_O, "other", 53);
+
+ assertTrue(mHelper.isDelegateAllowed(PKG_O, UID_O, "other", 53));
+ }
+
+ @Test
+ public void testDelegateXml_noDelegate() throws Exception {
+ mHelper.setImportance(PKG_O, UID_O, IMPORTANCE_UNSPECIFIED);
+
+ ByteArrayOutputStream baos = writeXmlAndPurge(PKG_O, UID_O, false);
+ mHelper = new PreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper);
+ loadStreamXml(baos, false);
+
+ assertNull(mHelper.getNotificationDelegate(PKG_O, UID_O));
+ }
+
+ @Test
+ public void testDelegateXml_delegate() throws Exception {
+ mHelper.setNotificationDelegate(PKG_O, UID_O, "other", 53);
+
+ ByteArrayOutputStream baos = writeXmlAndPurge(PKG_O, UID_O, false);
+ mHelper = new PreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper);
+ loadStreamXml(baos, false);
+
+ assertEquals("other", mHelper.getNotificationDelegate(PKG_O, UID_O));
+ }
+
+ @Test
+ public void testDelegateXml_disabledDelegate() throws Exception {
+ mHelper.setNotificationDelegate(PKG_O, UID_O, "other", 53);
+ mHelper.revokeNotificationDelegate(PKG_O, UID_O);
+
+ ByteArrayOutputStream baos = writeXmlAndPurge(PKG_O, UID_O, false);
+ mHelper = new PreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper);
+ loadStreamXml(baos, false);
+
+ assertNull(mHelper.getNotificationDelegate(PKG_O, UID_O));
+ }
+
+ @Test
+ public void testDelegateXml_userDisabledDelegate() throws Exception {
+ mHelper.setNotificationDelegate(PKG_O, UID_O, "other", 53);
+ mHelper.toggleNotificationDelegate(PKG_O, UID_O, false);
+
+ ByteArrayOutputStream baos = writeXmlAndPurge(PKG_O, UID_O, false);
+ mHelper = new PreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper);
+ loadStreamXml(baos, false);
+
+ // appears disabled
+ assertNull(mHelper.getNotificationDelegate(PKG_O, UID_O));
+
+ // but was loaded and can be toggled back on
+ mHelper.toggleNotificationDelegate(PKG_O, UID_O, true);
+ assertEquals("other", mHelper.getNotificationDelegate(PKG_O, UID_O));
+ }
+
+ @Test
+ public void testDelegateXml_entirelyDisabledDelegate() throws Exception {
+ mHelper.setNotificationDelegate(PKG_O, UID_O, "other", 53);
+ mHelper.toggleNotificationDelegate(PKG_O, UID_O, false);
+ mHelper.revokeNotificationDelegate(PKG_O, UID_O);
+
+ ByteArrayOutputStream baos = writeXmlAndPurge(PKG_O, UID_O, false);
+ mHelper = new PreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper);
+ loadStreamXml(baos, false);
+
+ // appears disabled
+ assertNull(mHelper.getNotificationDelegate(PKG_O, UID_O));
+
+ mHelper.setNotificationDelegate(PKG_O, UID_O, "other", 53);
+ assertNull(mHelper.getNotificationDelegate(PKG_O, UID_O));
+
+ mHelper.toggleNotificationDelegate(PKG_O, UID_O, true);
+ assertEquals("other", mHelper.getNotificationDelegate(PKG_O, UID_O));
+ }
}
diff --git a/services/tests/wmtests/Android.mk b/services/tests/wmtests/Android.mk
new file mode 100644
index 000000000000..0f8b18ab92cf
--- /dev/null
+++ b/services/tests/wmtests/Android.mk
@@ -0,0 +1,41 @@
+#########################################################################
+# Build WmTests package
+#########################################################################
+
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+# We only want this apk build for tests.
+LOCAL_MODULE_TAGS := tests
+
+# Include all test java files.
+LOCAL_SRC_FILES := \
+ $(call all-java-files-under, src) \
+ $(call all-java-files-under, ../servicestests/utils)
+
+LOCAL_STATIC_JAVA_LIBRARIES := \
+ androidx-test \
+ mockito-target-minus-junit4 \
+ platform-test-annotations \
+
+LOCAL_JAVA_LIBRARIES := \
+ android.test.mock \
+ android.test.base \
+ android.test.runner \
+
+LOCAL_PACKAGE_NAME := WmTests
+LOCAL_PRIVATE_PLATFORM_APIS := true
+LOCAL_COMPATIBILITY_SUITE := device-tests
+
+LOCAL_CERTIFICATE := platform
+
+LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
+
+LOCAL_JACK_FLAGS := --multi-dex native
+LOCAL_DX_FLAGS := --multi-dex
+
+LOCAL_PROGUARD_ENABLED := disabled
+
+include $(BUILD_PACKAGE)
+
+include $(call all-makefiles-under, $(LOCAL_PATH))
diff --git a/services/tests/wmtests/AndroidManifest.xml b/services/tests/wmtests/AndroidManifest.xml
new file mode 100644
index 000000000000..1fb947309028
--- /dev/null
+++ b/services/tests/wmtests/AndroidManifest.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2018 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.frameworks.wmtests">
+
+ <!-- Uses API introduced in P (28) -->
+ <uses-sdk
+ android:minSdkVersion="1"
+ android:targetSdkVersion="28" />
+
+ <application android:testOnly="true" />
+
+ <instrumentation
+ android:name="androidx.test.runner.AndroidJUnitRunner"
+ android:label="Window Manager Tests"
+ android:targetPackage="com.android.frameworks.wmtests" />
+</manifest>
diff --git a/services/tests/wmtests/AndroidTest.xml b/services/tests/wmtests/AndroidTest.xml
new file mode 100644
index 000000000000..2717ef901216
--- /dev/null
+++ b/services/tests/wmtests/AndroidTest.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2018 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<configuration description="Runs Window Manager Tests.">
+ <option name="test-suite-tag" value="apct" />
+ <option name="test-suite-tag" value="apct-instrumentation" />
+ <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
+ <option name="cleanup-apks" value="true" />
+ <option name="install-arg" value="-t" />
+ <option name="test-file-name" value="WmTests.apk" />
+ </target_preparer>
+
+ <option name="test-tag" value="WmTests" />
+ <test class="com.android.tradefed.testtype.AndroidJUnitTest">
+ <option name="package" value="com.android.frameworks.wmtests" />
+ <option name="runner" value="androidx.test.runner.AndroidJUnitRunner" />
+ <option name="hidden-api-checks" value="false" />
+ </test>
+</configuration>
diff --git a/services/tests/wmtests/src/com/android/server/am/DummyAmTests.java b/services/tests/wmtests/src/com/android/server/am/DummyAmTests.java
new file mode 100644
index 000000000000..023e4ab6636f
--- /dev/null
+++ b/services/tests/wmtests/src/com/android/server/am/DummyAmTests.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.am;
+
+import android.platform.test.annotations.Presubmit;
+
+import org.junit.Test;
+
+import androidx.test.filters.FlakyTest;
+
+/**
+ * Dummy test for com.android.server.am.
+ * TODO(b/113800711): Remove this class once the actual tests are moved from servicestests.
+ */
+public class DummyAmTests {
+
+ @Presubmit
+ @Test
+ public void preSubmitTest() {}
+
+ @FlakyTest
+ @Presubmit
+ @Test
+ public void flakyPreSubmitTest() {}
+
+ @Test
+ public void postSubmitTest() {}
+
+ @FlakyTest
+ @Test
+ public void flakyPostSubmitTest() {}
+}
diff --git a/services/tests/wmtests/src/com/android/server/wm/DummyWmTests.java b/services/tests/wmtests/src/com/android/server/wm/DummyWmTests.java
new file mode 100644
index 000000000000..aecb2783badd
--- /dev/null
+++ b/services/tests/wmtests/src/com/android/server/wm/DummyWmTests.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.wm;
+
+import android.platform.test.annotations.Presubmit;
+
+import org.junit.Test;
+
+import androidx.test.filters.FlakyTest;
+
+/**
+ * Dummy test for com.android.server.wm
+ * TODO(b/113800711): Remove this class once the actual tests are moved from servicestests.
+ */
+public class DummyWmTests {
+
+ @Presubmit
+ @Test
+ public void preSubmitTest() {}
+
+ @FlakyTest
+ @Presubmit
+ @Test
+ public void flakyPreSubmitTest() {}
+
+ @Test
+ public void postSubmitTest() {}
+
+ @FlakyTest
+ @Test
+ public void flakyPostSubmitTest() {}
+}
diff --git a/services/usage/java/com/android/server/usage/AppTimeLimitController.java b/services/usage/java/com/android/server/usage/AppTimeLimitController.java
index e7c54d8415d7..5916b04c079a 100644
--- a/services/usage/java/com/android/server/usage/AppTimeLimitController.java
+++ b/services/usage/java/com/android/server/usage/AppTimeLimitController.java
@@ -168,6 +168,7 @@ public class AppTimeLimitController {
}
/** Returns an existing UserData object for the given userId, or creates one */
+ @GuardedBy("mLock")
private UserData getOrCreateUserDataLocked(int userId) {
UserData userData = mUsers.get(userId);
if (userData == null) {
diff --git a/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerService.java b/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerService.java
index de1771690e60..7c22613664a5 100644
--- a/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerService.java
+++ b/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerService.java
@@ -670,6 +670,7 @@ public class SoundTriggerService extends SystemService {
/**
* Disconnect from the service, but allow to re-connect when new operations are triggered.
*/
+ @GuardedBy("mRemoteServiceLock")
private void disconnectLocked() {
if (mService != null) {
try {
diff --git a/telephony/java/android/telephony/SubscriptionManager.java b/telephony/java/android/telephony/SubscriptionManager.java
index 5e3bac5b0ce4..1d9e6052a31c 100644
--- a/telephony/java/android/telephony/SubscriptionManager.java
+++ b/telephony/java/android/telephony/SubscriptionManager.java
@@ -19,6 +19,7 @@ package android.telephony;
import static android.net.NetworkPolicyManager.OVERRIDE_CONGESTED;
import static android.net.NetworkPolicyManager.OVERRIDE_UNMETERED;
+import android.annotation.CallbackExecutor;
import android.annotation.DurationMillisLong;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -47,6 +48,7 @@ import android.os.RemoteException;
import android.os.ServiceManager;
import android.telephony.euicc.EuiccManager;
import android.util.DisplayMetrics;
+import android.util.Log;
import com.android.internal.telephony.IOnSubscriptionsChangedListener;
import com.android.internal.telephony.ISub;
@@ -57,6 +59,7 @@ import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
+import java.util.concurrent.Executor;
import java.util.concurrent.TimeUnit;
/**
@@ -666,7 +669,7 @@ public class SubscriptionManager {
tr.addOnSubscriptionsChangedListener(pkgName, listener.callback);
}
} catch (RemoteException ex) {
- // Should not happen
+ Log.e(LOG_TAG, "Remote exception ITelephonyRegistry " + ex);
}
}
@@ -684,7 +687,116 @@ public class SubscriptionManager {
+ " listener=" + listener);
}
try {
- // We use the TelephonyRegistry as its runs in the system and thus is always
+ // We use the TelephonyRegistry as it runs in the system and thus is always
+ // available where as SubscriptionController could crash and not be available
+ ITelephonyRegistry tr = ITelephonyRegistry.Stub.asInterface(ServiceManager.getService(
+ "telephony.registry"));
+ if (tr != null) {
+ tr.removeOnSubscriptionsChangedListener(pkgForDebug, listener.callback);
+ }
+ } catch (RemoteException ex) {
+ Log.e(LOG_TAG, "Remote exception ITelephonyRegistry " + ex);
+ }
+ }
+
+ /**
+ * A listener class for monitoring changes to {@link SubscriptionInfo} records of opportunistic
+ * subscriptions.
+ * <p>
+ * Override the onOpportunisticSubscriptionsChanged method in the object that extends this
+ * or {@link #addOnOpportunisticSubscriptionsChangedListener(
+ * Executor, OnOpportunisticSubscriptionsChangedListener)}
+ * to register your listener and to unregister invoke
+ * {@link #removeOnOpportunisticSubscriptionsChangedListener(
+ * OnOpportunisticSubscriptionsChangedListener)}
+ * <p>
+ * Permissions android.Manifest.permission.READ_PHONE_STATE is required
+ * for #onOpportunisticSubscriptionsChanged to be invoked.
+ */
+ public static class OnOpportunisticSubscriptionsChangedListener {
+ private Executor mExecutor;
+ /**
+ * Callback invoked when there is any change to any SubscriptionInfo. Typically
+ * this method would invoke {@link #getActiveSubscriptionInfoList}
+ */
+ public void onOpportunisticSubscriptionsChanged() {
+ if (DBG) log("onOpportunisticSubscriptionsChanged: NOT OVERRIDDEN");
+ }
+
+ private void setExecutor(Executor executor) {
+ mExecutor = executor;
+ }
+
+ /**
+ * The callback methods need to be called on the handler thread where
+ * this object was created. If the binder did that for us it'd be nice.
+ */
+ IOnSubscriptionsChangedListener callback = new IOnSubscriptionsChangedListener.Stub() {
+ @Override
+ public void onSubscriptionsChanged() {
+ if (DBG) log("onOpportunisticSubscriptionsChanged callback received.");
+ mExecutor.execute(() -> onOpportunisticSubscriptionsChanged());
+ }
+ };
+
+ private void log(String s) {
+ Rlog.d(LOG_TAG, s);
+ }
+ }
+
+ /**
+ * Register for changes to the list of opportunistic subscription records or to the
+ * individual records themselves. When a change occurs the onOpportunisticSubscriptionsChanged
+ * method of the listener will be invoked immediately if there has been a notification.
+ *
+ * @param listener an instance of {@link OnOpportunisticSubscriptionsChangedListener} with
+ * onOpportunisticSubscriptionsChanged overridden.
+ */
+ public void addOnOpportunisticSubscriptionsChangedListener(
+ @NonNull @CallbackExecutor Executor executor,
+ @NonNull OnOpportunisticSubscriptionsChangedListener listener) {
+ if (executor == null || listener == null) {
+ return;
+ }
+
+ String pkgName = mContext != null ? mContext.getOpPackageName() : "<unknown>";
+ if (DBG) {
+ logd("register addOnOpportunisticSubscriptionsChangedListener pkgName=" + pkgName
+ + " listener=" + listener);
+ }
+
+ listener.setExecutor(executor);
+
+ try {
+ // We use the TelephonyRegistry as it runs in the system and thus is always
+ // available. Where as SubscriptionController could crash and not be available
+ ITelephonyRegistry tr = ITelephonyRegistry.Stub.asInterface(ServiceManager.getService(
+ "telephony.registry"));
+ if (tr != null) {
+ tr.addOnOpportunisticSubscriptionsChangedListener(pkgName, listener.callback);
+ }
+ } catch (RemoteException ex) {
+ Log.e(LOG_TAG, "Remote exception ITelephonyRegistry " + ex);
+ }
+ }
+
+ /**
+ * Unregister the {@link OnOpportunisticSubscriptionsChangedListener} that is currently
+ * listening opportunistic subscriptions change. This is not strictly necessary
+ * as the listener will automatically be unregistered if an attempt to invoke the listener
+ * fails.
+ *
+ * @param listener that is to be unregistered.
+ */
+ public void removeOnOpportunisticSubscriptionsChangedListener(
+ OnOpportunisticSubscriptionsChangedListener listener) {
+ String pkgForDebug = mContext != null ? mContext.getOpPackageName() : "<unknown>";
+ if (DBG) {
+ logd("unregister OnOpportunisticSubscriptionsChangedListener pkgForDebug="
+ + pkgForDebug + " listener=" + listener);
+ }
+ try {
+ // We use the TelephonyRegistry as it runs in the system and thus is always
// available where as SubscriptionController could crash and not be available
ITelephonyRegistry tr = ITelephonyRegistry.Stub.asInterface(ServiceManager.getService(
"telephony.registry"));
@@ -692,7 +804,7 @@ public class SubscriptionManager {
tr.removeOnSubscriptionsChangedListener(pkgForDebug, listener.callback);
}
} catch (RemoteException ex) {
- // Should not happen
+ Log.e(LOG_TAG, "Remote exception ITelephonyRegistry " + ex);
}
}
@@ -1177,6 +1289,15 @@ public class SubscriptionManager {
}
+ /**
+ * Get an array of Subscription Ids for specified slot Index.
+ * @param slotIndex the slot Index.
+ * @return subscription Ids or null if the given slot Index is not valid.
+ */
+ public static int[] getSubscriptionIds(int slotIndex) {
+ return getSubId(slotIndex);
+ }
+
/** @hide */
@UnsupportedAppUsage
public static int[] getSubId(int slotIndex) {
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index b8e4c0eb58bf..2ac0afe71894 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -135,6 +135,22 @@ public class TelephonyManager {
static final int NEVER_USE = 2;
}
+ /** @hide */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef(prefix = {"NETWORK_SELECTION_MODE_"},
+ value = {
+ NETWORK_SELECTION_MODE_UNKNOWN,
+ NETWORK_SELECTION_MODE_AUTO,
+ NETWORK_SELECTION_MODE_MANUAL})
+ public @interface NetworkSelectionMode {}
+
+ /** @hide */
+ public static final int NETWORK_SELECTION_MODE_UNKNOWN = 0;
+ /** @hide */
+ public static final int NETWORK_SELECTION_MODE_AUTO = 1;
+ /** @hide */
+ public static final int NETWORK_SELECTION_MODE_MANUAL = 2;
+
/** The otaspMode passed to PhoneStateListener#onOtaspChanged */
/** @hide */
static public final int OTASP_UNINITIALIZED = 0;
@@ -5790,6 +5806,31 @@ public class TelephonyManager {
return false;
}
+ /**
+ * Get the network selection mode.
+ *
+ * <p>If this object has been created with {@link #createForSubscriptionId}, applies to the
+ * given subId. Otherwise, applies to {@link SubscriptionManager#getDefaultDataSubscriptionId()}
+
+ * @return the network selection mode.
+ *
+ * @hide
+ */
+ @NetworkSelectionMode
+ @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE)
+ public int getNetworkSelectionMode() {
+ int mode = NETWORK_SELECTION_MODE_UNKNOWN;
+ try {
+ ITelephony telephony = getITelephony();
+ if (telephony != null) {
+ mode = telephony.getNetworkSelectionMode(getSubId());
+ }
+ } catch (RemoteException ex) {
+ Rlog.e(TAG, "getNetworkSelectionMode RemoteException", ex);
+ }
+ return mode;
+ }
+
/**
* Set the preferred network type.
* Used for device configuration by some CDMA operators.
@@ -6704,6 +6745,84 @@ public class TelephonyManager {
}
/**
+ * Gets the roaming mode for CDMA phone.
+ *
+ * <p>If this object has been created with {@link #createForSubscriptionId}, applies to the
+ * given subId. Otherwise, applies to {@link SubscriptionManager#getDefaultDataSubscriptionId()}
+ *
+ * @return one of {@link #CDMA_ROAMING_MODE_RADIO_DEFAULT}, {@link #CDMA_ROAMING_MODE_HOME},
+ * {@link #CDMA_ROAMING_MODE_AFFILIATED}, {@link #CDMA_ROAMING_MODE_ANY}.
+ *
+ * @hide
+ */
+ @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE)
+ public int getCdmaRoamingMode() {
+ int mode = CDMA_ROAMING_MODE_RADIO_DEFAULT;
+ try {
+ ITelephony telephony = getITelephony();
+ if (telephony != null) {
+ mode = telephony.getCdmaRoamingMode(getSubId());
+ }
+ } catch (RemoteException ex) {
+ Log.e(TAG, "Error calling ITelephony#getCdmaRoamingMode", ex);
+ }
+ return mode;
+ }
+
+ /**
+ * Sets the roaming mode for CDMA phone to the given mode {@code mode}.
+ *
+ * <p>If this object has been created with {@link #createForSubscriptionId}, applies to the
+ * given subId. Otherwise, applies to {@link SubscriptionManager#getDefaultDataSubscriptionId()}
+ *
+ * @param mode should be one of {@link #CDMA_ROAMING_MODE_RADIO_DEFAULT},
+ * {@link #CDMA_ROAMING_MODE_HOME}, {@link #CDMA_ROAMING_MODE_AFFILIATED},
+ * {@link #CDMA_ROAMING_MODE_ANY}.
+ *
+ * @return {@code true} if successed.
+ *
+ * @hide
+ */
+ @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
+ public boolean setCdmaRoamingMode(int mode) {
+ try {
+ ITelephony telephony = getITelephony();
+ if (telephony != null) {
+ return telephony.setCdmaRoamingMode(getSubId(), mode);
+ }
+ } catch (RemoteException ex) {
+ Log.e(TAG, "Error calling ITelephony#setCdmaRoamingMode", ex);
+ }
+ return false;
+ }
+
+ /**
+ * Sets the subscription mode for CDMA phone to the given mode {@code mode}.
+ *
+ * @param mode CDMA subscription mode
+ *
+ * @return {@code true} if successed.
+ *
+ * @see Phone#CDMA_SUBSCRIPTION_UNKNOWN
+ * @see Phone#CDMA_SUBSCRIPTION_RUIM_SIM
+ * @see Phone#CDMA_SUBSCRIPTION_NV
+ *
+ * @hide
+ */
+ @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
+ public boolean setCdmaSubscriptionMode(int mode) {
+ try {
+ ITelephony telephony = getITelephony();
+ if (telephony != null) {
+ return telephony.setCdmaSubscriptionMode(getSubId(), mode);
+ }
+ } catch (RemoteException ex) {
+ Log.e(TAG, "Error calling ITelephony#setCdmaSubscriptionMode", ex);
+ }
+ return false;
+ }
+
+ /**
* Enables/Disables the data roaming on the subscription.
*
* <p>If this object has been created with {@link #createForSubscriptionId}, applies to the
diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl
index a7e55812d2fe..c0bccde2cda3 100644
--- a/telephony/java/com/android/internal/telephony/ITelephony.aidl
+++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl
@@ -1530,6 +1530,34 @@ interface ITelephony {
void setDataRoamingEnabled(int subId, boolean isEnabled);
/**
+ * Gets the roaming mode for the CDMA phone with the subscription id {@code subId}.
+ *
+ * @param the subscription id.
+ * @return the roaming mode for CDMA phone.
+ */
+ int getCdmaRoamingMode(int subId);
+
+ /**
+ * Sets the roaming mode on the CDMA phone with the subscription {@code subId} to the given
+ * roaming mode {@code mode}.
+ *
+ * @param subId the subscription id.
+ * @param mode the roaming mode should be set.
+ * @return {@code true} if successed.
+ */
+ boolean setCdmaRoamingMode(int subId, int mode);
+
+ /**
+ * Sets the subscription mode for CDMA phone with the subscription {@code subId} to the given
+ * subscription mode {@code mode}.
+ *
+ * @param subId the subscription id.
+ * @param mode the subscription mode should be set.
+ * @return {@code true} if successed.
+ */
+ boolean setCdmaSubscriptionMode(int subId, int mode);
+
+ /**
* A test API to override carrier information including mccmnc, imsi, iccid, gid1, gid2,
* plmn and spn. This would be handy for, eg, forcing a particular carrier id, carrier's config
* (also any country or carrier overlays) to be loaded when using a test SIM with a call box.
@@ -1553,4 +1581,9 @@ interface ITelephony {
* @hide
*/
int getNumberOfModemsWithSimultaneousDataConnections(int subId, String callingPackage);
+
+ /**
+ * Return the network selection mode on the subscription with id {@code subId}.
+ */
+ int getNetworkSelectionMode(int subId);
}
diff --git a/telephony/java/com/android/internal/telephony/ITelephonyRegistry.aidl b/telephony/java/com/android/internal/telephony/ITelephonyRegistry.aidl
index e0e1a7b87916..43d56b39e0c4 100644
--- a/telephony/java/com/android/internal/telephony/ITelephonyRegistry.aidl
+++ b/telephony/java/com/android/internal/telephony/ITelephonyRegistry.aidl
@@ -32,6 +32,8 @@ import com.android.internal.telephony.IOnSubscriptionsChangedListener;
interface ITelephonyRegistry {
void addOnSubscriptionsChangedListener(String pkg,
IOnSubscriptionsChangedListener callback);
+ void addOnOpportunisticSubscriptionsChangedListener(String pkg,
+ IOnSubscriptionsChangedListener callback);
void removeOnSubscriptionsChangedListener(String pkg,
IOnSubscriptionsChangedListener callback);
void listen(String pkg, IPhoneStateListener callback, int events, boolean notifyNow);
@@ -73,6 +75,7 @@ interface ITelephonyRegistry {
int activationState, int activationType);
void notifyOemHookRawEventForSubscriber(in int subId, in byte[] rawData);
void notifySubscriptionInfoChanged();
+ void notifyOpportunisticSubscriptionInfoChanged();
void notifyCarrierNetworkChange(in boolean active);
void notifyUserMobileDataStateChangedForPhoneId(in int phoneId, in int subId, in boolean state);
void notifyPhoneCapabilityChanged(in PhoneCapability capability);
diff --git a/test-mock/api/system-current.txt b/test-mock/api/system-current.txt
index 20401a50b6a2..3bd3d68ba6cf 100644
--- a/test-mock/api/system-current.txt
+++ b/test-mock/api/system-current.txt
@@ -11,6 +11,7 @@ package android.test.mock {
public deprecated class MockPackageManager extends android.content.pm.PackageManager {
method public void addOnPermissionsChangeListener(android.content.pm.PackageManager.OnPermissionsChangedListener);
+ method public boolean arePermissionsIndividuallyControlled();
method public java.util.List<android.content.IntentFilter> getAllIntentFilters(java.lang.String);
method public java.lang.String getDefaultBrowserPackageNameAsUser(int);
method public java.util.List<android.content.pm.PackageInfo> getInstalledPackagesAsUser(int, int);
diff --git a/tests/SystemMemoryTest/README.txt b/tests/SystemMemoryTest/README.txt
index de5042cf3732..8ffca1532117 100644
--- a/tests/SystemMemoryTest/README.txt
+++ b/tests/SystemMemoryTest/README.txt
@@ -13,8 +13,7 @@ Running the test
You can manually run the test as follows:
- make tradefed-all system-memory-test SystemMemoryTestDevice
- tradefed.sh run commandAndExit template/local_min --template:map test=system-memory-test
+ atest -v system-memory-test
This installs and runs the test on device. You can see the metrics in the
tradefed output.
diff --git a/tests/SystemMemoryTest/host/src/com/android/tests/sysmem/host/Metrics.java b/tests/SystemMemoryTest/host/src/com/android/tests/sysmem/host/Metrics.java
index 7de092a973ad..616983e39c50 100644
--- a/tests/SystemMemoryTest/host/src/com/android/tests/sysmem/host/Metrics.java
+++ b/tests/SystemMemoryTest/host/src/com/android/tests/sysmem/host/Metrics.java
@@ -66,6 +66,18 @@ class Metrics {
}
/**
+ * Writes the given <code>text</code> to a log with the given label.
+ */
+ private void logText(String label, String text) throws IOException {
+ File file = File.createTempFile(label, "txt");
+ PrintStream ps = new PrintStream(file);
+ ps.print(text);
+ try (FileInputStreamSource dataStream = new FileInputStreamSource(file)) {
+ logs.addTestLog(label, LogDataType.TEXT, dataStream);
+ }
+ }
+
+ /**
* Returns the pid for the process with the given name.
*/
private int getPidForProcess(String name)
@@ -111,13 +123,7 @@ class Metrics {
// Read showmap for system server and add it as a test log
String showmap = device.executeShellCommand("showmap " + pid);
- String showmapLabel = label + ".system_server.showmap";
- File file = File.createTempFile(showmapLabel, "txt");
- PrintStream ps = new PrintStream(file);
- ps.print(showmap);
- try (FileInputStreamSource dataStream = new FileInputStreamSource(file)) {
- logs.addTestLog(showmapLabel, LogDataType.TEXT, dataStream);
- }
+ logText(label + ".system_server.showmap", showmap);
// Extract VSS, PSS and RSS from the showmap and output them as metrics.
// The last lines of the showmap output looks something like:
@@ -140,6 +146,11 @@ class Metrics {
throw new MetricsException("unexpected showmap format", e);
}
+ // Run debuggerd -j to get GC stats for system server and add it as a
+ // test log
+ String debuggerd = device.executeShellCommand("debuggerd -j " + pid);
+ logText(label + ".system_server.debuggerd", debuggerd);
+
// TODO: Experiment with other additional metrics.
// TODO: Consider launching an instrumentation to collect metrics from
diff --git a/tests/TtsTests/src/com/android/speech/tts/TextToSpeechTests.java b/tests/TtsTests/src/com/android/speech/tts/TextToSpeechTests.java
index 918873bf0bdd..d9bb7db17685 100644
--- a/tests/TtsTests/src/com/android/speech/tts/TextToSpeechTests.java
+++ b/tests/TtsTests/src/com/android/speech/tts/TextToSpeechTests.java
@@ -28,6 +28,7 @@ import org.mockito.internal.stubbing.StubberImpl;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer;
import org.mockito.stubbing.Stubber;
+import org.mockito.quality.Strictness;
import junit.framework.Assert;
import java.util.Locale;
@@ -210,12 +211,16 @@ public class TextToSpeechTests extends InstrumentationTestCase {
}
public static abstract class CountDownBehaviour extends StubberImpl {
+ public CountDownBehaviour(Strictness strictness) {
+ super(strictness);
+ }
+
/** Used to mock methods that return a result. */
public abstract Stubber andReturn(Object result);
}
public static CountDownBehaviour doCountDown(final CountDownLatch latch) {
- return new CountDownBehaviour() {
+ return new CountDownBehaviour(Strictness.WARN) {
@Override
public <T> T when(T mock) {
return Mockito.doAnswer(new Answer<Void>() {
@@ -229,7 +234,7 @@ public class TextToSpeechTests extends InstrumentationTestCase {
@Override
public Stubber andReturn(final Object result) {
- return new StubberImpl() {
+ return new StubberImpl(Strictness.WARN) {
@Override
public <T> T when(T mock) {
return Mockito.doAnswer(new Answer<Object>() {
diff --git a/tools/hiddenapi/generate_hiddenapi_lists.py b/tools/hiddenapi/generate_hiddenapi_lists.py
index 4a0931a149af..6c46e67be63d 100755
--- a/tools/hiddenapi/generate_hiddenapi_lists.py
+++ b/tools/hiddenapi/generate_hiddenapi_lists.py
@@ -59,6 +59,8 @@ def get_args():
def read_lines(filename):
"""Reads entire file and return it as a list of lines.
+ Lines which begin with a hash are ignored.
+
Args:
filename (string): Path to the file to read from.
@@ -66,7 +68,7 @@ def read_lines(filename):
list: Lines of the loaded file as a list of strings.
"""
with open(filename, 'r') as f:
- return f.readlines()
+ return filter(lambda line: not line.startswith('#'), f.readlines())
def write_lines(filename, lines):
"""Writes list of lines into a file, overwriting the file it it exists.
diff --git a/tools/hiddenapi/sort_api.sh b/tools/hiddenapi/sort_api.sh
index 1c6eb1b286b1..bdcc8076dde1 100755
--- a/tools/hiddenapi/sort_api.sh
+++ b/tools/hiddenapi/sort_api.sh
@@ -11,8 +11,14 @@ fi
readarray A < "$source_list"
# Sort
IFS=$'\n'
+# Stash away comments
+C=( $(grep -E '^#' <<< "${A[*]}") )
+A=( $(grep -v -E '^#' <<< "${A[*]}") )
+# Sort entries
A=( $(LC_COLLATE=C sort -f <<< "${A[*]}") )
A=( $(uniq <<< "${A[*]}") )
+# Concatenate comments and entries
+A=( ${C[*]} ${A[*]} )
unset IFS
# Dump array back into the file
printf '%s\n' "${A[@]}" > "$dest_list"
diff --git a/tools/stats_log_api_gen/Collation.cpp b/tools/stats_log_api_gen/Collation.cpp
index 40ee490fc186..f294728860ae 100644
--- a/tools/stats_log_api_gen/Collation.cpp
+++ b/tools/stats_log_api_gen/Collation.cpp
@@ -184,16 +184,6 @@ int collate_atom(const Descriptor *atom, AtomDecl *atomDecl,
expectedNumber++;
}
- // Skips the key value pair atom.
- for (map<int, const FieldDescriptor *>::const_iterator it = fields.begin();
- it != fields.end(); it++) {
- const FieldDescriptor *field = it->second;
- java_type_t javaType = java_type(field);
- if (javaType == JAVA_TYPE_KEY_VALUE_PAIR) {
- return 0;
- }
- }
-
// Check that only allowed types are present. Remove any invalid ones.
for (map<int, const FieldDescriptor *>::const_iterator it = fields.begin();
it != fields.end(); it++) {
diff --git a/tools/stats_log_api_gen/main.cpp b/tools/stats_log_api_gen/main.cpp
index 8038a3a4f44e..83a66312b425 100644
--- a/tools/stats_log_api_gen/main.cpp
+++ b/tools/stats_log_api_gen/main.cpp
@@ -235,6 +235,10 @@ static int write_stats_log_cpp(FILE *out, const Atoms &atoms,
chainField.name.c_str(), chainField.name.c_str());
}
}
+ } else if (*arg == JAVA_TYPE_KEY_VALUE_PAIR) {
+ fprintf(out, ", const std::map<int, int64_t>& arg%d_1, "
+ "const std::map<int, char const*>& arg%d_2, "
+ "const std::map<int, float>& arg%d_3", argIndex, argIndex, argIndex);
} else {
fprintf(out, ", %s arg%d", cpp_type_name(*arg), argIndex);
}
@@ -277,6 +281,30 @@ static int write_stats_log_cpp(FILE *out, const Atoms &atoms,
fprintf(out, " event.end();\n");
fprintf(out, " }\n");
fprintf(out, " event.end();\n\n");
+ } else if (*arg == JAVA_TYPE_KEY_VALUE_PAIR) {
+ fprintf(out, " event.begin();\n\n");
+ fprintf(out, " for (const auto& it : arg%d_1) {\n", argIndex);
+ fprintf(out, " event.begin();\n");
+ fprintf(out, " event << it.first;\n");
+ fprintf(out, " event << it.second;\n");
+ fprintf(out, " event.end();\n");
+ fprintf(out, " }\n");
+
+ fprintf(out, " for (const auto& it : arg%d_2) {\n", argIndex);
+ fprintf(out, " event.begin();\n");
+ fprintf(out, " event << it.first;\n");
+ fprintf(out, " event << it.second;\n");
+ fprintf(out, " event.end();\n");
+ fprintf(out, " }\n");
+
+ fprintf(out, " for (const auto& it : arg%d_3) {\n", argIndex);
+ fprintf(out, " event.begin();\n");
+ fprintf(out, " event << it.first;\n");
+ fprintf(out, " event << it.second;\n");
+ fprintf(out, " event.end();\n");
+ fprintf(out, " }\n");
+
+ fprintf(out, " event.end();\n\n");
} else {
if (*arg == JAVA_TYPE_STRING) {
fprintf(out, " if (arg%d == NULL) {\n", argIndex);
@@ -300,7 +328,7 @@ static int write_stats_log_cpp(FILE *out, const Atoms &atoms,
signature != atoms.signatures.end(); signature++) {
int argIndex;
- fprintf(out, "int \n");
+ fprintf(out, "int\n");
fprintf(out, "stats_write(int32_t code");
argIndex = 1;
for (vector<java_type_t>::const_iterator arg = signature->begin();
@@ -317,6 +345,10 @@ static int write_stats_log_cpp(FILE *out, const Atoms &atoms,
chainField.name.c_str(), chainField.name.c_str());
}
}
+ } else if (*arg == JAVA_TYPE_KEY_VALUE_PAIR) {
+ fprintf(out, ", const std::map<int, int64_t>& arg%d_1, "
+ "const std::map<int, char const*>& arg%d_2, "
+ "const std::map<int, float>& arg%d_3", argIndex, argIndex, argIndex);
} else {
fprintf(out, ", %s arg%d", cpp_type_name(*arg), argIndex);
}
@@ -343,6 +375,8 @@ static int write_stats_log_cpp(FILE *out, const Atoms &atoms,
chainField.name.c_str(), chainField.name.c_str());
}
}
+ } else if (*arg == JAVA_TYPE_KEY_VALUE_PAIR) {
+ fprintf(out, ", arg%d_1, arg%d_2, arg%d_3", argIndex, argIndex, argIndex);
} else {
fprintf(out, ", arg%d", argIndex);
}
@@ -496,6 +530,11 @@ static void write_cpp_usage(
chainField.name.c_str(), chainField.name.c_str());
}
}
+ } else if (field->javaType == JAVA_TYPE_KEY_VALUE_PAIR) {
+ fprintf(out, ", const std::map<int, int64_t>& %s_int"
+ ", const std::map<int, char const*>& %s_str"
+ ", const std::map<int, float>& %s_float",
+ field->name.c_str(), field->name.c_str(), field->name.c_str());
} else {
fprintf(out, ", %s %s", cpp_type_name(field->javaType), field->name.c_str());
}
@@ -508,7 +547,7 @@ static void write_cpp_method_header(
const AtomDecl &attributionDecl) {
for (set<vector<java_type_t>>::const_iterator signature = signatures.begin();
signature != signatures.end(); signature++) {
- fprintf(out, "int %s(int32_t code ", method_name.c_str());
+ fprintf(out, "int %s(int32_t code", method_name.c_str());
int argIndex = 1;
for (vector<java_type_t>::const_iterator arg = signature->begin();
arg != signature->end(); arg++) {
@@ -523,6 +562,10 @@ static void write_cpp_method_header(
chainField.name.c_str(), chainField.name.c_str());
}
}
+ } else if (*arg == JAVA_TYPE_KEY_VALUE_PAIR) {
+ fprintf(out, ", const std::map<int, int64_t>& arg%d_1, "
+ "const std::map<int, char const*>& arg%d_2, "
+ "const std::map<int, float>& arg%d_3", argIndex, argIndex, argIndex);
} else {
fprintf(out, ", %s arg%d", cpp_type_name(*arg), argIndex);
}
@@ -637,6 +680,8 @@ static void write_java_usage(FILE* out, const string& method_name, const string&
field != atom.fields.end(); field++) {
if (field->javaType == JAVA_TYPE_ATTRIBUTION_CHAIN) {
fprintf(out, ", android.os.WorkSource workSource");
+ } else if (field->javaType == JAVA_TYPE_KEY_VALUE_PAIR) {
+ fprintf(out, ", SparseArray<Object> value_map");
} else {
fprintf(out, ", %s %s", java_type_name(field->javaType), field->name.c_str());
}
@@ -658,6 +703,8 @@ static void write_java_method(
fprintf(out, ", %s[] %s",
java_type_name(chainField.javaType), chainField.name.c_str());
}
+ } else if (*arg == JAVA_TYPE_KEY_VALUE_PAIR) {
+ fprintf(out, ", SparseArray<Object> value_map");
} else {
fprintf(out, ", %s arg%d", java_type_name(*arg), argIndex);
}
@@ -746,6 +793,7 @@ write_stats_log_java(FILE* out, const Atoms& atoms, const AtomDecl &attributionD
fprintf(out, "package android.util;\n");
fprintf(out, "\n");
fprintf(out, "import android.os.WorkSource;\n");
+ fprintf(out, "import android.util.SparseArray;\n");
fprintf(out, "import java.util.ArrayList;\n");
fprintf(out, "\n");
fprintf(out, "\n");
@@ -837,6 +885,8 @@ jni_array_type_name(java_type_t type)
switch (type) {
case JAVA_TYPE_INT:
return "jintArray";
+ case JAVA_TYPE_FLOAT:
+ return "jfloatArray";
case JAVA_TYPE_STRING:
return "jobjectArray";
default:
@@ -873,6 +923,9 @@ jni_function_name(const string& method_name, const vector<java_type_t>& signatur
case JAVA_TYPE_ATTRIBUTION_CHAIN:
result += "_AttributionChain";
break;
+ case JAVA_TYPE_KEY_VALUE_PAIR:
+ result += "_KeyValuePairs";
+ break;
default:
result += "_UNKNOWN";
break;
@@ -914,6 +967,8 @@ jni_function_signature(const vector<java_type_t>& signature, const AtomDecl &att
result += "[";
result += java_type_signature(chainField.javaType);
}
+ } else if (*arg == JAVA_TYPE_KEY_VALUE_PAIR) {
+ result += "Landroid/util/SparseArray;";
} else {
result += java_type_signature(*arg);
}
@@ -922,6 +977,43 @@ jni_function_signature(const vector<java_type_t>& signature, const AtomDecl &att
return result;
}
+static void write_key_value_map_jni(FILE* out) {
+ fprintf(out, " std::map<int, int64_t> int64_t_map;\n");
+ fprintf(out, " std::map<int, float> float_map;\n");
+ fprintf(out, " std::map<int, char const*> string_map;\n\n");
+
+ fprintf(out, " jclass jmap_class = env->FindClass(\"android/util/SparseArray\");\n");
+
+ fprintf(out, " jmethodID jget_size_method = env->GetMethodID(jmap_class, \"size\", \"()I\");\n");
+ fprintf(out, " jmethodID jget_key_method = env->GetMethodID(jmap_class, \"keyAt\", \"(I)I\");\n");
+ fprintf(out, " jmethodID jget_value_method = env->GetMethodID(jmap_class, \"valueAt\", \"(I)Ljava/lang/Object;\");\n\n");
+
+
+ fprintf(out, " std::vector<std::unique_ptr<ScopedUtfChars>> scoped_ufs;\n\n");
+
+ fprintf(out, " jclass jlong_class = env->FindClass(\"java/lang/Long\");\n");
+ fprintf(out, " jclass jfloat_class = env->FindClass(\"java/lang/Float\");\n");
+ fprintf(out, " jclass jstring_class = env->FindClass(\"java/lang/String\");\n");
+ fprintf(out, " jmethodID jget_long_method = env->GetMethodID(jlong_class, \"longValue\", \"()J\");\n");
+ fprintf(out, " jmethodID jget_float_method = env->GetMethodID(jfloat_class, \"floatValue\", \"()F\");\n\n");
+
+ fprintf(out, " jint jsize = env->CallIntMethod(value_map, jget_size_method);\n");
+ fprintf(out, " for(int i = 0; i < jsize; i++) {\n");
+ fprintf(out, " jint key = env->CallIntMethod(value_map, jget_key_method, i);\n");
+ fprintf(out, " jobject jvalue_obj = env->CallObjectMethod(value_map, jget_value_method, i);\n");
+ fprintf(out, " if (jvalue_obj == NULL) { continue; }\n");
+ fprintf(out, " if (env->IsInstanceOf(jvalue_obj, jlong_class)) {\n");
+ fprintf(out, " int64_t_map[key] = env->CallLongMethod(jvalue_obj, jget_long_method);\n");
+ fprintf(out, " } else if (env->IsInstanceOf(jvalue_obj, jfloat_class)) {\n");
+ fprintf(out, " float_map[key] = env->CallFloatMethod(jvalue_obj, jget_float_method);\n");
+ fprintf(out, " } else if (env->IsInstanceOf(jvalue_obj, jstring_class)) {\n");
+ fprintf(out, " std::unique_ptr<ScopedUtfChars> utf(new ScopedUtfChars(env, (jstring)jvalue_obj));\n");
+ fprintf(out, " if (utf->c_str() != NULL) { string_map[key] = utf->c_str(); }\n");
+ fprintf(out, " scoped_ufs.push_back(std::move(utf));\n");
+ fprintf(out, " }\n");
+ fprintf(out, " }\n");
+}
+
static int
write_stats_log_jni(FILE* out, const string& java_method_name, const string& cpp_method_name,
const set<vector<java_type_t>>& signatures, const AtomDecl &attributionDecl)
@@ -942,6 +1034,8 @@ write_stats_log_jni(FILE* out, const string& java_method_name, const string& cpp
fprintf(out, ", %s %s", jni_array_type_name(chainField.javaType),
chainField.name.c_str());
}
+ } else if (*arg == JAVA_TYPE_KEY_VALUE_PAIR) {
+ fprintf(out, ", jobject value_map");
} else {
fprintf(out, ", %s arg%d", jni_type_name(*arg), argIndex);
}
@@ -954,6 +1048,7 @@ write_stats_log_jni(FILE* out, const string& java_method_name, const string& cpp
// Prepare strings
argIndex = 1;
bool hadStringOrChain = false;
+ bool isKeyValuePairAtom = false;
for (vector<java_type_t>::const_iterator arg = signature->begin();
arg != signature->end(); arg++) {
if (*arg == JAVA_TYPE_STRING) {
@@ -1006,18 +1101,23 @@ write_stats_log_jni(FILE* out, const string& java_method_name, const string& cpp
}
fprintf(out, "\n");
}
+ } else if (*arg == JAVA_TYPE_KEY_VALUE_PAIR) {
+ isKeyValuePairAtom = true;
}
argIndex++;
}
// Emit this to quiet the unused parameter warning if there were no strings or attribution
// chains.
- if (!hadStringOrChain) {
+ if (!hadStringOrChain && !isKeyValuePairAtom) {
fprintf(out, " (void)env;\n");
}
+ if (isKeyValuePairAtom) {
+ write_key_value_map_jni(out);
+ }
// stats_write call
argIndex = 1;
- fprintf(out, " int ret = android::util::%s(code", cpp_method_name.c_str());
+ fprintf(out, "\n int ret = android::util::%s(code", cpp_method_name.c_str());
for (vector<java_type_t>::const_iterator arg = signature->begin();
arg != signature->end(); arg++) {
if (*arg == JAVA_TYPE_ATTRIBUTION_CHAIN) {
@@ -1030,6 +1130,8 @@ write_stats_log_jni(FILE* out, const string& java_method_name, const string& cpp
fprintf(out, ", %s_vec", chainField.name.c_str());
}
}
+ } else if (*arg == JAVA_TYPE_KEY_VALUE_PAIR) {
+ fprintf(out, ", int64_t_map, string_map, float_map");
} else {
const char *argName = (*arg == JAVA_TYPE_STRING) ? "str" : "arg";
fprintf(out, ", (%s)%s%d", cpp_type_name(*arg), argName, argIndex);
@@ -1063,6 +1165,7 @@ write_stats_log_jni(FILE* out, const string& java_method_name, const string& cpp
}
argIndex++;
}
+
fprintf(out, " return ret;\n");
fprintf(out, "}\n");